QGIS API Documentation  3.9.0-Master (224899f119)
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 "qgsrendercontext.h"
71 #include "qgsvectordataprovider.h"
77 #include "qgsvectorlayerlabeling.h"
78 #include "qgsvectorlayerrenderer.h"
81 #include "qgspoint.h"
82 #include "qgsrenderer.h"
83 #include "qgssymbollayer.h"
85 #include "qgsdiagramrenderer.h"
86 #include "qgsstyle.h"
87 #include "qgspallabeling.h"
88 #include "qgssimplifymethod.h"
90 #include "qgsexpressioncontext.h"
91 #include "qgsfeedback.h"
92 #include "qgsxmlutils.h"
93 #include "qgsunittypes.h"
94 #include "qgstaskmanager.h"
95 #include "qgstransaction.h"
96 #include "qgsauxiliarystorage.h"
97 #include "qgsgeometryoptions.h"
99 
100 #include "diagram/qgsdiagram.h"
101 
102 #ifdef TESTPROVIDERLIB
103 #include <dlfcn.h>
104 #endif
105 
106 typedef bool saveStyle_t(
107  const QString &uri,
108  const QString &qmlStyle,
109  const QString &sldStyle,
110  const QString &styleName,
111  const QString &styleDescription,
112  const QString &uiFileContent,
113  bool useAsDefault,
114  QString &errCause
115 );
116 
117 typedef QString loadStyle_t(
118  const QString &uri,
119  QString &errCause
120 );
121 
122 typedef int listStyles_t(
123  const QString &uri,
124  QStringList &ids,
125  QStringList &names,
126  QStringList &descriptions,
127  QString &errCause
128 );
129 
130 typedef QString getStyleById_t(
131  const QString &uri,
132  QString styleID,
133  QString &errCause
134 );
135 
136 typedef bool deleteStyleById_t(
137  const QString &uri,
138  QString styleID,
139  QString &errCause
140 );
141 
142 
143 QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
144  const QString &baseName,
145  const QString &providerKey,
146  const QgsVectorLayer::LayerOptions &options )
147  : QgsMapLayer( QgsMapLayerType::VectorLayer, baseName, vectorLayerPath )
148  , mAuxiliaryLayer( nullptr )
149  , mAuxiliaryLayerKey( QString() )
150  , mReadExtentFromXml( options.readExtentFromXml )
151 {
152  if ( options.fallbackCrs.isValid() )
153  setCrs( options.fallbackCrs, false );
154  mWkbType = options.fallbackWkbType;
155 
156  setProviderType( providerKey );
157 
158  mGeometryOptions = qgis::make_unique<QgsGeometryOptions>();
159  mActions = new QgsActionManager( this );
160  mConditionalStyles = new QgsConditionalLayerStyles();
161  mStoredExpressionManager = new QgsStoredExpressionManager();
162  mStoredExpressionManager->setParent( this );
163 
164  mJoinBuffer = new QgsVectorLayerJoinBuffer( this );
165  mJoinBuffer->setParent( this );
166  connect( mJoinBuffer, &QgsVectorLayerJoinBuffer::joinedFieldsChanged, this, &QgsVectorLayer::onJoinedFieldsChanged );
167 
168  mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
169  // if we're given a provider type, try to create and bind one to this layer
170  if ( !vectorLayerPath.isEmpty() && !mProviderKey.isEmpty() )
171  {
172  QgsDataProvider::ProviderOptions providerOptions { options.transformContext };
173  setDataSource( vectorLayerPath, baseName, providerKey, providerOptions, options.loadDefaultStyle );
174  }
175 
176  connect( this, &QgsVectorLayer::selectionChanged, this, [ = ] { triggerRepaint(); } );
177  connect( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded, this, &QgsVectorLayer::onRelationsLoaded );
178 
180 
181  // Default simplify drawing settings
182  QgsSettings settings;
183  mSimplifyMethod.setSimplifyHints( settings.flagValue( QStringLiteral( "qgis/simplifyDrawingHints" ), mSimplifyMethod.simplifyHints(), QgsSettings::NoSection ) );
184  mSimplifyMethod.setSimplifyAlgorithm( settings.enumValue( QStringLiteral( "qgis/simplifyAlgorithm" ), mSimplifyMethod.simplifyAlgorithm() ) );
185  mSimplifyMethod.setThreshold( settings.value( QStringLiteral( "qgis/simplifyDrawingTol" ), mSimplifyMethod.threshold() ).toFloat() );
186  mSimplifyMethod.setForceLocalOptimization( settings.value( QStringLiteral( "qgis/simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ).toBool() );
187  mSimplifyMethod.setMaximumScale( settings.value( QStringLiteral( "qgis/simplifyMaxScale" ), mSimplifyMethod.maximumScale() ).toFloat() );
188 
189 } // QgsVectorLayer ctor
190 
191 
193 {
194  emit willBeDeleted();
195 
196  mValid = false;
197 
198  delete mDataProvider;
199  delete mEditBuffer;
200  delete mJoinBuffer;
201  delete mExpressionFieldBuffer;
202  delete mLabeling;
203  delete mDiagramLayerSettings;
204  delete mDiagramRenderer;
205 
206  delete mActions;
207 
208  delete mRenderer;
209  delete mConditionalStyles;
210  delete mStoredExpressionManager;
211 
212  if ( mFeatureCounter )
213  mFeatureCounter->cancel();
214 }
215 
217 {
219  if ( mDataProvider )
220  {
221  options.transformContext = mDataProvider->transformContext();
222  }
223  QgsVectorLayer *layer = new QgsVectorLayer( source(), name(), mProviderKey, options );
224  if ( mDataProvider && layer->dataProvider() )
225  {
226  layer->dataProvider()->handlePostCloneOperations( mDataProvider );
227  }
228  QgsMapLayer::clone( layer );
229 
230  QList<QgsVectorLayerJoinInfo> joins = vectorJoins();
231  const auto constJoins = joins;
232  for ( const QgsVectorLayerJoinInfo &join : constJoins )
233  {
234  // do not copy join information for auxiliary layer
235  if ( !auxiliaryLayer()
236  || ( auxiliaryLayer() && auxiliaryLayer()->id() != join.joinLayerId() ) )
237  layer->addJoin( join );
238  }
239 
240  layer->setProviderEncoding( dataProvider()->encoding() );
242  layer->setMapTipTemplate( mapTipTemplate() );
243  layer->setReadOnly( isReadOnly() );
244  layer->selectByIds( selectedFeatureIds() );
249  layer->setOpacity( opacity() );
251 
252  const auto constActions = actions()->actions();
253  for ( const QgsAction &action : constActions )
254  {
255  layer->actions()->addAction( action );
256  }
257 
258  if ( renderer() )
259  {
260  layer->setRenderer( renderer()->clone() );
261  }
262 
263  if ( labeling() )
264  {
265  layer->setLabeling( labeling()->clone() );
266  }
267  layer->setLabelsEnabled( labelsEnabled() );
268 
269  layer->setSimplifyMethod( simplifyMethod() );
270 
271  if ( diagramRenderer() )
272  {
274  }
275 
276  if ( diagramLayerSettings() )
277  {
279  }
280 
281  for ( int i = 0; i < fields().count(); i++ )
282  {
283  layer->setFieldAlias( i, attributeAlias( i ) );
284  layer->setEditorWidgetSetup( i, editorWidgetSetup( i ) );
287 
288  QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> constraints = fieldConstraintsAndStrength( i );
289  auto constraintIt = constraints.constBegin();
290  for ( ; constraintIt != constraints.constEnd(); ++ constraintIt )
291  {
292  layer->setFieldConstraint( i, constraintIt.key(), constraintIt.value() );
293  }
294 
296  {
297  layer->addExpressionField( expressionField( i ), fields().at( i ) );
298  }
299  }
300 
301  layer->setEditFormConfig( editFormConfig() );
302 
303  if ( auxiliaryLayer() )
304  layer->setAuxiliaryLayer( auxiliaryLayer()->clone( layer ) );
305 
306  return layer;
307 }
308 
310 {
311  if ( mDataProvider )
312  {
313  return mDataProvider->storageType();
314  }
315  return QString();
316 }
317 
318 
320 {
321  if ( mDataProvider )
322  {
323  return mDataProvider->capabilitiesString();
324  }
325  return QString();
326 }
327 
329 {
330  if ( mDataProvider )
331  {
332  return mDataProvider->dataComment();
333  }
334  return QString();
335 }
336 
338 {
339  return crs();
340 }
341 
343 {
344  return name();
345 }
346 
348 {
349  if ( mDataProvider )
350  {
351  mDataProvider->reloadData();
352  updateFields();
353  }
354 }
355 
357 {
358  return new QgsVectorLayerRenderer( this, rendererContext );
359 }
360 
361 
362 void QgsVectorLayer::drawVertexMarker( double x, double y, QPainter &p, QgsVectorLayer::VertexMarkerType type, int m )
363 {
365  {
366  p.setPen( QColor( 50, 100, 120, 200 ) );
367  p.setBrush( QColor( 200, 200, 210, 120 ) );
368  p.drawEllipse( x - m, y - m, m * 2 + 1, m * 2 + 1 );
369  }
370  else if ( type == QgsVectorLayer::Cross )
371  {
372  p.setPen( QColor( 255, 0, 0 ) );
373  p.drawLine( x - m, y + m, x + m, y - m );
374  p.drawLine( x - m, y - m, x + m, y + m );
375  }
376 }
377 
379 {
380  mSelectedFeatureIds.insert( fid );
381 
382  emit selectionChanged( QgsFeatureIds() << fid, QgsFeatureIds(), false );
383 }
384 
385 void QgsVectorLayer::select( const QgsFeatureIds &featureIds )
386 {
387  mSelectedFeatureIds.unite( featureIds );
388 
389  emit selectionChanged( featureIds, QgsFeatureIds(), false );
390 }
391 
393 {
394  mSelectedFeatureIds.remove( fid );
395 
396  emit selectionChanged( QgsFeatureIds(), QgsFeatureIds() << fid, false );
397 }
398 
399 void QgsVectorLayer::deselect( const QgsFeatureIds &featureIds )
400 {
401  mSelectedFeatureIds.subtract( featureIds );
402 
403  emit selectionChanged( QgsFeatureIds(), featureIds, false );
404 }
405 
407 {
408  // normalize the rectangle
409  rect.normalize();
410 
411  QgsFeatureIds newSelection;
412 
414  .setFilterRect( rect )
416  .setNoAttributes() );
417 
418  QgsFeature feat;
419  while ( features.nextFeature( feat ) )
420  {
421  newSelection << feat.id();
422  }
423  features.close();
424 
425  selectByIds( newSelection, behavior );
426 }
427 
428 void QgsVectorLayer::selectByExpression( const QString &expression, QgsVectorLayer::SelectBehavior behavior )
429 {
430  QgsFeatureIds newSelection;
431 
433 
434  if ( behavior == SetSelection || behavior == AddToSelection )
435  {
437  .setExpressionContext( context )
439  .setNoAttributes();
440 
441  QgsFeatureIterator features = getFeatures( request );
442 
443  if ( behavior == AddToSelection )
444  {
445  newSelection = selectedFeatureIds();
446  }
447  QgsFeature feat;
448  while ( features.nextFeature( feat ) )
449  {
450  newSelection << feat.id();
451  }
452  features.close();
453  }
454  else if ( behavior == IntersectSelection || behavior == RemoveFromSelection )
455  {
456  QgsExpression exp( expression );
457  exp.prepare( &context );
458 
459  QgsFeatureIds oldSelection = selectedFeatureIds();
460  QgsFeatureRequest request = QgsFeatureRequest().setFilterFids( oldSelection );
461 
462  //refine request
463  if ( !exp.needsGeometry() )
465  request.setSubsetOfAttributes( exp.referencedColumns(), fields() );
466 
467  QgsFeatureIterator features = getFeatures( request );
468  QgsFeature feat;
469  while ( features.nextFeature( feat ) )
470  {
471  context.setFeature( feat );
472  bool matches = exp.evaluate( &context ).toBool();
473 
474  if ( matches && behavior == IntersectSelection )
475  {
476  newSelection << feat.id();
477  }
478  else if ( !matches && behavior == RemoveFromSelection )
479  {
480  newSelection << feat.id();
481  }
482  }
483  }
484 
485  selectByIds( newSelection );
486 }
487 
489 {
490  QgsFeatureIds newSelection;
491 
492  switch ( behavior )
493  {
494  case SetSelection:
495  newSelection = ids;
496  break;
497 
498  case AddToSelection:
499  newSelection = mSelectedFeatureIds + ids;
500  break;
501 
502  case RemoveFromSelection:
503  newSelection = mSelectedFeatureIds - ids;
504  break;
505 
506  case IntersectSelection:
507  newSelection = mSelectedFeatureIds.intersect( ids );
508  break;
509  }
510 
511  QgsFeatureIds deselectedFeatures = mSelectedFeatureIds - newSelection;
512  mSelectedFeatureIds = newSelection;
513 
514  emit selectionChanged( newSelection, deselectedFeatures, true );
515 }
516 
517 void QgsVectorLayer::modifySelection( const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds )
518 {
519  QgsFeatureIds intersectingIds = selectIds & deselectIds;
520  if ( !intersectingIds.isEmpty() )
521  {
522  QgsDebugMsgLevel( QStringLiteral( "Trying to select and deselect the same item at the same time. Unsure what to do. Selecting dubious items." ), 3 );
523  }
524 
525  mSelectedFeatureIds -= deselectIds;
526  mSelectedFeatureIds += selectIds;
527 
528  emit selectionChanged( selectIds, deselectIds - intersectingIds, false );
529 }
530 
532 {
534  ids.subtract( mSelectedFeatureIds );
535  selectByIds( ids );
536 }
537 
539 {
541 }
542 
544 {
545  // normalize the rectangle
546  rect.normalize();
547 
549  .setFilterRect( rect )
551  .setNoAttributes() );
552 
553  QgsFeatureIds selectIds;
554  QgsFeatureIds deselectIds;
555 
556  QgsFeature fet;
557  while ( fit.nextFeature( fet ) )
558  {
559  if ( mSelectedFeatureIds.contains( fet.id() ) )
560  {
561  deselectIds << fet.id();
562  }
563  else
564  {
565  selectIds << fet.id();
566  }
567  }
568 
569  modifySelection( selectIds, deselectIds );
570 }
571 
573 {
574  if ( mSelectedFeatureIds.isEmpty() )
575  return;
576 
578 }
579 
581 {
582  return mDataProvider;
583 }
584 
586 {
587  return mDataProvider;
588 }
589 
590 void QgsVectorLayer::setProviderEncoding( const QString &encoding )
591 {
592  if ( mValid && mDataProvider && mDataProvider->encoding() != encoding )
593  {
594  mDataProvider->setEncoding( encoding );
595  updateFields();
596  }
597 }
598 
600 {
601  delete mDiagramRenderer;
602  mDiagramRenderer = r;
603  emit rendererChanged();
604  emit styleChanged();
605 }
606 
608 {
609  return QgsWkbTypes::geometryType( mWkbType );
610 }
611 
613 {
614  return mWkbType;
615 }
616 
618 {
619  if ( !mValid || !isSpatial() || mSelectedFeatureIds.isEmpty() ) //no selected features
620  {
621  return QgsRectangle( 0, 0, 0, 0 );
622  }
623 
624  QgsRectangle r, retval;
625  retval.setMinimal();
626 
627  QgsFeature fet;
628  if ( mDataProvider->capabilities() & QgsVectorDataProvider::SelectAtId )
629  {
631  .setFilterFids( mSelectedFeatureIds )
632  .setNoAttributes() );
633 
634  while ( fit.nextFeature( fet ) )
635  {
636  if ( !fet.hasGeometry() )
637  continue;
638  r = fet.geometry().boundingBox();
639  retval.combineExtentWith( r );
640  }
641  }
642  else
643  {
645  .setNoAttributes() );
646 
647  while ( fit.nextFeature( fet ) )
648  {
649  if ( mSelectedFeatureIds.contains( fet.id() ) )
650  {
651  if ( fet.hasGeometry() )
652  {
653  r = fet.geometry().boundingBox();
654  retval.combineExtentWith( r );
655  }
656  }
657  }
658  }
659 
660  if ( retval.width() == 0.0 || retval.height() == 0.0 )
661  {
662  // If all of the features are at the one point, buffer the
663  // rectangle a bit. If they are all at zero, do something a bit
664  // more crude.
665 
666  if ( retval.xMinimum() == 0.0 && retval.xMaximum() == 0.0 &&
667  retval.yMinimum() == 0.0 && retval.yMaximum() == 0.0 )
668  {
669  retval.set( -1.0, -1.0, 1.0, 1.0 );
670  }
671  }
672 
673  return retval;
674 }
675 
677 {
678  return mLabelsEnabled && static_cast< bool >( mLabeling );
679 }
680 
682 {
683  mLabelsEnabled = enabled;
684 }
685 
687 {
688  if ( !mDiagramRenderer || !mDiagramLayerSettings )
689  return false;
690 
691  QList<QgsDiagramSettings> settingList = mDiagramRenderer->diagramSettings();
692  if ( !settingList.isEmpty() )
693  {
694  return settingList.at( 0 ).enabled;
695  }
696  return false;
697 }
698 
699 long QgsVectorLayer::featureCount( const QString &legendKey ) const
700 {
701  if ( !mSymbolFeatureCounted )
702  return -1;
703 
704  return mSymbolFeatureCountMap.value( legendKey, -1 );
705 }
706 
707 QgsFeatureIds QgsVectorLayer::symbolFeatureIds( const QString &legendKey ) const
708 {
709  if ( !mSymbolFeatureCounted )
710  return QgsFeatureIds();
711 
712  return mSymbolFeatureIdMap.value( legendKey, QgsFeatureIds() );
713 }
714 
716 {
717  if ( mSymbolFeatureCounted || mFeatureCounter )
718  return mFeatureCounter;
719 
720  mSymbolFeatureCountMap.clear();
721  mSymbolFeatureIdMap.clear();
722 
723  if ( !mValid )
724  {
725  QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer" ), 3 );
726  return mFeatureCounter;
727  }
728  if ( !mDataProvider )
729  {
730  QgsDebugMsgLevel( QStringLiteral( "invoked with null mDataProvider" ), 3 );
731  return mFeatureCounter;
732  }
733  if ( !mRenderer )
734  {
735  QgsDebugMsgLevel( QStringLiteral( "invoked with null mRenderer" ), 3 );
736  return mFeatureCounter;
737  }
738 
739  if ( !mFeatureCounter )
740  {
741  mFeatureCounter = new QgsVectorLayerFeatureCounter( this );
742  connect( mFeatureCounter, &QgsTask::taskCompleted, this, &QgsVectorLayer::onFeatureCounterCompleted );
743  connect( mFeatureCounter, &QgsTask::taskTerminated, this, &QgsVectorLayer::onFeatureCounterTerminated );
744 
745  QgsApplication::taskManager()->addTask( mFeatureCounter );
746  }
747 
748  return mFeatureCounter;
749 }
750 
752 {
753  // do not update extent by default when trust project option is activated
754  if ( force || !mReadExtentFromXml || ( mReadExtentFromXml && mXmlExtent.isNull() ) )
755  mValidExtent = false;
756 }
757 
759 {
761  mValidExtent = true;
762 }
763 
764 void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature )
765 {
766  if ( !mDefaultValueOnUpdateFields.isEmpty() )
767  {
768  if ( !feature.isValid() )
769  feature = getFeature( fid );
770 
771  int size = mFields.size();
772  for ( int idx : qgis::as_const( mDefaultValueOnUpdateFields ) )
773  {
774  if ( idx < 0 || idx >= size )
775  continue;
776 
777  feature.setAttribute( idx, defaultValue( idx, feature ) );
778  updateFeature( feature, true );
779  }
780  }
781 }
782 
784 {
785  QgsRectangle rect;
786  rect.setMinimal();
787 
788  if ( !isSpatial() )
789  return rect;
790 
791  if ( !mValidExtent && mLazyExtent && mDataProvider && !mDataProvider->hasMetadata() && mReadExtentFromXml && !mXmlExtent.isNull() )
792  {
793  mExtent = mXmlExtent;
794  mValidExtent = true;
795  mLazyExtent = false;
796  }
797 
798  if ( !mValidExtent && mLazyExtent && mDataProvider && mDataProvider->isValid() )
799  {
800  // get the extent
801  QgsRectangle mbr = mDataProvider->extent();
802 
803  // show the extent
804  QgsDebugMsgLevel( QStringLiteral( "Extent of layer: %1" ).arg( mbr.toString() ), 3 );
805  // store the extent
806  mValidExtent = true;
807  mExtent = mbr;
808 
809  mLazyExtent = false;
810  }
811 
812  if ( mValidExtent )
813  return QgsMapLayer::extent();
814 
815  if ( !mValid || !mDataProvider )
816  {
817  QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
818  return rect;
819  }
820 
821  if ( !mEditBuffer ||
822  ( mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mChangedGeometries.isEmpty() ) ||
823  QgsDataSourceUri( mDataProvider->dataSourceUri() ).useEstimatedMetadata() )
824  {
825  mDataProvider->updateExtents();
826 
827  // get the extent of the layer from the provider
828  // but only when there are some features already
829  if ( mDataProvider->featureCount() != 0 )
830  {
831  QgsRectangle r = mDataProvider->extent();
832  rect.combineExtentWith( r );
833  }
834 
835  if ( mEditBuffer )
836  {
837  for ( QgsFeatureMap::const_iterator it = mEditBuffer->mAddedFeatures.constBegin(); it != mEditBuffer->mAddedFeatures.constEnd(); ++it )
838  {
839  if ( it->hasGeometry() )
840  {
841  QgsRectangle r = it->geometry().boundingBox();
842  rect.combineExtentWith( r );
843  }
844  }
845  }
846  }
847  else
848  {
850  .setNoAttributes() );
851 
852  QgsFeature fet;
853  while ( fit.nextFeature( fet ) )
854  {
855  if ( fet.hasGeometry() && fet.geometry().type() != QgsWkbTypes::UnknownGeometry )
856  {
857  QgsRectangle bb = fet.geometry().boundingBox();
858  rect.combineExtentWith( bb );
859  }
860  }
861  }
862 
863  if ( rect.xMinimum() > rect.xMaximum() && rect.yMinimum() > rect.yMaximum() )
864  {
865  // special case when there are no features in provider nor any added
866  rect = QgsRectangle(); // use rectangle with zero coordinates
867  }
868 
869  mValidExtent = true;
870  mExtent = rect;
871 
872  // Send this (hopefully) up the chain to the map canvas
873  emit recalculateExtents();
874 
875  return rect;
876 }
877 
879 {
880  return extent();
881 }
882 
883 QString QgsVectorLayer::subsetString() const
884 {
885  if ( !mValid || !mDataProvider )
886  {
887  QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider" ), 3 );
888  return QString();
889  }
890  return mDataProvider->subsetString();
891 }
892 
893 bool QgsVectorLayer::setSubsetString( const QString &subset )
894 {
895  if ( !mValid || !mDataProvider || mEditBuffer )
896  {
897  QgsDebugMsgLevel( QStringLiteral( "invoked with invalid layer or null mDataProvider or while editing" ), 3 );
898  return false;
899  }
900 
901  if ( subset == mDataProvider->subsetString() )
902  return true;
903 
904  bool res = mDataProvider->setSubsetString( subset );
905 
906  // get the updated data source string from the provider
907  mDataSource = mDataProvider->dataSourceUri();
908  updateExtents();
909  updateFields();
910 
911  if ( res )
912  {
913  emit subsetStringChanged();
914  triggerRepaint();
915  }
916 
917  return res;
918 }
919 
921 {
922  if ( mValid && mDataProvider && !mEditBuffer && ( isSpatial() && geometryType() != QgsWkbTypes::PointGeometry ) && ( mSimplifyMethod.simplifyHints() & simplifyHint ) && renderContext.useRenderingOptimization() )
923  {
924  double maximumSimplificationScale = mSimplifyMethod.maximumScale();
925 
926  // check maximum scale at which generalisation should be carried out
927  return !( maximumSimplificationScale > 1 && renderContext.rendererScale() <= maximumSimplificationScale );
928  }
929  return false;
930 }
931 
933 {
934  return mConditionalStyles;
935 }
936 
938 {
939  if ( !mValid || !mDataProvider )
940  return QgsFeatureIterator();
941 
942  return QgsFeatureIterator( new QgsVectorLayerFeatureIterator( new QgsVectorLayerFeatureSource( this ), true, request ) );
943 }
944 
946 {
947  QgsFeature feature;
949  if ( feature.isValid() )
950  return feature.geometry();
951  else
952  return QgsGeometry();
953 }
954 
955 bool QgsVectorLayer::addFeature( QgsFeature &feature, Flags )
956 {
957  if ( !mValid || !mEditBuffer || !mDataProvider )
958  return false;
959 
960 
961  if ( mGeometryOptions->isActive() )
962  {
963  QgsGeometry geom = feature.geometry();
964  mGeometryOptions->apply( geom );
965  feature.setGeometry( geom );
966  }
967 
968  bool success = mEditBuffer->addFeature( feature );
969 
970  if ( success )
971  {
972  updateExtents();
973 
974  if ( mJoinBuffer->containsJoins() )
975  success = mJoinBuffer->addFeature( feature );
976  }
977 
978  return success;
979 }
980 
981 bool QgsVectorLayer::updateFeature( QgsFeature &updatedFeature, bool skipDefaultValues )
982 {
983  if ( !mEditBuffer || !mDataProvider )
984  {
985  return false;
986  }
987 
988  QgsFeature currentFeature = getFeature( updatedFeature.id() );
989  if ( currentFeature.isValid() )
990  {
991  bool hasChanged = false;
992  bool hasError = false;
993 
994  if ( ( updatedFeature.hasGeometry() || currentFeature.hasGeometry() ) && !updatedFeature.geometry().equals( currentFeature.geometry() ) )
995  {
996  QgsGeometry geometry = updatedFeature.geometry();
997  if ( changeGeometry( updatedFeature.id(), geometry, true ) )
998  {
999  hasChanged = true;
1000  updatedFeature.setGeometry( geometry );
1001  }
1002  else
1003  {
1004  QgsDebugMsgLevel( QStringLiteral( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ), 3 );
1005  }
1006  }
1007 
1008  QgsAttributes fa = updatedFeature.attributes();
1009  QgsAttributes ca = currentFeature.attributes();
1010 
1011  for ( int attr = 0; attr < fa.count(); ++attr )
1012  {
1013  if ( fa.at( attr ) != ca.at( attr ) )
1014  {
1015  if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
1016  {
1017  hasChanged = true;
1018  }
1019  else
1020  {
1021  QgsDebugMsgLevel( QStringLiteral( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( updatedFeature.id() ), 3 );
1022  hasError = true;
1023  }
1024  }
1025  }
1026  if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() && !skipDefaultValues )
1027  updateDefaultValues( updatedFeature.id(), updatedFeature );
1028 
1029  return !hasError;
1030  }
1031  else
1032  {
1033  QgsDebugMsgLevel( QStringLiteral( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ), 3 );
1034  return false;
1035  }
1036 }
1037 
1038 
1039 bool QgsVectorLayer::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
1040 {
1041  if ( !mValid || !mEditBuffer || !mDataProvider )
1042  return false;
1043 
1044  QgsVectorLayerEditUtils utils( this );
1045  bool result = utils.insertVertex( x, y, atFeatureId, beforeVertex );
1046  if ( result )
1047  updateExtents();
1048  return result;
1049 }
1050 
1051 
1052 bool QgsVectorLayer::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
1053 {
1054  if ( !mValid || !mEditBuffer || !mDataProvider )
1055  return false;
1056 
1057  QgsVectorLayerEditUtils utils( this );
1058  bool result = utils.insertVertex( point, atFeatureId, beforeVertex );
1059  if ( result )
1060  updateExtents();
1061  return result;
1062 }
1063 
1064 
1065 bool QgsVectorLayer::moveVertex( double x, double y, QgsFeatureId atFeatureId, int atVertex )
1066 {
1067  if ( !mValid || !mEditBuffer || !mDataProvider )
1068  return false;
1069 
1070  QgsVectorLayerEditUtils utils( this );
1071  bool result = utils.moveVertex( x, y, atFeatureId, atVertex );
1072 
1073  if ( result )
1074  updateExtents();
1075  return result;
1076 }
1077 
1078 bool QgsVectorLayer::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
1079 {
1080  if ( !mValid || !mEditBuffer || !mDataProvider )
1081  return false;
1082 
1083  QgsVectorLayerEditUtils utils( this );
1084  bool result = utils.moveVertex( p, atFeatureId, atVertex );
1085 
1086  if ( result )
1087  updateExtents();
1088  return result;
1089 }
1090 
1092 {
1093  if ( !mValid || !mEditBuffer || !mDataProvider )
1095 
1096  QgsVectorLayerEditUtils utils( this );
1097  EditResult result = utils.deleteVertex( featureId, vertex );
1098 
1099  if ( result == Success )
1100  updateExtents();
1101  return result;
1102 }
1103 
1104 
1106 {
1107  if ( !mValid || !mDataProvider || !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
1108  {
1109  return false;
1110  }
1111 
1112  if ( !isEditable() )
1113  {
1114  return false;
1115  }
1116 
1117  int deleted = 0;
1118  int count = mSelectedFeatureIds.size();
1119  // Make a copy since deleteFeature modifies mSelectedFeatureIds
1120  QgsFeatureIds selectedFeatures( mSelectedFeatureIds );
1121  const auto constSelectedFeatures = selectedFeatures;
1122  for ( QgsFeatureId fid : constSelectedFeatures )
1123  {
1124  deleted += deleteFeature( fid ); // removes from selection
1125  }
1126 
1127  triggerRepaint();
1128  updateExtents();
1129 
1130  if ( deletedCount )
1131  {
1132  *deletedCount = deleted;
1133  }
1134 
1135  return deleted == count;
1136 }
1137 
1138 QgsGeometry::OperationResult QgsVectorLayer::addRing( const QVector<QgsPointXY> &ring, QgsFeatureId *featureId )
1139 {
1140  if ( !mValid || !mEditBuffer || !mDataProvider )
1141  return QgsGeometry::OperationResult::LayerNotEditable;
1142 
1143  QgsVectorLayerEditUtils utils( this );
1144  QgsGeometry::OperationResult result = QgsGeometry::OperationResult::AddRingNotInExistingFeature;
1145 
1146  //first try with selected features
1147  if ( !mSelectedFeatureIds.isEmpty() )
1148  {
1149  result = utils.addRing( ring, mSelectedFeatureIds, featureId );
1150  }
1151 
1152  if ( result != QgsGeometry::OperationResult::Success )
1153  {
1154  //try with all intersecting features
1155  result = utils.addRing( ring, QgsFeatureIds(), featureId );
1156  }
1157 
1158  return result;
1159 }
1160 
1162 {
1163  if ( !mValid || !mEditBuffer || !mDataProvider )
1164  {
1165  delete ring;
1166  return QgsGeometry::OperationResult::LayerNotEditable;
1167  }
1168 
1169  if ( !ring )
1170  {
1171  return QgsGeometry::OperationResult::InvalidInputGeometryType;
1172  }
1173 
1174  if ( !ring->isClosed() )
1175  {
1176  delete ring;
1177  return QgsGeometry::OperationResult::AddRingNotClosed;
1178  }
1179 
1180  QgsVectorLayerEditUtils utils( this );
1181  QgsGeometry::OperationResult result = QgsGeometry::OperationResult::AddRingNotInExistingFeature;
1182 
1183  //first try with selected features
1184  if ( !mSelectedFeatureIds.isEmpty() )
1185  {
1186  result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), mSelectedFeatureIds, featureId );
1187  }
1188 
1189  if ( result != QgsGeometry::OperationResult::Success )
1190  {
1191  //try with all intersecting features
1192  result = utils.addRing( static_cast< QgsCurve * >( ring->clone() ), QgsFeatureIds(), featureId );
1193  }
1194 
1195  delete ring;
1196  return result;
1197 }
1198 
1199 QgsGeometry::OperationResult QgsVectorLayer::addPart( const QList<QgsPointXY> &points )
1200 {
1201  if ( !mValid || !mEditBuffer || !mDataProvider )
1202  return QgsGeometry::OperationResult::LayerNotEditable;
1203 
1204  //number of selected features must be 1
1205 
1206  if ( mSelectedFeatureIds.empty() )
1207  {
1208  QgsDebugMsgLevel( QStringLiteral( "Number of selected features < 1" ), 3 );
1209  return QgsGeometry::OperationResult::SelectionIsEmpty;
1210  }
1211  else if ( mSelectedFeatureIds.size() > 1 )
1212  {
1213  QgsDebugMsgLevel( QStringLiteral( "Number of selected features > 1" ), 3 );
1214  return QgsGeometry::OperationResult::SelectionIsGreaterThanOne;
1215  }
1216 
1217  QgsVectorLayerEditUtils utils( this );
1218  QgsGeometry::OperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1219 
1220  if ( result == QgsGeometry::OperationResult::Success )
1221  updateExtents();
1222  return result;
1223 }
1224 
1226 {
1227  if ( !mValid || !mEditBuffer || !mDataProvider )
1228  return QgsGeometry::OperationResult::LayerNotEditable;
1229 
1230  //number of selected features must be 1
1231 
1232  if ( mSelectedFeatureIds.empty() )
1233  {
1234  QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1235  return QgsGeometry::OperationResult::SelectionIsEmpty;
1236  }
1237  else if ( mSelectedFeatureIds.size() > 1 )
1238  {
1239  QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1240  return QgsGeometry::OperationResult::SelectionIsGreaterThanOne;
1241  }
1242 
1243  QgsVectorLayerEditUtils utils( this );
1244  QgsGeometry::OperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1245 
1246  if ( result == QgsGeometry::OperationResult::Success )
1247  updateExtents();
1248  return result;
1249 }
1250 
1252 {
1253  if ( !mValid || !mEditBuffer || !mDataProvider )
1254  return QgsGeometry::OperationResult::LayerNotEditable;
1255 
1256  //number of selected features must be 1
1257 
1258  if ( mSelectedFeatureIds.empty() )
1259  {
1260  QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1261  return QgsGeometry::OperationResult::SelectionIsEmpty;
1262  }
1263  else if ( mSelectedFeatureIds.size() > 1 )
1264  {
1265  QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1266  return QgsGeometry::OperationResult::SelectionIsGreaterThanOne;
1267  }
1268 
1269  QgsVectorLayerEditUtils utils( this );
1270  QgsGeometry::OperationResult result = utils.addPart( ring, *mSelectedFeatureIds.constBegin() );
1271 
1272  if ( result == QgsGeometry::OperationResult::Success )
1273  updateExtents();
1274  return result;
1275 }
1276 
1277 int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1278 {
1279  if ( !mValid || !mEditBuffer || !mDataProvider )
1280  return QgsGeometry::OperationResult::LayerNotEditable;
1281 
1282  QgsVectorLayerEditUtils utils( this );
1283  int result = utils.translateFeature( featureId, dx, dy );
1284 
1285  if ( result == QgsGeometry::OperationResult::Success )
1286  updateExtents();
1287  return result;
1288 }
1289 
1290 QgsGeometry::OperationResult QgsVectorLayer::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1291 {
1292  if ( !mValid || !mEditBuffer || !mDataProvider )
1293  return QgsGeometry::OperationResult::LayerNotEditable;
1294 
1295  QgsVectorLayerEditUtils utils( this );
1296  return utils.splitParts( splitLine, topologicalEditing );
1297 }
1298 
1299 QgsGeometry::OperationResult QgsVectorLayer::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1300 {
1301  if ( !mValid || !mEditBuffer || !mDataProvider )
1302  return QgsGeometry::OperationResult::LayerNotEditable;
1303 
1304  QgsVectorLayerEditUtils utils( this );
1305  return utils.splitFeatures( splitLine, topologicalEditing );
1306 }
1307 
1309 {
1310  if ( !mValid || !mEditBuffer || !mDataProvider )
1311  return -1;
1312 
1313  QgsVectorLayerEditUtils utils( this );
1314  return utils.addTopologicalPoints( geom );
1315 }
1316 
1318 {
1319  return addTopologicalPoints( QgsPoint( p ) );
1320 }
1321 
1323 {
1324  if ( !mValid || !mEditBuffer || !mDataProvider )
1325  return -1;
1326 
1327  QgsVectorLayerEditUtils utils( this );
1328  return utils.addTopologicalPoints( p );
1329 }
1330 
1332 {
1333  if ( mLabeling == labeling )
1334  return;
1335 
1336  delete mLabeling;
1337  mLabeling = labeling;
1338 }
1339 
1341 {
1342  if ( !mValid || !mDataProvider )
1343  {
1344  return false;
1345  }
1346 
1347  // allow editing if provider supports any of the capabilities
1348  if ( !( mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities ) )
1349  {
1350  return false;
1351  }
1352 
1353  if ( mReadOnly )
1354  {
1355  return false;
1356  }
1357 
1358  if ( mEditBuffer )
1359  {
1360  // editing already underway
1361  return false;
1362  }
1363 
1364  emit beforeEditingStarted();
1365 
1366  mDataProvider->enterUpdateMode();
1367 
1368  if ( mDataProvider->transaction() )
1369  {
1370  mEditBuffer = new QgsVectorLayerEditPassthrough( this );
1371 
1372  connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
1373  }
1374  else
1375  {
1376  mEditBuffer = new QgsVectorLayerEditBuffer( this );
1377  }
1378  // forward signals
1379  connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
1380  connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
1381  //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
1383  connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
1394 
1395  updateFields();
1396 
1397  emit editingStarted();
1398 
1399  return true;
1400 }
1401 
1403 {
1404  if ( mDataProvider )
1405  mDataProvider->setTransformContext( transformContext );
1406 }
1407 
1409 {
1410  if ( mRenderer )
1411  if ( !mRenderer->accept( visitor ) )
1412  return false;
1413 
1414  if ( mLabeling )
1415  if ( !mLabeling->accept( visitor ) )
1416  return false;
1417 
1418  return true;
1419 }
1420 
1421 bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1422 {
1423  QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsVectorLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1424 
1425  //process provider key
1426  QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1427 
1428  if ( pkeyNode.isNull() )
1429  {
1430  mProviderKey.clear();
1431  }
1432  else
1433  {
1434  QDomElement pkeyElt = pkeyNode.toElement();
1435  mProviderKey = pkeyElt.text();
1436  }
1437 
1438  // determine type of vector layer
1439  if ( !mProviderKey.isNull() )
1440  {
1441  // if the provider string isn't empty, then we successfully
1442  // got the stored provider
1443  }
1444  else if ( mDataSource.contains( QLatin1String( "dbname=" ) ) )
1445  {
1446  mProviderKey = QStringLiteral( "postgres" );
1447  }
1448  else
1449  {
1450  mProviderKey = QStringLiteral( "ogr" );
1451  }
1452 
1453  QgsDataProvider::ProviderOptions options { context.transformContext() };
1454  if ( ( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) || !setDataProvider( mProviderKey, options ) )
1455  {
1456  if ( !( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) )
1457  {
1458  QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1459  }
1460  const QDomElement elem = layer_node.toElement();
1461 
1462  // for invalid layer sources, we fallback to stored wkbType if available
1463  if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1464  mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
1465  }
1466 
1467  QDomElement pkeyElem = pkeyNode.toElement();
1468  if ( !pkeyElem.isNull() )
1469  {
1470  QString encodingString = pkeyElem.attribute( QStringLiteral( "encoding" ) );
1471  if ( mDataProvider && !encodingString.isEmpty() )
1472  {
1473  mDataProvider->setEncoding( encodingString );
1474  }
1475  }
1476 
1477  // load vector joins - does not resolve references to layers yet
1478  mJoinBuffer->readXml( layer_node );
1479 
1480  updateFields();
1481 
1482  QString errorMsg;
1483  if ( !readSymbology( layer_node, errorMsg, context ) )
1484  {
1485  return false;
1486  }
1487 
1488  readStyleManager( layer_node );
1489 
1490  QDomNode depsNode = layer_node.namedItem( QStringLiteral( "dataDependencies" ) );
1491  QDomNodeList depsNodes = depsNode.childNodes();
1492  QSet<QgsMapLayerDependency> sources;
1493  for ( int i = 0; i < depsNodes.count(); i++ )
1494  {
1495  QString source = depsNodes.at( i ).toElement().attribute( QStringLiteral( "id" ) );
1496  sources << QgsMapLayerDependency( source );
1497  }
1498  setDependencies( sources );
1499 
1501  QDomElement legendElem = layer_node.firstChildElement( QStringLiteral( "legend" ) );
1502  if ( !legendElem.isNull() )
1503  legend->readXml( legendElem, context );
1504  setLegend( legend );
1505 
1506  // read extent
1507  if ( mReadExtentFromXml )
1508  {
1509  QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
1510  if ( !extentNode.isNull() )
1511  {
1512  mXmlExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
1513  }
1514  }
1515 
1516  // auxiliary layer
1517  const QDomNode asNode = layer_node.namedItem( QStringLiteral( "auxiliaryLayer" ) );
1518  const QDomElement asElem = asNode.toElement();
1519  if ( !asElem.isNull() )
1520  {
1521  mAuxiliaryLayerKey = asElem.attribute( QStringLiteral( "key" ) );
1522  }
1523 
1524  return mValid; // should be true if read successfully
1525 
1526 } // void QgsVectorLayer::readXml
1527 
1528 
1529 void QgsVectorLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag )
1530 {
1532  setDataSource( dataSource, baseName, provider, options, loadDefaultStyleFlag );
1533 }
1534 
1535 void QgsVectorLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
1536 {
1538 
1539  mDataSource = dataSource;
1540  setName( baseName );
1541  setDataProvider( provider, options );
1542 
1543  if ( !mValid )
1544  {
1545  emit dataSourceChanged();
1546  return;
1547  }
1548 
1549  // Always set crs
1551 
1552  // reset style if loading default style, style is missing, or geometry type is has changed (and layer is valid)
1553  if ( !renderer() || !legend() || ( mValid && geomType != geometryType() ) || loadDefaultStyleFlag )
1554  {
1555  bool defaultLoadedFlag = false;
1556 
1557  if ( loadDefaultStyleFlag && isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1558  {
1559  // first try to create a renderer directly from the data provider
1560  std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1561  if ( defaultRenderer )
1562  {
1563  defaultLoadedFlag = true;
1564  setRenderer( defaultRenderer.release() );
1565  }
1566  }
1567 
1568  // else check if there is a default style / propertysheet defined
1569  // for this layer and if so apply it
1570  if ( !defaultLoadedFlag && loadDefaultStyleFlag )
1571  {
1572  loadDefaultStyle( defaultLoadedFlag );
1573  }
1574 
1575  // if the default style failed to load or was disabled use some very basic defaults
1576  if ( !defaultLoadedFlag && isSpatial() )
1577  {
1578  // add single symbol renderer
1580  }
1581 
1583 
1584  if ( mDataProvider->capabilities() & QgsVectorDataProvider::CreateLabeling )
1585  {
1586  std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
1587  if ( defaultLabeling )
1588  {
1589  setLabeling( defaultLabeling.release() );
1590  setLabelsEnabled( true );
1591  }
1592  }
1593  }
1594 
1595  emit dataSourceChanged();
1596  triggerRepaint();
1597 }
1598 
1599 QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
1600 {
1601  if ( isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1602  {
1603  // first try to create a renderer directly from the data provider
1604  std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1605  if ( defaultRenderer )
1606  {
1607  resultFlag = true;
1608  setRenderer( defaultRenderer.release() );
1609  return QString();
1610  }
1611  }
1612 
1613  return QgsMapLayer::loadDefaultStyle( resultFlag );
1614 }
1615 
1616 
1617 bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options )
1618 {
1619  mProviderKey = provider;
1620  delete mDataProvider;
1621 
1622  // For Postgres provider primary key unicity is tested at construction time,
1623  // so it has to be set before initializing the provider,
1624  // this manipulation is necessary to preserve default behavior when
1625  // "trust layer metadata" project level option is set and checkPrimaryKeyUnicity
1626  // was not explicitly passed in the uri
1627  if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
1628  {
1629  const QString checkUnicityKey { QStringLiteral( "checkPrimaryKeyUnicity" ) };
1631  if ( ! uri.hasParam( checkUnicityKey ) )
1632  {
1633  uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
1634  mDataSource = uri.uri( false );
1635  }
1636  }
1637 
1638  mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options ) );
1639  if ( !mDataProvider )
1640  {
1641  mValid = false;
1642  QgsDebugMsgLevel( QStringLiteral( "Unable to get data provider" ), 2 );
1643  return false;
1644  }
1645 
1646  mDataProvider->setParent( this );
1647  connect( mDataProvider, &QgsVectorDataProvider::raiseError, this, &QgsVectorLayer::raiseError );
1648 
1649  QgsDebugMsgLevel( QStringLiteral( "Instantiated the data provider plugin" ), 2 );
1650 
1651  mValid = mDataProvider->isValid();
1652  if ( !mValid )
1653  {
1654  QgsDebugMsgLevel( QStringLiteral( "Invalid provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
1655  return false;
1656  }
1657 
1658  if ( mDataProvider->capabilities() & QgsVectorDataProvider::ReadLayerMetadata )
1659  {
1660  setMetadata( mDataProvider->layerMetadata() );
1661  QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
1662  }
1663 
1664  // TODO: Check if the provider has the capability to send fullExtentCalculated
1665  connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [ = ] { updateExtents(); } );
1666 
1667  // get and store the feature type
1668  mWkbType = mDataProvider->wkbType();
1669 
1670  updateFields();
1671 
1672  if ( mProviderKey == QLatin1String( "postgres" ) )
1673  {
1674  // update datasource from data provider computed one
1675  mDataSource = mDataProvider->dataSourceUri( false );
1676 
1677  QgsDebugMsgLevel( QStringLiteral( "Beautifying layer name %1" ).arg( name() ), 3 );
1678 
1679  // adjust the display name for postgres layers
1680  QRegExp reg( R"lit("[^"]+"\."([^"] + )"( \([^)]+\))?)lit" );
1681  if ( reg.indexIn( name() ) >= 0 )
1682  {
1683  QStringList stuff = reg.capturedTexts();
1684  QString lName = stuff[1];
1685 
1686  const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers();
1687 
1688  QMap<QString, QgsMapLayer *>::const_iterator it;
1689  for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
1690  ;
1691 
1692  if ( it != layers.constEnd() && stuff.size() > 2 )
1693  {
1694  lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
1695  }
1696 
1697  if ( !lName.isEmpty() )
1698  setName( lName );
1699  }
1700  QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
1701  }
1702  else if ( mProviderKey == QLatin1String( "osm" ) )
1703  {
1704  // make sure that the "observer" has been removed from URI to avoid crashes
1705  mDataSource = mDataProvider->dataSourceUri();
1706  }
1707  else if ( provider == QLatin1String( "ogr" ) )
1708  {
1709  // make sure that the /vsigzip or /vsizip is added to uri, if applicable
1710  mDataSource = mDataProvider->dataSourceUri();
1711  if ( mDataSource.right( 10 ) == QLatin1String( "|layerid=0" ) )
1712  mDataSource.chop( 10 );
1713  }
1714  else if ( provider == QStringLiteral( "memory" ) )
1715  {
1716  // required so that source differs between memory layers
1717  mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
1718  }
1719 
1720  connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
1721  connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::removeSelection );
1722 
1723  return true;
1724 } // QgsVectorLayer:: setDataProvider
1725 
1726 
1727 
1728 
1729 /* virtual */
1730 bool QgsVectorLayer::writeXml( QDomNode &layer_node,
1731  QDomDocument &document,
1732  const QgsReadWriteContext &context ) const
1733 {
1734  // first get the layer element so that we can append the type attribute
1735 
1736  QDomElement mapLayerNode = layer_node.toElement();
1737 
1738  if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
1739  {
1740  QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
1741  return false;
1742  }
1743 
1744  mapLayerNode.setAttribute( QStringLiteral( "type" ), QStringLiteral( "vector" ) );
1745 
1746  // set the geometry type
1747  mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
1748  mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
1749 
1750  // add provider node
1751  if ( mDataProvider )
1752  {
1753  QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1754  provider.setAttribute( QStringLiteral( "encoding" ), mDataProvider->encoding() );
1755  QDomText providerText = document.createTextNode( providerType() );
1756  provider.appendChild( providerText );
1757  layer_node.appendChild( provider );
1758  }
1759 
1760  //save joins
1761  mJoinBuffer->writeXml( layer_node, document );
1762 
1763  // dependencies
1764  QDomElement dependenciesElement = document.createElement( QStringLiteral( "layerDependencies" ) );
1765  const auto constDependencies = dependencies();
1766  for ( const QgsMapLayerDependency &dep : constDependencies )
1767  {
1768  if ( dep.type() != QgsMapLayerDependency::PresenceDependency )
1769  continue;
1770  QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
1771  depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
1772  dependenciesElement.appendChild( depElem );
1773  }
1774  layer_node.appendChild( dependenciesElement );
1775 
1776  // change dependencies
1777  QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
1778  for ( const QgsMapLayerDependency &dep : constDependencies )
1779  {
1780  if ( dep.type() != QgsMapLayerDependency::DataDependency )
1781  continue;
1782  QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
1783  depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
1784  dataDependenciesElement.appendChild( depElem );
1785  }
1786  layer_node.appendChild( dataDependenciesElement );
1787 
1788  // legend
1789  if ( legend() )
1790  {
1791  QDomElement legendElement = legend()->writeXml( document, context );
1792  if ( !legendElement.isNull() )
1793  layer_node.appendChild( legendElement );
1794  }
1795 
1796  // save expression fields
1797  mExpressionFieldBuffer->writeXml( layer_node, document );
1798 
1799  writeStyleManager( layer_node, document );
1800 
1801  // auxiliary layer
1802  QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
1803  if ( mAuxiliaryLayer )
1804  {
1805  const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
1806  asElem.setAttribute( QStringLiteral( "key" ), pkField );
1807  }
1808  layer_node.appendChild( asElem );
1809 
1810  // renderer specific settings
1811  QString errorMsg;
1812  return writeSymbology( layer_node, document, errorMsg, context );
1813 }
1814 
1815 QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1816 {
1817  QString src( source );
1818 
1819  // TODO: what about postgres, mysql and others, they should not go through writePath()
1820  if ( providerType() == QLatin1String( "spatialite" ) )
1821  {
1822  QgsDataSourceUri uri( src );
1823  QString database = context.pathResolver().writePath( uri.database() );
1824  uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
1825  src = uri.uri();
1826  }
1827  else if ( providerType() == QLatin1String( "ogr" ) )
1828  {
1829  QStringList theURIParts = src.split( '|' );
1830  theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
1831  src = theURIParts.join( QStringLiteral( "|" ) );
1832  }
1833  else if ( providerType() == QLatin1String( "gpx" ) )
1834  {
1835  QStringList theURIParts = src.split( '?' );
1836  theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
1837  src = theURIParts.join( QStringLiteral( "?" ) );
1838  }
1839  else if ( providerType() == QLatin1String( "delimitedtext" ) )
1840  {
1841  QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
1842  QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().writePath( urlSource.toLocalFile() ) );
1843  urlDest.setQueryItems( urlSource.queryItems() );
1844  src = QString::fromLatin1( urlDest.toEncoded() );
1845  }
1846  else if ( providerType() == QLatin1String( "memory" ) )
1847  {
1848  // Refetch the source from the provider, because adding fields actually changes the source for this provider.
1849  src = dataProvider()->dataSourceUri();
1850  }
1851  else if ( providerType() == QLatin1String( "virtual" ) )
1852  {
1853  QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
1854  QStringList theURIParts;
1855 
1856  QUrlQuery query = QUrlQuery( urlSource.query() );
1857  QList<QPair<QString, QString> > queryItems = query.queryItems();
1858 
1859  for ( int i = 0; i < queryItems.size(); i++ )
1860  {
1861  QString key = queryItems.at( i ).first;
1862  QString value = queryItems.at( i ).second;
1863  if ( key == QLatin1String( "layer" ) )
1864  {
1865  // syntax: provider:url_encoded_source_URI(:name(:encoding)?)?
1866  theURIParts = value.split( ':' );
1867  theURIParts[1] = QUrl::fromPercentEncoding( theURIParts[1].toUtf8() );
1868  theURIParts[1] = context.pathResolver().writePath( theURIParts[1] );
1869  theURIParts[1] = QUrl::toPercentEncoding( theURIParts[1] );
1870  queryItems[i].second = theURIParts.join( QStringLiteral( ":" ) ) ;
1871  }
1872  }
1873 
1874  query.setQueryItems( queryItems );
1875 
1876  QUrl urlDest = QUrl( urlSource );
1877  urlDest.setQuery( query.query() );
1878  src = QString::fromLatin1( urlDest.toEncoded() );
1879  }
1880  else
1881  {
1882  src = context.pathResolver().writePath( src );
1883  }
1884 
1885  return src;
1886 }
1887 
1888 QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
1889 {
1890  QString src( source );
1891 
1892  if ( provider == QLatin1String( "spatialite" ) )
1893  {
1894  QgsDataSourceUri uri( src );
1895  uri.setDatabase( context.pathResolver().readPath( uri.database() ) );
1896  src = uri.uri();
1897  }
1898  else if ( provider == QLatin1String( "ogr" ) )
1899  {
1900  QStringList theURIParts = src.split( '|' );
1901  theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
1902  src = theURIParts.join( QStringLiteral( "|" ) );
1903  }
1904  else if ( provider == QLatin1String( "gpx" ) )
1905  {
1906  QStringList theURIParts = src.split( '?' );
1907  theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
1908  src = theURIParts.join( QStringLiteral( "?" ) );
1909  }
1910  else if ( provider == QLatin1String( "delimitedtext" ) )
1911  {
1912  QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
1913 
1914  if ( !src.startsWith( QLatin1String( "file:" ) ) )
1915  {
1916  QUrl file = QUrl::fromLocalFile( src.left( src.indexOf( '?' ) ) );
1917  urlSource.setScheme( QStringLiteral( "file" ) );
1918  urlSource.setPath( file.path() );
1919  }
1920 
1921  QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().readPath( urlSource.toLocalFile() ) );
1922  urlDest.setQueryItems( urlSource.queryItems() );
1923  src = QString::fromLatin1( urlDest.toEncoded() );
1924  }
1925  else if ( provider == QLatin1String( "virtual" ) )
1926  {
1927  QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
1928  QStringList theURIParts;
1929 
1930  QUrlQuery query = QUrlQuery( urlSource.query() );
1931  QList<QPair<QString, QString> > queryItems = query.queryItems();
1932 
1933  for ( int i = 0; i < queryItems.size(); i++ )
1934  {
1935  QString key = queryItems.at( i ).first;
1936  QString value = queryItems.at( i ).second;
1937  if ( key == QLatin1String( "layer" ) )
1938  {
1939  // syntax: provider:url_encoded_source_URI(:name(:encoding)?)?
1940  theURIParts = value.split( ':' );
1941  theURIParts[1] = QUrl::fromPercentEncoding( theURIParts[1].toUtf8() );
1942  theURIParts[1] = context.pathResolver().readPath( theURIParts[1] );
1943  theURIParts[1] = QUrl::toPercentEncoding( theURIParts[1] );
1944  queryItems[i].second = theURIParts.join( QStringLiteral( ":" ) ) ;
1945  }
1946  }
1947 
1948  query.setQueryItems( queryItems );
1949 
1950  QUrl urlDest = QUrl( urlSource );
1951  urlDest.setQuery( query.query() );
1952  src = QString::fromLatin1( urlDest.toEncoded() );
1953  }
1954  else
1955  {
1956  src = context.pathResolver().readPath( src );
1957  }
1958 
1959  return src;
1960 }
1961 
1962 
1963 
1965 {
1966  QgsMapLayer::resolveReferences( project );
1967  mJoinBuffer->resolveReferences( project );
1968 }
1969 
1970 
1971 bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage,
1972  QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
1973 {
1974  QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
1975 
1976  if ( categories.testFlag( Fields ) )
1977  {
1978  if ( !mExpressionFieldBuffer )
1979  mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
1980  mExpressionFieldBuffer->readXml( layerNode );
1981 
1982  updateFields();
1983  }
1984 
1985  QDomElement layerElement = layerNode.toElement();
1986 
1987  readCommonStyle( layerElement, context, categories );
1988 
1989  readStyle( layerNode, errorMessage, context, categories );
1990 
1991  if ( categories.testFlag( MapTips ) )
1992  mMapTipTemplate = layerNode.namedItem( QStringLiteral( "mapTip" ) ).toElement().text();
1993 
1994  if ( categories.testFlag( LayerConfiguration ) )
1995  mDisplayExpression = layerNode.namedItem( QStringLiteral( "previewExpression" ) ).toElement().text();
1996 
1997  // Try to migrate pre QGIS 3.0 display field property
1998  QString displayField = layerNode.namedItem( QStringLiteral( "displayfield" ) ).toElement().text();
1999  if ( mFields.lookupField( displayField ) < 0 )
2000  {
2001  // if it's not a field, it's a maptip
2002  if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2003  mMapTipTemplate = displayField;
2004  }
2005  else
2006  {
2007  if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2008  mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2009  }
2010 
2011  // process the attribute actions
2012  if ( categories.testFlag( Actions ) )
2013  mActions->readXml( layerNode );
2014 
2015  if ( categories.testFlag( Fields ) )
2016  {
2017  mAttributeAliasMap.clear();
2018  QDomNode aliasesNode = layerNode.namedItem( QStringLiteral( "aliases" ) );
2019  if ( !aliasesNode.isNull() )
2020  {
2021  QDomElement aliasElem;
2022 
2023  QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( QStringLiteral( "alias" ) );
2024  for ( int i = 0; i < aliasNodeList.size(); ++i )
2025  {
2026  aliasElem = aliasNodeList.at( i ).toElement();
2027 
2028  QString field;
2029  if ( aliasElem.hasAttribute( QStringLiteral( "field" ) ) )
2030  {
2031  field = aliasElem.attribute( QStringLiteral( "field" ) );
2032  }
2033  else
2034  {
2035  int index = aliasElem.attribute( QStringLiteral( "index" ) ).toInt();
2036 
2037  if ( index >= 0 && index < fields().count() )
2038  field = fields().at( index ).name();
2039  }
2040 
2041  QString alias;
2042 
2043  if ( !aliasElem.attribute( QStringLiteral( "name" ) ).isEmpty() )
2044  {
2045  //if it has alias
2046  alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), aliasElem.attribute( QStringLiteral( "name" ) ) );
2047  QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + aliasElem.attribute( QStringLiteral( "name" ) ), 3 );
2048  }
2049  else
2050  {
2051  //if it has no alias, it should be the fields translation
2052  alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), field );
2053  QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + field, 3 );
2054  //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2055  if ( alias == aliasElem.attribute( QStringLiteral( "field" ) ) )
2056  alias.clear();
2057  }
2058 
2059  QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( QStringLiteral( "name" ) ) + " trans " + alias, 3 );
2060  mAttributeAliasMap.insert( field, alias );
2061  }
2062  }
2063 
2064  // default expressions
2065  mDefaultExpressionMap.clear();
2066  QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) );
2067  if ( !defaultsNode.isNull() )
2068  {
2069  QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( QStringLiteral( "default" ) );
2070  for ( int i = 0; i < defaultNodeList.size(); ++i )
2071  {
2072  QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2073 
2074  QString field = defaultElem.attribute( QStringLiteral( "field" ), QString() );
2075  QString expression = defaultElem.attribute( QStringLiteral( "expression" ), QString() );
2076  bool applyOnUpdate = defaultElem.attribute( QStringLiteral( "applyOnUpdate" ), QStringLiteral( "0" ) ) == QLatin1String( "1" );
2077  if ( field.isEmpty() || expression.isEmpty() )
2078  continue;
2079 
2080  mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2081  }
2082  }
2083 
2084  // constraints
2085  mFieldConstraints.clear();
2086  mFieldConstraintStrength.clear();
2087  QDomNode constraintsNode = layerNode.namedItem( QStringLiteral( "constraints" ) );
2088  if ( !constraintsNode.isNull() )
2089  {
2090  QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2091  for ( int i = 0; i < constraintNodeList.size(); ++i )
2092  {
2093  QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2094 
2095  QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2096  int constraints = constraintElem.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
2097  if ( field.isEmpty() || constraints == 0 )
2098  continue;
2099 
2100  mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2101 
2102  int uniqueStrength = constraintElem.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
2103  int notNullStrength = constraintElem.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
2104  int expStrength = constraintElem.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
2105 
2106  mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2107  mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2108  mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2109  }
2110  }
2111  mFieldConstraintExpressions.clear();
2112  QDomNode constraintExpressionsNode = layerNode.namedItem( QStringLiteral( "constraintExpressions" ) );
2113  if ( !constraintExpressionsNode.isNull() )
2114  {
2115  QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2116  for ( int i = 0; i < constraintNodeList.size(); ++i )
2117  {
2118  QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2119 
2120  QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2121  QString exp = constraintElem.attribute( QStringLiteral( "exp" ), QString() );
2122  QString desc = constraintElem.attribute( QStringLiteral( "desc" ), QString() );
2123  if ( field.isEmpty() || exp.isEmpty() )
2124  continue;
2125 
2126  mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2127  }
2128  }
2129 
2130  updateFields();
2131 
2132  //Attributes excluded from WMS and WFS
2133  mExcludeAttributesWMS.clear();
2134  QDomNode excludeWMSNode = layerNode.namedItem( QStringLiteral( "excludeAttributesWMS" ) );
2135  if ( !excludeWMSNode.isNull() )
2136  {
2137  QDomNodeList attributeNodeList = excludeWMSNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2138  for ( int i = 0; i < attributeNodeList.size(); ++i )
2139  {
2140  mExcludeAttributesWMS.insert( attributeNodeList.at( i ).toElement().text() );
2141  }
2142  }
2143 
2144  mExcludeAttributesWFS.clear();
2145  QDomNode excludeWFSNode = layerNode.namedItem( QStringLiteral( "excludeAttributesWFS" ) );
2146  if ( !excludeWFSNode.isNull() )
2147  {
2148  QDomNodeList attributeNodeList = excludeWFSNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2149  for ( int i = 0; i < attributeNodeList.size(); ++i )
2150  {
2151  mExcludeAttributesWFS.insert( attributeNodeList.at( i ).toElement().text() );
2152  }
2153  }
2154 
2155  // Load editor widget configuration
2156  QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
2157  QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
2158  for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2159  {
2160  const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2161  const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();
2162 
2163  QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
2164 
2165  const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
2166  const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
2167  const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2168  QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2169  if ( widgetType == QStringLiteral( "ValueRelation" ) )
2170  {
2171  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() );
2172  }
2173  QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2174  mFieldWidgetSetups[fieldName] = setup;
2175  }
2176  }
2177 
2178  if ( categories.testFlag( GeometryOptions ) )
2179  mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
2180 
2181  if ( categories.testFlag( Forms ) )
2182  mEditFormConfig.readXml( layerNode, context );
2183 
2184  if ( categories.testFlag( AttributeTable ) )
2185  {
2186  mAttributeTableConfig.readXml( layerNode );
2187  mConditionalStyles->readXml( layerNode, context );
2188  mStoredExpressionManager->readXml( layerNode );
2189  }
2190 
2191  if ( categories.testFlag( CustomProperties ) )
2192  readCustomProperties( layerNode, QStringLiteral( "variable" ) );
2193 
2194  QDomElement mapLayerNode = layerNode.toElement();
2195  if ( categories.testFlag( LayerConfiguration )
2196  && mapLayerNode.attribute( QStringLiteral( "readOnly" ), QStringLiteral( "0" ) ).toInt() == 1 )
2197  mReadOnly = true;
2198 
2199  updateFields();
2200 
2201  return true;
2202 }
2203 
2204 bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage,
2205  QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2206 {
2207  bool result = true;
2208  emit readCustomSymbology( node.toElement(), errorMessage );
2209 
2210  // we must try to restore a renderer if our geometry type is unknown
2211  // as this allows the renderer to be correctly restored even for layers
2212  // with broken sources
2213  if ( isSpatial() || mWkbType == QgsWkbTypes::Unknown )
2214  {
2215  // try renderer v2 first
2216  if ( categories.testFlag( Symbology ) )
2217  {
2218  QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2219  if ( !rendererElement.isNull() )
2220  {
2221  QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2222  if ( r )
2223  {
2224  setRenderer( r );
2225  }
2226  else
2227  {
2228  result = false;
2229  }
2230  }
2231  // make sure layer has a renderer - if none exists, fallback to a default renderer
2232  if ( isSpatial() && !renderer() )
2233  {
2235  }
2236  }
2237 
2238  // read labeling definition
2239  if ( categories.testFlag( Labeling ) )
2240  {
2241  QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
2243  if ( labelingElement.isNull() ||
2244  ( labelingElement.attribute( QStringLiteral( "type" ) ) == QLatin1String( "simple" ) && labelingElement.firstChildElement( QStringLiteral( "settings" ) ).isNull() ) )
2245  {
2246  // make sure we have custom properties for labeling for 2.x projects
2247  // (custom properties should be already loaded when reading the whole layer from XML,
2248  // but when reading style, custom properties are not read)
2249  readCustomProperties( node, QStringLiteral( "labeling" ) );
2250 
2251  // support for pre-QGIS 3 labeling configurations written in custom properties
2252  labeling = readLabelingFromCustomProperties();
2253  }
2254  else
2255  {
2256  labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2257  }
2258  setLabeling( labeling );
2259 
2260  if ( node.toElement().hasAttribute( QStringLiteral( "labelsEnabled" ) ) )
2261  mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ) ).toInt();
2262  else
2263  mLabelsEnabled = true;
2264  }
2265 
2266  if ( categories.testFlag( Symbology ) )
2267  {
2268  // get and set the blend mode if it exists
2269  QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
2270  if ( !blendModeNode.isNull() )
2271  {
2272  QDomElement e = blendModeNode.toElement();
2273  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
2274  }
2275 
2276  // get and set the feature blend mode if it exists
2277  QDomNode featureBlendModeNode = node.namedItem( QStringLiteral( "featureBlendMode" ) );
2278  if ( !featureBlendModeNode.isNull() )
2279  {
2280  QDomElement e = featureBlendModeNode.toElement();
2281  setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
2282  }
2283  }
2284 
2285  // get and set the layer transparency if it exists
2286  if ( categories.testFlag( Rendering ) )
2287  {
2288  QDomNode layerTransparencyNode = node.namedItem( QStringLiteral( "layerTransparency" ) );
2289  if ( !layerTransparencyNode.isNull() )
2290  {
2291  QDomElement e = layerTransparencyNode.toElement();
2292  setOpacity( 1.0 - e.text().toInt() / 100.0 );
2293  }
2294  QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
2295  if ( !layerOpacityNode.isNull() )
2296  {
2297  QDomElement e = layerOpacityNode.toElement();
2298  setOpacity( e.text().toDouble() );
2299  }
2300  }
2301 
2302  if ( categories.testFlag( Rendering ) )
2303  {
2304  QDomElement e = node.toElement();
2305 
2306  // get the simplification drawing settings
2307  mSimplifyMethod.setSimplifyHints( static_cast< QgsVectorSimplifyMethod::SimplifyHints >( e.attribute( QStringLiteral( "simplifyDrawingHints" ), QStringLiteral( "1" ) ).toInt() ) );
2308  mSimplifyMethod.setSimplifyAlgorithm( static_cast< QgsVectorSimplifyMethod::SimplifyAlgorithm >( e.attribute( QStringLiteral( "simplifyAlgorithm" ), QStringLiteral( "0" ) ).toInt() ) );
2309  mSimplifyMethod.setThreshold( e.attribute( QStringLiteral( "simplifyDrawingTol" ), QStringLiteral( "1" ) ).toFloat() );
2310  mSimplifyMethod.setForceLocalOptimization( e.attribute( QStringLiteral( "simplifyLocal" ), QStringLiteral( "1" ) ).toInt() );
2311  mSimplifyMethod.setMaximumScale( e.attribute( QStringLiteral( "simplifyMaxScale" ), QStringLiteral( "1" ) ).toFloat() );
2312  }
2313 
2314  //diagram renderer and diagram layer settings
2315  if ( categories.testFlag( Diagrams ) )
2316  {
2317  delete mDiagramRenderer;
2318  mDiagramRenderer = nullptr;
2319  QDomElement singleCatDiagramElem = node.firstChildElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
2320  if ( !singleCatDiagramElem.isNull() )
2321  {
2322  mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
2323  mDiagramRenderer->readXml( singleCatDiagramElem, context );
2324  }
2325  QDomElement linearDiagramElem = node.firstChildElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
2326  if ( !linearDiagramElem.isNull() )
2327  {
2328  if ( linearDiagramElem.hasAttribute( QStringLiteral( "classificationAttribute" ) ) )
2329  {
2330  // fix project from before QGIS 3.0
2331  int idx = linearDiagramElem.attribute( QStringLiteral( "classificationAttribute" ) ).toInt();
2332  if ( idx >= 0 && idx < mFields.count() )
2333  linearDiagramElem.setAttribute( QStringLiteral( "classificationField" ), mFields.at( idx ).name() );
2334  }
2335 
2336  mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
2337  mDiagramRenderer->readXml( linearDiagramElem, context );
2338  }
2339 
2340  if ( mDiagramRenderer )
2341  {
2342  QDomElement diagramSettingsElem = node.firstChildElement( QStringLiteral( "DiagramLayerSettings" ) );
2343  if ( !diagramSettingsElem.isNull() )
2344  {
2345  bool oldXPos = diagramSettingsElem.hasAttribute( QStringLiteral( "xPosColumn" ) );
2346  bool oldYPos = diagramSettingsElem.hasAttribute( QStringLiteral( "yPosColumn" ) );
2347  bool oldShow = diagramSettingsElem.hasAttribute( QStringLiteral( "showColumn" ) );
2348  if ( oldXPos || oldYPos || oldShow )
2349  {
2350  // fix project from before QGIS 3.0
2352  if ( oldXPos )
2353  {
2354  int xPosColumn = diagramSettingsElem.attribute( QStringLiteral( "xPosColumn" ) ).toInt();
2355  if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
2356  ddp.setProperty( QgsDiagramLayerSettings::PositionX, QgsProperty::fromField( mFields.at( xPosColumn ).name(), true ) );
2357  }
2358  if ( oldYPos )
2359  {
2360  int yPosColumn = diagramSettingsElem.attribute( QStringLiteral( "yPosColumn" ) ).toInt();
2361  if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
2362  ddp.setProperty( QgsDiagramLayerSettings::PositionY, QgsProperty::fromField( mFields.at( yPosColumn ).name(), true ) );
2363  }
2364  if ( oldShow )
2365  {
2366  int showColumn = diagramSettingsElem.attribute( QStringLiteral( "showColumn" ) ).toInt();
2367  if ( showColumn >= 0 && showColumn < mFields.count() )
2368  ddp.setProperty( QgsDiagramLayerSettings::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
2369  }
2370  QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( QStringLiteral( "properties" ) );
2372  {
2373  { QgsDiagramLayerSettings::PositionX, QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
2374  { QgsDiagramLayerSettings::PositionY, QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
2375  { QgsDiagramLayerSettings::Show, QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
2376  };
2377  ddp.writeXml( propertiesElem, defs );
2378  diagramSettingsElem.appendChild( propertiesElem );
2379  }
2380 
2381  delete mDiagramLayerSettings;
2382  mDiagramLayerSettings = new QgsDiagramLayerSettings();
2383  mDiagramLayerSettings->readXml( diagramSettingsElem );
2384  }
2385  }
2386  }
2387  // end diagram
2388  }
2389  return result;
2390 }
2391 
2392 
2393 bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2394  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2395 {
2396  QDomElement layerElement = node.toElement();
2397  writeCommonStyle( layerElement, doc, context, categories );
2398 
2399  ( void )writeStyle( node, doc, errorMessage, context, categories );
2400 
2401  if ( categories.testFlag( GeometryOptions ) )
2402  mGeometryOptions->writeXml( node );
2403 
2404  if ( categories.testFlag( Fields ) )
2405  {
2406  QDomElement fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
2407  node.appendChild( fieldConfigurationElement );
2408 
2409  int index = 0;
2410  for ( const QgsField &field : mFields )
2411  {
2412  QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
2413  fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
2414 
2415  fieldConfigurationElement.appendChild( fieldElement );
2416 
2417  QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
2418 
2419  // TODO : wrap this part in an if to only save if it was user-modified
2420  QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
2421  fieldElement.appendChild( editWidgetElement );
2422  editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
2423  QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
2424 
2425  editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
2426  editWidgetElement.appendChild( editWidgetConfigElement );
2427  // END TODO : wrap this part in an if to only save if it was user-modified
2428 
2429  ++index;
2430  }
2431 
2432  //attribute aliases
2433  QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
2434  for ( const QgsField &field : mFields )
2435  {
2436  QDomElement aliasEntryElem = doc.createElement( QStringLiteral( "alias" ) );
2437  aliasEntryElem.setAttribute( QStringLiteral( "field" ), field.name() );
2438  aliasEntryElem.setAttribute( QStringLiteral( "index" ), mFields.indexFromName( field.name() ) );
2439  aliasEntryElem.setAttribute( QStringLiteral( "name" ), field.alias() );
2440  aliasElem.appendChild( aliasEntryElem );
2441  }
2442  node.appendChild( aliasElem );
2443 
2444  //exclude attributes WMS
2445  QDomElement excludeWMSElem = doc.createElement( QStringLiteral( "excludeAttributesWMS" ) );
2446  QSet<QString>::const_iterator attWMSIt = mExcludeAttributesWMS.constBegin();
2447  for ( ; attWMSIt != mExcludeAttributesWMS.constEnd(); ++attWMSIt )
2448  {
2449  QDomElement attrElem = doc.createElement( QStringLiteral( "attribute" ) );
2450  QDomText attrText = doc.createTextNode( *attWMSIt );
2451  attrElem.appendChild( attrText );
2452  excludeWMSElem.appendChild( attrElem );
2453  }
2454  node.appendChild( excludeWMSElem );
2455 
2456  //exclude attributes WFS
2457  QDomElement excludeWFSElem = doc.createElement( QStringLiteral( "excludeAttributesWFS" ) );
2458  QSet<QString>::const_iterator attWFSIt = mExcludeAttributesWFS.constBegin();
2459  for ( ; attWFSIt != mExcludeAttributesWFS.constEnd(); ++attWFSIt )
2460  {
2461  QDomElement attrElem = doc.createElement( QStringLiteral( "attribute" ) );
2462  QDomText attrText = doc.createTextNode( *attWFSIt );
2463  attrElem.appendChild( attrText );
2464  excludeWFSElem.appendChild( attrElem );
2465  }
2466  node.appendChild( excludeWFSElem );
2467 
2468  //default expressions
2469  QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) );
2470  for ( const QgsField &field : mFields )
2471  {
2472  QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
2473  defaultElem.setAttribute( QStringLiteral( "field" ), field.name() );
2474  defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
2475  defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
2476  defaultsElem.appendChild( defaultElem );
2477  }
2478  node.appendChild( defaultsElem );
2479 
2480  // constraints
2481  QDomElement constraintsElem = doc.createElement( QStringLiteral( "constraints" ) );
2482  for ( const QgsField &field : mFields )
2483  {
2484  QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
2485  constraintElem.setAttribute( QStringLiteral( "field" ), field.name() );
2486  constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
2487  constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
2488  constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
2489  constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
2490  constraintsElem.appendChild( constraintElem );
2491  }
2492  node.appendChild( constraintsElem );
2493 
2494  // constraint expressions
2495  QDomElement constraintExpressionsElem = doc.createElement( QStringLiteral( "constraintExpressions" ) );
2496  for ( const QgsField &field : mFields )
2497  {
2498  QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraint" ) );
2499  constraintExpressionElem.setAttribute( QStringLiteral( "field" ), field.name() );
2500  constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
2501  constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
2502  constraintExpressionsElem.appendChild( constraintExpressionElem );
2503  }
2504  node.appendChild( constraintExpressionsElem );
2505 
2506  // save expression fields
2507  if ( !mExpressionFieldBuffer )
2508  {
2509  // can happen when saving style on a invalid layer
2511  dummy.writeXml( node, doc );
2512  }
2513  else
2514  {
2515  mExpressionFieldBuffer->writeXml( node, doc );
2516  }
2517  }
2518 
2519  // add attribute actions
2520  if ( categories.testFlag( Actions ) )
2521  mActions->writeXml( node );
2522 
2523  if ( categories.testFlag( AttributeTable ) )
2524  {
2525  mAttributeTableConfig.writeXml( node );
2526  mConditionalStyles->writeXml( node, doc, context );
2527  mStoredExpressionManager->writeXml( node );
2528  }
2529 
2530  if ( categories.testFlag( Forms ) )
2531  mEditFormConfig.writeXml( node, context );
2532 
2533  // save readonly state
2534  if ( categories.testFlag( LayerConfiguration ) )
2535  node.toElement().setAttribute( QStringLiteral( "readOnly" ), mReadOnly );
2536 
2537  // save preview expression
2538  if ( categories.testFlag( LayerConfiguration ) )
2539  {
2540  QDomElement prevExpElem = doc.createElement( QStringLiteral( "previewExpression" ) );
2541  QDomText prevExpText = doc.createTextNode( mDisplayExpression );
2542  prevExpElem.appendChild( prevExpText );
2543  node.appendChild( prevExpElem );
2544  }
2545 
2546  // save map tip
2547  if ( categories.testFlag( MapTips ) )
2548  {
2549  QDomElement mapTipElem = doc.createElement( QStringLiteral( "mapTip" ) );
2550  QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
2551  mapTipElem.appendChild( mapTipText );
2552  node.toElement().appendChild( mapTipElem );
2553  }
2554 
2555  return true;
2556 }
2557 
2558 bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2559  const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2560 {
2561  QDomElement mapLayerNode = node.toElement();
2562 
2563  emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
2564 
2565  if ( isSpatial() )
2566  {
2567  if ( categories.testFlag( Symbology ) )
2568  {
2569  if ( mRenderer )
2570  {
2571  QDomElement rendererElement = mRenderer->save( doc, context );
2572  node.appendChild( rendererElement );
2573  }
2574  }
2575 
2576  if ( categories.testFlag( Labeling ) )
2577  {
2578  if ( mLabeling )
2579  {
2580  QDomElement labelingElement = mLabeling->save( doc, context );
2581  node.appendChild( labelingElement );
2582  }
2583  mapLayerNode.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
2584  }
2585 
2586  // save the simplification drawing settings
2587  if ( categories.testFlag( Rendering ) )
2588  {
2589  mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingHints" ), QString::number( mSimplifyMethod.simplifyHints() ) );
2590  mapLayerNode.setAttribute( QStringLiteral( "simplifyAlgorithm" ), QString::number( mSimplifyMethod.simplifyAlgorithm() ) );
2591  mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingTol" ), QString::number( mSimplifyMethod.threshold() ) );
2592  mapLayerNode.setAttribute( QStringLiteral( "simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
2593  mapLayerNode.setAttribute( QStringLiteral( "simplifyMaxScale" ), QString::number( mSimplifyMethod.maximumScale() ) );
2594  }
2595 
2596  //save customproperties
2597  if ( categories.testFlag( CustomProperties ) )
2598  {
2599  writeCustomProperties( node, doc );
2600  }
2601 
2602  if ( categories.testFlag( Symbology ) )
2603  {
2604  // add the blend mode field
2605  QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
2606  QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
2607  blendModeElem.appendChild( blendModeText );
2608  node.appendChild( blendModeElem );
2609 
2610  // add the feature blend mode field
2611  QDomElement featureBlendModeElem = doc.createElement( QStringLiteral( "featureBlendMode" ) );
2612  QDomText featureBlendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) );
2613  featureBlendModeElem.appendChild( featureBlendModeText );
2614  node.appendChild( featureBlendModeElem );
2615  }
2616 
2617  // add the layer opacity
2618  if ( categories.testFlag( Rendering ) )
2619  {
2620  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
2621  QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
2622  layerOpacityElem.appendChild( layerOpacityText );
2623  node.appendChild( layerOpacityElem );
2624  }
2625 
2626  if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
2627  {
2628  mDiagramRenderer->writeXml( mapLayerNode, doc, context );
2629  if ( mDiagramLayerSettings )
2630  mDiagramLayerSettings->writeXml( mapLayerNode, doc );
2631  }
2632  }
2633  return true;
2634 }
2635 
2636 bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
2637 {
2638  // get the Name element
2639  QDomElement nameElem = node.firstChildElement( QStringLiteral( "Name" ) );
2640  if ( nameElem.isNull() )
2641  {
2642  errorMessage = QStringLiteral( "Warning: Name element not found within NamedLayer while it's required." );
2643  }
2644 
2645  if ( isSpatial() )
2646  {
2647  QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
2648  if ( !r )
2649  return false;
2650 
2651  setRenderer( r );
2652 
2653  // labeling
2654  readSldLabeling( node );
2655  }
2656  return true;
2657 }
2658 
2659 bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsStringMap &props ) const
2660 {
2661  Q_UNUSED( errorMessage )
2662 
2663  QgsStringMap localProps = QgsStringMap( props );
2664  if ( hasScaleBasedVisibility() )
2665  {
2667  }
2668 
2669  if ( isSpatial() )
2670  {
2671  // store the Name element
2672  QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
2673  nameNode.appendChild( doc.createTextNode( name() ) );
2674  node.appendChild( nameNode );
2675 
2676  QDomElement userStyleElem = doc.createElement( QStringLiteral( "UserStyle" ) );
2677  node.appendChild( userStyleElem );
2678 
2679  QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
2680  nameElem.appendChild( doc.createTextNode( name() ) );
2681 
2682  userStyleElem.appendChild( nameElem );
2683 
2684  QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "se:FeatureTypeStyle" ) );
2685  userStyleElem.appendChild( featureTypeStyleElem );
2686 
2687  mRenderer->toSld( doc, featureTypeStyleElem, localProps );
2688  if ( labelsEnabled() )
2689  {
2690  mLabeling->toSld( featureTypeStyleElem, localProps );
2691  }
2692  }
2693  return true;
2694 }
2695 
2696 
2697 bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
2698 {
2699  if ( !mEditBuffer || !mDataProvider )
2700  {
2701  return false;
2702  }
2703 
2704  if ( mGeometryOptions->isActive() )
2705  mGeometryOptions->apply( geom );
2706 
2707  updateExtents();
2708 
2709  bool result = mEditBuffer->changeGeometry( fid, geom );
2710 
2711  if ( result )
2712  {
2713  updateExtents();
2714  if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
2715  updateDefaultValues( fid );
2716  }
2717  return result;
2718 }
2719 
2720 
2721 bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues )
2722 {
2723  bool result = false;
2724 
2725  switch ( fields().fieldOrigin( field ) )
2726  {
2727  case QgsFields::OriginJoin:
2728  result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
2729  if ( result )
2730  emit attributeValueChanged( fid, field, newValue );
2731  break;
2732 
2734  case QgsFields::OriginEdit:
2736  {
2737  if ( mEditBuffer && mDataProvider )
2738  result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
2739  break;
2740  }
2741 
2743  break;
2744  }
2745 
2746  if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
2747  updateDefaultValues( fid );
2748 
2749  return result;
2750 }
2751 
2752 bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues )
2753 {
2754  bool result = true;
2755 
2756  QgsAttributeMap newValuesJoin;
2757  QgsAttributeMap oldValuesJoin;
2758 
2759  QgsAttributeMap newValuesNotJoin;
2760  QgsAttributeMap oldValuesNotJoin;
2761 
2762  for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
2763  {
2764  const int field = it.key();
2765  const QVariant newValue = it.value();
2766  QVariant oldValue;
2767 
2768  if ( oldValues.contains( field ) )
2769  oldValue = oldValues[field];
2770 
2771  switch ( fields().fieldOrigin( field ) )
2772  {
2773  case QgsFields::OriginJoin:
2774  newValuesJoin[field] = newValue;
2775  oldValuesJoin[field] = oldValue;
2776  break;
2777 
2779  case QgsFields::OriginEdit:
2781  {
2782  newValuesNotJoin[field] = newValue;
2783  oldValuesNotJoin[field] = oldValue;
2784  break;
2785  }
2786 
2788  break;
2789  }
2790  }
2791 
2792  if ( ! newValuesJoin.isEmpty() && mJoinBuffer )
2793  {
2794  result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
2795  }
2796 
2797  if ( ! newValuesNotJoin.isEmpty() && mEditBuffer && mDataProvider )
2798  {
2799  result &= mEditBuffer->changeAttributeValues( fid, newValues, oldValues );
2800  }
2801 
2802  if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
2803  {
2804  updateDefaultValues( fid );
2805  }
2806 
2807  return result;
2808 }
2809 
2811 {
2812  if ( !mEditBuffer || !mDataProvider )
2813  return false;
2814 
2815  return mEditBuffer->addAttribute( field );
2816 }
2817 
2819 {
2820  if ( attIndex < 0 || attIndex >= fields().count() )
2821  return;
2822 
2823  QString name = fields().at( attIndex ).name();
2824  mFields[ attIndex ].setAlias( QString() );
2825  if ( mAttributeAliasMap.contains( name ) )
2826  {
2827  mAttributeAliasMap.remove( name );
2828  updateFields();
2829  mEditFormConfig.setFields( mFields );
2830  emit layerModified();
2831  }
2832 }
2833 
2834 bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
2835 {
2836  if ( index < 0 || index >= fields().count() )
2837  return false;
2838 
2839  switch ( mFields.fieldOrigin( index ) )
2840  {
2842  {
2843  if ( mExpressionFieldBuffer )
2844  {
2845  int oi = mFields.fieldOriginIndex( index );
2846  mExpressionFieldBuffer->renameExpression( oi, newName );
2847  updateFields();
2848  return true;
2849  }
2850  else
2851  {
2852  return false;
2853  }
2854  }
2855 
2857  case QgsFields::OriginEdit:
2858 
2859  if ( !mEditBuffer || !mDataProvider )
2860  return false;
2861 
2862  return mEditBuffer->renameAttribute( index, newName );
2863 
2864  case QgsFields::OriginJoin:
2866  return false;
2867 
2868  }
2869 
2870  return false; // avoid warning
2871 }
2872 
2873 void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
2874 {
2875  if ( attIndex < 0 || attIndex >= fields().count() )
2876  return;
2877 
2878  QString name = fields().at( attIndex ).name();
2879 
2880  mAttributeAliasMap.insert( name, aliasString );
2881  mFields[ attIndex ].setAlias( aliasString );
2882  mEditFormConfig.setFields( mFields );
2883  emit layerModified(); // TODO[MD]: should have a different signal?
2884 }
2885 
2886 QString QgsVectorLayer::attributeAlias( int index ) const
2887 {
2888  if ( index < 0 || index >= fields().count() )
2889  return QString();
2890 
2891  return fields().at( index ).alias();
2892 }
2893 
2894 QString QgsVectorLayer::attributeDisplayName( int index ) const
2895 {
2896  if ( index >= 0 && index < mFields.count() )
2897  return mFields.at( index ).displayName();
2898  else
2899  return QString();
2900 }
2901 
2903 {
2904  return mAttributeAliasMap;
2905 }
2906 
2908 {
2909  if ( index < 0 || index >= fields().count() )
2910  return false;
2911 
2912  if ( mFields.fieldOrigin( index ) == QgsFields::OriginExpression )
2913  {
2914  removeExpressionField( index );
2915  return true;
2916  }
2917 
2918  if ( !mEditBuffer || !mDataProvider )
2919  return false;
2920 
2921  return mEditBuffer->deleteAttribute( index );
2922 }
2923 
2924 bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
2925 {
2926  bool deleted = false;
2927 
2928  // Remove multiple occurrences of same attribute
2929  QList<int> attrList = attrs.toSet().toList();
2930 
2931  std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
2932 
2933  for ( int attr : qgis::as_const( attrList ) )
2934  {
2935  if ( deleteAttribute( attr ) )
2936  {
2937  deleted = true;
2938  }
2939  }
2940 
2941  return deleted;
2942 }
2943 
2945 {
2946  if ( !mEditBuffer )
2947  return false;
2948 
2949  if ( mJoinBuffer->containsJoins() )
2950  mJoinBuffer->deleteFeature( fid );
2951 
2952  bool res = mEditBuffer->deleteFeature( fid );
2953  if ( res )
2954  {
2955  mSelectedFeatureIds.remove( fid ); // remove it from selection
2956  updateExtents();
2957  }
2958 
2959  return res;
2960 }
2961 
2963 {
2964  if ( !mEditBuffer )
2965  {
2966  QgsDebugMsgLevel( QStringLiteral( "Cannot delete features (mEditBuffer==NULL)" ), 1 );
2967  return false;
2968  }
2969 
2970  if ( mJoinBuffer->containsJoins() )
2971  mJoinBuffer->deleteFeatures( fids );
2972 
2973  bool res = mEditBuffer->deleteFeatures( fids );
2974 
2975  if ( res )
2976  {
2977  mSelectedFeatureIds.subtract( fids ); // remove it from selection
2978  updateExtents();
2979  }
2980 
2981  return res;
2982 }
2983 
2985 {
2986  return mFields;
2987 }
2988 
2990 {
2991  QgsAttributeList pkAttributesList;
2992 
2993  QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
2994  for ( int i = 0; i < mFields.count(); ++i )
2995  {
2996  if ( mFields.fieldOrigin( i ) == QgsFields::OriginProvider &&
2997  providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
2998  pkAttributesList << i;
2999  }
3000 
3001  return pkAttributesList;
3002 }
3003 
3005 {
3006  if ( ! mDataProvider )
3007  return -1;
3008  return mDataProvider->featureCount() +
3009  ( mEditBuffer ? mEditBuffer->mAddedFeatures.size() - mEditBuffer->mDeletedFeatureIds.size() : 0 );
3010 }
3011 
3013 {
3014  const QgsFeatureIds deletedFeatures( mEditBuffer ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3015  const QgsFeatureMap addedFeatures( mEditBuffer ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
3016 
3017  if ( mEditBuffer && !deletedFeatures.empty() )
3018  {
3019  if ( addedFeatures.size() > deletedFeatures.size() )
3020  return QgsFeatureSource::FeatureAvailability::FeaturesAvailable;
3021  else
3022  return QgsFeatureSource::FeatureAvailability::FeaturesMaybeAvailable;
3023  }
3024 
3025  if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider->empty() )
3026  return QgsFeatureSource::FeatureAvailability::NoFeaturesAvailable;
3027  else
3028  return QgsFeatureSource::FeatureAvailability::FeaturesAvailable;
3029 }
3030 
3032 {
3033  mCommitErrors.clear();
3034 
3035  if ( !mDataProvider )
3036  {
3037  mCommitErrors << tr( "ERROR: no provider" );
3038  return false;
3039  }
3040 
3041  if ( !mEditBuffer )
3042  {
3043  mCommitErrors << tr( "ERROR: layer not editable" );
3044  return false;
3045  }
3046 
3047  emit beforeCommitChanges();
3048 
3049  if ( !mAllowCommit )
3050  return false;
3051 
3052  bool success = mEditBuffer->commitChanges( mCommitErrors );
3053 
3054  if ( success )
3055  {
3056  delete mEditBuffer;
3057  mEditBuffer = nullptr;
3058  undoStack()->clear();
3059  emit editingStopped();
3060  }
3061  else
3062  {
3063  QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( QStringLiteral( "\n " ) ) ) );
3064  }
3065 
3066  updateFields();
3067  mDataProvider->updateExtents();
3068 
3069  mDataProvider->leaveUpdateMode();
3070 
3071  triggerRepaint();
3072 
3073  return success;
3074 }
3075 
3076 QStringList QgsVectorLayer::commitErrors() const
3077 {
3078  return mCommitErrors;
3079 }
3080 
3081 bool QgsVectorLayer::rollBack( bool deleteBuffer )
3082 {
3083  if ( !mEditBuffer )
3084  {
3085  return false;
3086  }
3087 
3088  bool rollbackExtent = !mEditBuffer->mDeletedFeatureIds.isEmpty() ||
3089  !mEditBuffer->mAddedFeatures.isEmpty() ||
3090  !mEditBuffer->mChangedGeometries.isEmpty();
3091 
3092  emit beforeRollBack();
3093 
3094  mEditBuffer->rollBack();
3095 
3096  emit afterRollBack();
3097 
3098  if ( isModified() )
3099  {
3100  // new undo stack roll back method
3101  // old method of calling every undo could cause many canvas refreshes
3102  undoStack()->setIndex( 0 );
3103  }
3104 
3105  updateFields();
3106 
3107  if ( deleteBuffer )
3108  {
3109  delete mEditBuffer;
3110  mEditBuffer = nullptr;
3111  undoStack()->clear();
3112  }
3113  emit editingStopped();
3114 
3115  if ( rollbackExtent )
3116  updateExtents();
3117 
3118  mDataProvider->leaveUpdateMode();
3119 
3120  triggerRepaint();
3121  return true;
3122 }
3123 
3125 {
3126  return mSelectedFeatureIds.size();
3127 }
3128 
3130 {
3131  return mSelectedFeatureIds;
3132 }
3133 
3135 {
3136  QgsFeatureList features;
3137  features.reserve( mSelectedFeatureIds.count() );
3138  QgsFeature f;
3139 
3140  if ( mSelectedFeatureIds.count() <= 8 )
3141  {
3142  // for small amount of selected features, fetch them directly
3143  // because request with FilterFids would go iterate over the whole layer
3144  const auto constMSelectedFeatureIds = mSelectedFeatureIds;
3145  for ( QgsFeatureId fid : constMSelectedFeatureIds )
3146  {
3147  getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f );
3148  features << f;
3149  }
3150  }
3151  else
3152  {
3154 
3155  while ( it.nextFeature( f ) )
3156  {
3157  features.push_back( f );
3158  }
3159  }
3160 
3161  return features;
3162 }
3163 
3165 {
3166  if ( mSelectedFeatureIds.isEmpty() )
3167  return QgsFeatureIterator();
3168 
3171 
3172  if ( mSelectedFeatureIds.count() == 1 )
3173  request.setFilterFid( *mSelectedFeatureIds.constBegin() );
3174  else
3175  request.setFilterFids( mSelectedFeatureIds );
3176 
3177  return getFeatures( request );
3178 }
3179 
3181 {
3182  if ( !mEditBuffer || !mDataProvider )
3183  return false;
3184 
3185  if ( mGeometryOptions->isActive() )
3186  {
3187  for ( auto feature = features.begin(); feature != features.end(); ++feature )
3188  {
3189  QgsGeometry geom = feature->geometry();
3190  mGeometryOptions->apply( geom );
3191  feature->setGeometry( geom );
3192  }
3193  }
3194 
3195  bool res = mEditBuffer->addFeatures( features );
3196  updateExtents();
3197 
3198  if ( res && mJoinBuffer->containsJoins() )
3199  res = mJoinBuffer->addFeatures( features );
3200 
3201  return res;
3202 }
3203 
3205 {
3206  // if layer is not spatial, it has not CRS!
3207  setCrs( isSpatial() ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
3208 }
3209 
3211 {
3213  if ( exp.isField() )
3214  {
3215  return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
3216  }
3217 
3218  return QString();
3219 }
3220 
3222 {
3223  if ( mDisplayExpression == displayExpression )
3224  return;
3225 
3226  mDisplayExpression = displayExpression;
3227  emit displayExpressionChanged();
3228 }
3229 
3230 QString QgsVectorLayer::displayExpression() const
3231 {
3232  if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
3233  {
3234  return mDisplayExpression;
3235  }
3236  else
3237  {
3238  QString idxName;
3239 
3240  // Check the fields and keep the first one that matches.
3241  // We assume that the user has organized the data with the
3242  // more "interesting" field names first. As such, name should
3243  // be selected before oldname, othername, etc.
3244  // This candidates list is a prioritized list of candidates ranked by "interestingness"!
3245  // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
3246  // but adding hardcoded localized variants of the strings is encouraged.
3247  static QStringList sCandidates{ QStringLiteral( "name" ),
3248  QStringLiteral( "title" ),
3249  QStringLiteral( "heibt" ),
3250  QStringLiteral( "desc" ),
3251  QStringLiteral( "nom" ),
3252  QStringLiteral( "street" ),
3253  QStringLiteral( "road" ),
3254  QStringLiteral( "id" )};
3255  for ( const QString &candidate : sCandidates )
3256  {
3257  for ( const QgsField &field : mFields )
3258  {
3259  QString fldName = field.name();
3260  if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
3261  {
3262  idxName = fldName;
3263  break;
3264  }
3265  }
3266 
3267  if ( !idxName.isEmpty() )
3268  break;
3269  }
3270 
3271  if ( !idxName.isNull() )
3272  {
3273  return QgsExpression::quotedColumnRef( idxName );
3274  }
3275  else
3276  {
3277  return QgsExpression::quotedColumnRef( mFields.at( 0 ).name() );
3278  }
3279  }
3280 }
3281 
3283 {
3284  return ( mEditBuffer && mDataProvider );
3285 }
3286 
3288 {
3291 }
3292 
3293 bool QgsVectorLayer::isReadOnly() const
3294 {
3295  return mReadOnly;
3296 }
3297 
3298 bool QgsVectorLayer::setReadOnly( bool readonly )
3299 {
3300  // exit if the layer is in editing mode
3301  if ( readonly && mEditBuffer )
3302  return false;
3303 
3304  mReadOnly = readonly;
3305  emit readOnlyChanged();
3306  return true;
3307 }
3308 
3310 {
3311  emit beforeModifiedCheck();
3312  return mEditBuffer && mEditBuffer->isModified();
3313 }
3314 
3315 bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
3316 {
3317  bool auxiliaryField = false;
3318  srcIndex = -1;
3319 
3320  if ( !auxiliaryLayer() )
3321  return auxiliaryField;
3322 
3323  if ( index >= 0 && fields().fieldOrigin( index ) == QgsFields::OriginJoin )
3324  {
3325  const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
3326 
3327  if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
3328  auxiliaryField = true;
3329  }
3330 
3331  return auxiliaryField;
3332 }
3333 
3335 {
3336  // we must allow setting a renderer if our geometry type is unknown
3337  // as this allows the renderer to be correctly set even for layers
3338  // with broken sources
3339  if ( !isSpatial() && mWkbType != QgsWkbTypes::Unknown )
3340  return;
3341 
3342  if ( r != mRenderer )
3343  {
3344  delete mRenderer;
3345  mRenderer = r;
3346  mSymbolFeatureCounted = false;
3347  mSymbolFeatureCountMap.clear();
3348  mSymbolFeatureIdMap.clear();
3349 
3350  emit rendererChanged();
3351  emit styleChanged();
3352  }
3353 }
3354 
3355 void QgsVectorLayer::beginEditCommand( const QString &text )
3356 {
3357  if ( !mDataProvider )
3358  {
3359  return;
3360  }
3361  if ( mDataProvider->transaction() )
3362  {
3363  QString ignoredError;
3364  mDataProvider->transaction()->createSavepoint( ignoredError );
3365  }
3366  undoStack()->beginMacro( text );
3367  mEditCommandActive = true;
3368  emit editCommandStarted( text );
3369 }
3370 
3372 {
3373  if ( !mDataProvider )
3374  {
3375  return;
3376  }
3377  undoStack()->endMacro();
3378  mEditCommandActive = false;
3379  if ( !mDeletedFids.isEmpty() )
3380  {
3381  emit featuresDeleted( mDeletedFids );
3382  mDeletedFids.clear();
3383  }
3384  emit editCommandEnded();
3385 }
3386 
3388 {
3389  if ( !mDataProvider )
3390  {
3391  return;
3392  }
3393  undoStack()->endMacro();
3394  undoStack()->undo();
3395 
3396  // it's not directly possible to pop the last command off the stack (the destroyed one)
3397  // and delete, so we add a dummy obsolete command to force this to occur.
3398  // Pushing the new command deletes the destroyed one, and since the new
3399  // command is obsolete it's automatically deleted by the undo stack.
3400  std::unique_ptr< QUndoCommand > command = qgis::make_unique< QUndoCommand >();
3401  command->setObsolete( true );
3402  undoStack()->push( command.release() );
3403 
3404  mEditCommandActive = false;
3405  mDeletedFids.clear();
3406  emit editCommandDestroyed();
3407 }
3408 
3410 {
3411  return mJoinBuffer->addJoin( joinInfo );
3412 }
3413 
3414 
3415 bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
3416 {
3417  return mJoinBuffer->removeJoin( joinLayerId );
3418 }
3419 
3420 const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
3421 {
3422  return mJoinBuffer->vectorJoins();
3423 }
3424 
3425 int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
3426 {
3427  emit beforeAddingExpressionField( fld.name() );
3428  mExpressionFieldBuffer->addExpression( exp, fld );
3429  updateFields();
3430  int idx = mFields.indexFromName( fld.name() );
3431  emit attributeAdded( idx );
3432  return idx;
3433 }
3434 
3436 {
3437  emit beforeRemovingExpressionField( index );
3438  int oi = mFields.fieldOriginIndex( index );
3439  mExpressionFieldBuffer->removeExpression( oi );
3440  updateFields();
3441  emit attributeDeleted( index );
3442 }
3443 
3444 QString QgsVectorLayer::expressionField( int index ) const
3445 {
3446  int oi = mFields.fieldOriginIndex( index );
3447  if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
3448  return QString();
3449 
3450  return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
3451 }
3452 
3453 void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
3454 {
3455  int oi = mFields.fieldOriginIndex( index );
3456  mExpressionFieldBuffer->updateExpression( oi, exp );
3457 }
3458 
3460 {
3461  if ( !mDataProvider )
3462  return;
3463 
3464  QgsFields oldFields = mFields;
3465 
3466  mFields = mDataProvider->fields();
3467 
3468  // added / removed fields
3469  if ( mEditBuffer )
3470  mEditBuffer->updateFields( mFields );
3471 
3472  // joined fields
3473  if ( mJoinBuffer->containsJoins() )
3474  mJoinBuffer->updateFields( mFields );
3475 
3476  if ( mExpressionFieldBuffer )
3477  mExpressionFieldBuffer->updateFields( mFields );
3478 
3479  // set aliases and default values
3480  QMap< QString, QString >::const_iterator aliasIt = mAttributeAliasMap.constBegin();
3481  for ( ; aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
3482  {
3483  int index = mFields.lookupField( aliasIt.key() );
3484  if ( index < 0 )
3485  continue;
3486 
3487  mFields[ index ].setAlias( aliasIt.value() );
3488  }
3489 
3490  // Update default values
3491  mDefaultValueOnUpdateFields.clear();
3492  QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
3493  for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
3494  {
3495  int index = mFields.lookupField( defaultIt.key() );
3496  if ( index < 0 )
3497  continue;
3498 
3499  mFields[ index ].setDefaultValueDefinition( defaultIt.value() );
3500  if ( defaultIt.value().applyOnUpdate() )
3501  mDefaultValueOnUpdateFields.insert( index );
3502  }
3503 
3504  QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
3505  for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
3506  {
3507  int index = mFields.lookupField( constraintIt.key() );
3508  if ( index < 0 )
3509  continue;
3510 
3511  QgsFieldConstraints constraints = mFields.at( index ).constraints();
3512 
3513  // always keep provider constraints intact
3514  if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
3516  if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
3518  if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
3520  mFields[ index ].setConstraints( constraints );
3521  }
3522 
3523  QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
3524  for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
3525  {
3526  int index = mFields.lookupField( constraintExpIt.key() );
3527  if ( index < 0 )
3528  continue;
3529 
3530  QgsFieldConstraints constraints = mFields.at( index ).constraints();
3531 
3532  // always keep provider constraints intact
3534  continue;
3535 
3536  constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
3537  mFields[ index ].setConstraints( constraints );
3538  }
3539 
3540  QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
3541  for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
3542  {
3543  int index = mFields.lookupField( constraintStrengthIt.key().first );
3544  if ( index < 0 )
3545  continue;
3546 
3547  QgsFieldConstraints constraints = mFields.at( index ).constraints();
3548 
3549  // always keep provider constraints intact
3551  continue;
3552 
3553  constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
3554  mFields[ index ].setConstraints( constraints );
3555  }
3556 
3557  auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
3558  for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++ fieldWidgetIterator )
3559  {
3560  int index = mFields.indexOf( fieldWidgetIterator.key() );
3561  if ( index < 0 )
3562  continue;
3563 
3564  mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
3565  }
3566 
3567  if ( oldFields != mFields )
3568  {
3569  emit updatedFields();
3570  mEditFormConfig.setFields( mFields );
3571  }
3572 }
3573 
3574 
3575 QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
3576 {
3577  if ( index < 0 || index >= mFields.count() )
3578  return QVariant();
3579 
3580  QString expression = mFields.at( index ).defaultValueDefinition().expression();
3581  if ( expression.isEmpty() )
3582  return mDataProvider->defaultValue( index );
3583 
3584  QgsExpressionContext *evalContext = context;
3585  std::unique_ptr< QgsExpressionContext > tempContext;
3586  if ( !evalContext )
3587  {
3588  // no context passed, so we create a default one
3590  evalContext = tempContext.get();
3591  }
3592 
3593  if ( feature.isValid() )
3594  {
3596  featScope->setFeature( feature );
3597  featScope->setFields( feature.fields() );
3598  evalContext->appendScope( featScope );
3599  }
3600 
3601  QVariant val;
3602  QgsExpression exp( expression );
3603  exp.prepare( evalContext );
3604  if ( exp.hasEvalError() )
3605  {
3606  QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
3607  }
3608  else
3609  {
3610  val = exp.evaluate( evalContext );
3611  }
3612 
3613  if ( feature.isValid() )
3614  {
3615  delete evalContext->popScope();
3616  }
3617 
3618  return val;
3619 }
3620 
3622 {
3623  if ( index < 0 || index >= mFields.count() )
3624  return;
3625 
3626  if ( definition.isValid() )
3627  {
3628  mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
3629  }
3630  else
3631  {
3632  mDefaultExpressionMap.remove( mFields.at( index ).name() );
3633  }
3634  updateFields();
3635 }
3636 
3638 {
3639  if ( index < 0 || index >= mFields.count() )
3640  return QgsDefaultValue();
3641  else
3642  return mFields.at( index ).defaultValueDefinition();
3643 }
3644 
3645 QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
3646 {
3647  QSet<QVariant> uniqueValues;
3648  if ( !mDataProvider )
3649  {
3650  return uniqueValues;
3651  }
3652 
3653  QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
3654  switch ( origin )
3655  {
3657  return uniqueValues;
3658 
3659  case QgsFields::OriginProvider: //a provider field
3660  {
3661  uniqueValues = mDataProvider->uniqueValues( index, limit );
3662 
3663  if ( mEditBuffer )
3664  {
3665  QSet<QString> vals;
3666  const auto constUniqueValues = uniqueValues;
3667  for ( const QVariant &v : constUniqueValues )
3668  {
3669  vals << v.toString();
3670  }
3671 
3672  QgsFeatureMap added = mEditBuffer->addedFeatures();
3673  QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
3674  while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
3675  {
3676  addedIt.next();
3677  QVariant v = addedIt.value().attribute( index );
3678  if ( v.isValid() )
3679  {
3680  QString vs = v.toString();
3681  if ( !vals.contains( vs ) )
3682  {
3683  vals << vs;
3684  uniqueValues << v;
3685  }
3686  }
3687  }
3688 
3689  QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
3690  while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
3691  {
3692  it.next();
3693  QVariant v = it.value().value( index );
3694  if ( v.isValid() )
3695  {
3696  QString vs = v.toString();
3697  if ( !vals.contains( vs ) )
3698  {
3699  vals << vs;
3700  uniqueValues << v;
3701  }
3702  }
3703  }
3704  }
3705 
3706  return uniqueValues;
3707  }
3708 
3709  case QgsFields::OriginEdit:
3710  // the layer is editable, but in certain cases it can still be avoided going through all features
3711  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
3712  mEditBuffer->mAddedFeatures.isEmpty() &&
3713  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
3714  mEditBuffer->mChangedAttributeValues.isEmpty() )
3715  {
3716  uniqueValues = mDataProvider->uniqueValues( index, limit );
3717  return uniqueValues;
3718  }
3719  FALLTHROUGH
3720  //we need to go through each feature
3721  case QgsFields::OriginJoin:
3723  {
3724  QgsAttributeList attList;
3725  attList << index;
3726 
3729  .setSubsetOfAttributes( attList ) );
3730 
3731  QgsFeature f;
3732  QVariant currentValue;
3733  QHash<QString, QVariant> val;
3734  while ( fit.nextFeature( f ) )
3735  {
3736  currentValue = f.attribute( index );
3737  val.insert( currentValue.toString(), currentValue );
3738  if ( limit >= 0 && val.size() >= limit )
3739  {
3740  break;
3741  }
3742  }
3743 
3744  return val.values().toSet();
3745  }
3746  }
3747 
3748  Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
3749  return uniqueValues;
3750 }
3751 
3752 QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
3753 {
3754  QStringList results;
3755  if ( !mDataProvider )
3756  {
3757  return results;
3758  }
3759 
3760  QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
3761  switch ( origin )
3762  {
3764  return results;
3765 
3766  case QgsFields::OriginProvider: //a provider field
3767  {
3768  results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
3769 
3770  if ( mEditBuffer )
3771  {
3772  QgsFeatureMap added = mEditBuffer->addedFeatures();
3773  QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
3774  while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
3775  {
3776  addedIt.next();
3777  QVariant v = addedIt.value().attribute( index );
3778  if ( v.isValid() )
3779  {
3780  QString vs = v.toString();
3781  if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
3782  {
3783  results << vs;
3784  }
3785  }
3786  }
3787 
3788  QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
3789  while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
3790  {
3791  it.next();
3792  QVariant v = it.value().value( index );
3793  if ( v.isValid() )
3794  {
3795  QString vs = v.toString();
3796  if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
3797  {
3798  results << vs;
3799  }
3800  }
3801  }
3802  }
3803 
3804  return results;
3805  }
3806 
3807  case QgsFields::OriginEdit:
3808  // the layer is editable, but in certain cases it can still be avoided going through all features
3809  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
3810  mEditBuffer->mAddedFeatures.isEmpty() &&
3811  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
3812  mEditBuffer->mChangedAttributeValues.isEmpty() )
3813  {
3814  return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
3815  }
3816  FALLTHROUGH
3817  //we need to go through each feature
3818  case QgsFields::OriginJoin:
3820  {
3821  QgsAttributeList attList;
3822  attList << index;
3823 
3824  QgsFeatureRequest request;
3825  request.setSubsetOfAttributes( attList );
3827  QString fieldName = mFields.at( index ).name();
3828  request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
3829  QgsFeatureIterator fit = getFeatures( request );
3830 
3831  QgsFeature f;
3832  QString currentValue;
3833  while ( fit.nextFeature( f ) )
3834  {
3835  currentValue = f.attribute( index ).toString();
3836  if ( !results.contains( currentValue ) )
3837  results << currentValue;
3838 
3839  if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
3840  {
3841  break;
3842  }
3843  }
3844 
3845  return results;
3846  }
3847  }
3848 
3849  Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
3850  return results;
3851 }
3852 
3853 QVariant QgsVectorLayer::minimumValue( int index ) const
3854 {
3855  if ( !mDataProvider )
3856  {
3857  return QVariant();
3858  }
3859 
3860  QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
3861 
3862  switch ( origin )
3863  {
3865  return QVariant();
3866 
3867  case QgsFields::OriginProvider: //a provider field
3868  {
3869  QVariant min = mDataProvider->minimumValue( index );
3870  if ( mEditBuffer )
3871  {
3872  QgsFeatureMap added = mEditBuffer->addedFeatures();
3873  QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
3874  while ( addedIt.hasNext() )
3875  {
3876  addedIt.next();
3877  QVariant v = addedIt.value().attribute( index );
3878  if ( v.isValid() && qgsVariantLessThan( v, min ) )
3879  {
3880  min = v;
3881  }
3882  }
3883 
3884  QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
3885  while ( it.hasNext() )
3886  {
3887  it.next();
3888  QVariant v = it.value().value( index );
3889  if ( v.isValid() && qgsVariantLessThan( v, min ) )
3890  {
3891  min = v;
3892  }
3893  }
3894  }
3895  return min;
3896  }
3897 
3898  case QgsFields::OriginEdit:
3899  {
3900  // the layer is editable, but in certain cases it can still be avoided going through all features
3901  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
3902  mEditBuffer->mAddedFeatures.isEmpty() && !
3903  mEditBuffer->mDeletedAttributeIds.contains( index ) &&
3904  mEditBuffer->mChangedAttributeValues.isEmpty() )
3905  {
3906  return mDataProvider->minimumValue( index );
3907  }
3908  }
3909  FALLTHROUGH
3910  // no choice but to go through all features
3912  case QgsFields::OriginJoin:
3913  {
3914  // we need to go through each feature
3915  QgsAttributeList attList;
3916  attList << index;
3917 
3920  .setSubsetOfAttributes( attList ) );
3921 
3922  QgsFeature f;
3923  double minimumValue = std::numeric_limits<double>::max();
3924  double currentValue = 0;
3925  while ( fit.nextFeature( f ) )
3926  {
3927  currentValue = f.attribute( index ).toDouble();
3928  if ( currentValue < minimumValue )
3929  {
3930  minimumValue = currentValue;
3931  }
3932  }
3933  return QVariant( minimumValue );
3934  }
3935  }
3936 
3937  Q_ASSERT_X( false, "QgsVectorLayer::minimumValue()", "Unknown source of the field!" );
3938  return QVariant();
3939 }
3940 
3941 QVariant QgsVectorLayer::maximumValue( int index ) const
3942 {
3943  if ( !mDataProvider )
3944  {
3945  return QVariant();
3946  }
3947 
3948  QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
3949  switch ( origin )
3950  {
3952  return QVariant();
3953 
3954  case QgsFields::OriginProvider: //a provider field
3955  {
3956  QVariant min = mDataProvider->maximumValue( index );
3957  if ( mEditBuffer )
3958  {
3959  QgsFeatureMap added = mEditBuffer->addedFeatures();
3960  QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
3961  while ( addedIt.hasNext() )
3962  {
3963  addedIt.next();
3964  QVariant v = addedIt.value().attribute( index );
3965  if ( v.isValid() && qgsVariantGreaterThan( v, min ) )
3966  {
3967  min = v;
3968  }
3969  }
3970 
3971  QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
3972  while ( it.hasNext() )
3973  {
3974  it.next();
3975  QVariant v = it.value().value( index );
3976  if ( v.isValid() && qgsVariantGreaterThan( v, min ) )
3977  {
3978  min = v;
3979  }
3980  }
3981  }
3982  return min;
3983  }
3984 
3985  case QgsFields::OriginEdit:
3986  // the layer is editable, but in certain cases it can still be avoided going through all features
3987  if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
3988  mEditBuffer->mAddedFeatures.isEmpty() &&
3989  !mEditBuffer->mDeletedAttributeIds.contains( index ) &&
3990  mEditBuffer->mChangedAttributeValues.isEmpty() )
3991  {
3992  return mDataProvider->maximumValue( index );
3993  }
3994 
3995  FALLTHROUGH
3996  //no choice but to go through each feature
3997  case QgsFields::OriginJoin:
3999  {
4000  QgsAttributeList attList;
4001  attList << index;
4002 
4005  .setSubsetOfAttributes( attList ) );
4006 
4007  QgsFeature f;
4008  double maximumValue = -std::numeric_limits<double>::max();
4009  double currentValue = 0;
4010  while ( fit.nextFeature( f ) )
4011  {
4012  currentValue = f.attribute( index ).toDouble();
4013  if ( currentValue > maximumValue )
4014  {
4015  maximumValue = currentValue;
4016  }
4017  }
4018  return QVariant( maximumValue );
4019  }
4020  }
4021 
4022  Q_ASSERT_X( false, "QgsVectorLayer::maximumValue()", "Unknown source of the field!" );
4023  return QVariant();
4024 }
4025 
4026 QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression,
4028  bool *ok, QgsFeatureIds *fids ) const
4029 {
4030  if ( ok )
4031  *ok = false;
4032 
4033  if ( !mDataProvider )
4034  {
4035  return QVariant();
4036  }
4037 
4038  // test if we are calculating based on a field
4039  int attrIndex = mFields.lookupField( fieldOrExpression );
4040  if ( attrIndex >= 0 )
4041  {
4042  // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
4043  // to the provider itself
4044  QgsFields::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
4045  if ( origin == QgsFields::OriginProvider )
4046  {
4047  bool providerOk = false;
4048  QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
4049  if ( providerOk )
4050  {
4051  // provider handled calculation
4052  if ( ok )
4053  *ok = true;
4054  return val;
4055  }
4056  }
4057  }
4058 
4059  // fallback to using aggregate calculator to determine aggregate
4060  QgsAggregateCalculator c( this );
4061  if ( fids )
4062  c.setFidsFilter( *fids );
4063  c.setParameters( parameters );
4064  return c.calculate( aggregate, fieldOrExpression, context, ok );
4065 }
4066 
4068 {
4069  if ( mFeatureBlendMode == featureBlendMode )
4070  return;
4071 
4072  mFeatureBlendMode = featureBlendMode;
4073  emit featureBlendModeChanged( featureBlendMode );
4074  emit styleChanged();
4075 }
4076 
4077 QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
4078 {
4079  return mFeatureBlendMode;
4080 }
4081 
4083 {
4084  if ( qgsDoubleNear( mLayerOpacity, opacity ) )
4085  return;
4086  mLayerOpacity = opacity;
4087  emit opacityChanged( opacity );
4088  emit styleChanged();
4089 }
4090 
4091 double QgsVectorLayer::opacity() const
4092 {
4093  return mLayerOpacity;
4094 }
4095 
4096 
4097 
4098 void QgsVectorLayer::readSldLabeling( const QDomNode &node )
4099 {
4100  setLabeling( nullptr ); // start with no labeling
4101  setLabelsEnabled( false );
4102 
4103  QDomElement element = node.toElement();
4104  if ( element.isNull() )
4105  return;
4106 
4107  QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
4108  if ( userStyleElem.isNull() )
4109  {
4110  QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
4111  return;
4112  }
4113 
4114  QDomElement featureTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
4115  if ( featureTypeStyleElem.isNull() )
4116  {
4117  QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
4118  return;
4119  }
4120 
4121  // use last rule
4122  QDomElement ruleElem = featureTypeStyleElem.lastChildElement( QStringLiteral( "Rule" ) );
4123  if ( ruleElem.isNull() )
4124  {
4125  QgsDebugMsgLevel( QStringLiteral( "Info: Rule element not found." ), 4 );
4126  return;
4127  }
4128 
4129  // use last text symbolizer
4130  QDomElement textSymbolizerElem = ruleElem.lastChildElement( QStringLiteral( "TextSymbolizer" ) );
4131  if ( textSymbolizerElem.isNull() )
4132  {
4133  QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element not found." ), 4 );
4134  return;
4135  }
4136 
4137  QgsPalLayerSettings settings;
4138 
4139  // Label
4140  QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
4141  if ( !labelElem.isNull() )
4142  {
4143  QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
4144  if ( !propertyNameElem.isNull() )
4145  {
4146  // set labeling defaults
4147 
4148  // label attribute
4149  QString labelAttribute = propertyNameElem.text();
4150  settings.fieldName = labelAttribute;
4151  settings.isExpression = false;
4152 
4153  int fieldIndex = mFields.lookupField( labelAttribute );
4154  if ( fieldIndex == -1 )
4155  {
4156  // label attribute is not in columns, check if it is an expression
4157  QgsExpression exp( labelAttribute );
4158  if ( !exp.hasEvalError() )
4159  {
4160  settings.isExpression = true;
4161  }
4162  else
4163  {
4164  QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
4165  }
4166  }
4167  }
4168  else
4169  {
4170  QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
4171  return;
4172  }
4173  }
4174  else
4175  {
4176  QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
4177  return;
4178  }
4179 
4180  QString fontFamily = QStringLiteral( "Sans-Serif" );
4181  int fontPointSize = 10;
4182  int fontWeight = -1;
4183  bool fontItalic = false;
4184  bool fontUnderline = false;
4185 
4186  // Font
4187  QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
4188  if ( !fontElem.isNull() )
4189  {
4190  QString cssName;
4191  QString elemText;
4192  QDomElement cssElem = fontElem.firstChildElement( QStringLiteral( "CssParameter" ) );
4193  while ( !cssElem.isNull() )
4194  {
4195  cssName = cssElem.attribute( QStringLiteral( "name" ), QStringLiteral( "not_found" ) );
4196  if ( cssName != QLatin1String( "not_found" ) )
4197  {
4198  elemText = cssElem.text();
4199  if ( cssName == QLatin1String( "font-family" ) )
4200  {
4201  fontFamily = elemText;
4202  }
4203  else if ( cssName == QLatin1String( "font-style" ) )
4204  {
4205  fontItalic = ( elemText == QLatin1String( "italic" ) ) || ( elemText == QLatin1String( "Italic" ) );
4206  }
4207  else if ( cssName == QLatin1String( "font-size" ) )
4208  {
4209  bool ok;
4210  int fontSize = elemText.toInt( &ok );
4211  if ( ok )
4212  {
4213  fontPointSize = fontSize;
4214  }
4215  }
4216  else if ( cssName == QLatin1String( "font-weight" ) )
4217  {
4218  if ( ( elemText == QLatin1String( "bold" ) ) || ( elemText == QLatin1String( "Bold" ) ) )
4219  fontWeight = QFont::Bold;
4220  }
4221  else if ( cssName == QLatin1String( "font-underline" ) )
4222  {
4223  fontUnderline = ( elemText == QLatin1String( "underline" ) ) || ( elemText == QLatin1String( "Underline" ) );
4224  }
4225  }
4226 
4227  cssElem = cssElem.nextSiblingElement( QStringLiteral( "CssParameter" ) );
4228  }
4229  }
4230 
4231  QgsTextFormat format;
4232  QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
4233  font.setUnderline( fontUnderline );
4234  format.setFont( font );
4235  format.setSize( fontPointSize );
4236 
4237  // Fill
4238  QColor textColor = QgsOgcUtils::colorFromOgcFill( textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) ) );
4239  if ( textColor.isValid() )
4240  {
4241  format.setColor( textColor );
4242  }
4243 
4244  QgsTextBufferSettings bufferSettings;
4245 
4246  // Halo
4247  QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
4248  if ( !haloElem.isNull() )
4249  {
4250  bufferSettings.setEnabled( true );
4251  bufferSettings.setSize( 1 );
4252 
4253  QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
4254  if ( !radiusElem.isNull() )
4255  {
4256  bool ok;
4257  double bufferSize = radiusElem.text().toDouble( &ok );
4258  if ( ok )
4259  {
4260  bufferSettings.setSize( bufferSize );
4261  }
4262  }
4263 
4264  QColor bufferColor = QgsOgcUtils::colorFromOgcFill( haloElem.firstChildElement( QStringLiteral( "Fill" ) ) );
4265  if ( bufferColor.isValid() )
4266  {
4267  bufferSettings.setColor( bufferColor );
4268  }
4269  }
4270 
4271  // LabelPlacement
4272  QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
4273  if ( !labelPlacementElem.isNull() )
4274  {
4275  // PointPlacement
4276  QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
4277  if ( !pointPlacementElem.isNull() )
4278  {
4280 
4281  QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
4282  if ( !displacementElem.isNull() )
4283  {
4284  QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
4285  if ( !displacementXElem.isNull() )
4286  {
4287  bool ok;
4288  double xOffset = displacementXElem.text().toDouble( &ok );
4289  if ( ok )
4290  {
4291  settings.xOffset = xOffset;
4292  }
4293  }
4294  QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
4295  if ( !displacementYElem.isNull() )
4296  {
4297  bool ok;
4298  double yOffset = displacementYElem.text().toDouble( &ok );
4299  if ( ok )
4300  {
4301  settings.yOffset = yOffset;
4302  }
4303  }
4304  }
4305 
4306  QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
4307  if ( !rotationElem.isNull() )
4308  {
4309  bool ok;
4310  double rotation = rotationElem.text().toDouble( &ok );
4311  if ( ok )
4312  {
4313  settings.angleOffset = 360 - rotation;
4314  }
4315  }
4316  }
4317  }
4318 
4319  format.setBuffer( bufferSettings );
4320  settings.setFormat( format );
4321  setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
4322  setLabelsEnabled( true );
4323 }
4324 
4326 {
4327  return mEditFormConfig;
4328 }
4329 
4331 {
4332  if ( mEditFormConfig == editFormConfig )
4333  return;
4334 
4335  mEditFormConfig = editFormConfig;
4336  mEditFormConfig.onRelationsLoaded();
4337  emit editFormConfigChanged();
4338 }
4339 
4340 QString QgsVectorLayer::mapTipTemplate() const
4341 {
4342  return mMapTipTemplate;
4343 }
4344 
4345 void QgsVectorLayer::setMapTipTemplate( const QString &mapTip )
4346 {
4347  if ( mMapTipTemplate == mapTip )
4348  return;
4349 
4350  mMapTipTemplate = mapTip;
4351  emit mapTipTemplateChanged();
4352 }
4353 
4355 {
4356  QgsAttributeTableConfig config = mAttributeTableConfig;
4357 
4358  if ( config.isEmpty() )
4359  config.update( fields() );
4360 
4361  return config;
4362 }
4363 
4365 {
4366  if ( mAttributeTableConfig != attributeTableConfig )
4367  {
4368  mAttributeTableConfig = attributeTableConfig;
4369  emit configChanged();
4370  }
4371 }
4372 
4374 {
4376 }
4377 
4379 {
4381 }
4382 
4384 {
4385  if ( !mDiagramLayerSettings )
4386  mDiagramLayerSettings = new QgsDiagramLayerSettings();
4387  *mDiagramLayerSettings = s;
4388 }
4389 
4391 {
4392  QgsLayerMetadataFormatter htmlFormatter( metadata() );
4393  QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
4394 
4395  // Begin Provider section
4396  myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
4397  myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
4398 
4399  // name
4400  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
4401 
4402  // local path
4403  QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
4404  QString path;
4405  if ( uriComponents.contains( QStringLiteral( "path" ) ) )
4406  {
4407  path = uriComponents[QStringLiteral( "path" )].toString();
4408  if ( QFile::exists( path ) )
4409  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" );
4410  }
4411  if ( uriComponents.contains( QStringLiteral( "url" ) ) )
4412  {
4413  const QString url = uriComponents[QStringLiteral( "url" )].toString();
4414  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" );
4415  }
4416 
4417  // data source
4418  if ( publicSource() != path )
4419  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() ) + QStringLiteral( "</td></tr>\n" );
4420 
4421  // storage type
4422  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Storage" ) + QStringLiteral( "</td><td>" ) + storageType() + QStringLiteral( "</td></tr>\n" );
4423 
4424  // comment
4425  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Comment" ) + QStringLiteral( "</td><td>" ) + dataComment() + QStringLiteral( "</td></tr>\n" );
4426 
4427  // encoding
4428  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Encoding" ) + QStringLiteral( "</td><td>" ) + dataProvider()->encoding() + QStringLiteral( "</td></tr>\n" );
4429 
4430  if ( isSpatial() )
4431  {
4432  // geom type
4434  if ( type < 0 || type > QgsWkbTypes::NullGeometry )
4435  {
4436  QgsDebugMsgLevel( QStringLiteral( "Invalid vector type" ), 2 );
4437  }
4438  else
4439  {
4440  QString typeString( QStringLiteral( "%1 (%2)" ).arg( QgsWkbTypes::geometryDisplayString( geometryType() ),
4442  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Geometry" ) + QStringLiteral( "</td><td>" ) + typeString + QStringLiteral( "</td></tr>\n" );
4443  }
4444 
4445  // EPSG
4446  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
4447  if ( crs().isValid() )
4448  {
4449  myMetadata += crs().authid() + QStringLiteral( " - " );
4450  myMetadata += crs().description() + QStringLiteral( " - " );
4451  if ( crs().isGeographic() )
4452  myMetadata += tr( "Geographic" );
4453  else
4454  myMetadata += tr( "Projected" );
4455  }
4456  myMetadata += QLatin1String( "</td></tr>\n" );
4457 
4458  // Extent
4459  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
4460 
4461  // unit
4462  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
4463 
4464  }
4465 
4466  // feature count
4467  QLocale locale = QLocale();
4468  locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
4469  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
4470  + tr( "Feature count" ) + QStringLiteral( "</td><td>" )
4471  + ( featureCount() == -1 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( featureCount() ) ) )
4472  + QStringLiteral( "</td></tr>\n" );
4473 
4474  // End Provider section
4475  myMetadata += QLatin1String( "</table>\n<br><br>" );
4476 
4477  // identification section
4478  myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
4479  myMetadata += htmlFormatter.identificationSectionHtml( );
4480  myMetadata += QLatin1String( "<br><br>\n" );
4481 
4482  // extent section
4483  myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
4484  myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
4485  myMetadata += QLatin1String( "<br><br>\n" );
4486 
4487  // Start the Access section
4488  myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
4489  myMetadata += htmlFormatter.accessSectionHtml( );
4490  myMetadata += QLatin1String( "<br><br>\n" );
4491 
4492  // Fields section
4493  myMetadata += QStringLiteral( "<h1>" ) + tr( "Fields" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
4494 
4495  // primary key
4496  QgsAttributeList pkAttrList = primaryKeyAttributes();
4497  if ( !pkAttrList.isEmpty() )
4498  {
4499  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Primary key attributes" ) + QStringLiteral( "</td><td>" );
4500  const auto constPkAttrList = pkAttrList;
4501  for ( int idx : constPkAttrList )
4502  {
4503  myMetadata += fields().at( idx ).name() + ' ';
4504  }
4505  myMetadata += QLatin1String( "</td></tr>\n" );
4506  }
4507 
4508  const QgsFields myFields = fields();
4509 
4510  // count fields
4511  myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( myFields.size() ) + QStringLiteral( "</td></tr>\n" );
4512 
4513  myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
4514  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" );
4515 
4516  for ( int i = 0; i < myFields.size(); ++i )
4517  {
4518  QgsField myField = myFields.at( i );
4519  QString rowClass;
4520  if ( i % 2 )
4521  rowClass = QStringLiteral( "class=\"odd-row\"" );
4522  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" );
4523  }
4524 
4525  //close field list
4526  myMetadata += QLatin1String( "</table>\n<br><br>" );
4527 
4528  // Start the contacts section
4529  myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
4530  myMetadata += htmlFormatter.contactsSectionHtml( );
4531  myMetadata += QLatin1String( "<br><br>\n" );
4532 
4533  // Start the links section
4534  myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
4535  myMetadata += htmlFormatter.linksSectionHtml( );
4536  myMetadata += QLatin1String( "<br><br>\n" );
4537 
4538  // Start the history section
4539  myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
4540  myMetadata += htmlFormatter.historySectionHtml( );
4541  myMetadata += QLatin1String( "<br><br>\n" );
4542 
4543  myMetadata += QStringLiteral( "\n</body>\n</html>\n" );
4544  return myMetadata;
4545 }
4546 
4547 void QgsVectorLayer::invalidateSymbolCountedFlag()
4548 {
4549  mSymbolFeatureCounted = false;
4550 }
4551 
4552 void QgsVectorLayer::onFeatureCounterCompleted()
4553 {
4554  onSymbolsCounted();
4555  mFeatureCounter = nullptr;
4556 }
4557 
4558 void QgsVectorLayer::onFeatureCounterTerminated()
4559 {
4560  mFeatureCounter = nullptr;
4561 }
4562 
4563 void QgsVectorLayer::onJoinedFieldsChanged()
4564 {
4565  // some of the fields of joined layers have changed -> we need to update this layer's fields too
4566  updateFields();
4567 }
4568 
4569 void QgsVectorLayer::onFeatureDeleted( QgsFeatureId fid )
4570 {
4571  if ( mEditCommandActive )
4572  mDeletedFids << fid;
4573  else
4574  emit featuresDeleted( QgsFeatureIds() << fid );
4575 
4576  emit featureDeleted( fid );
4577 }
4578 
4579 void QgsVectorLayer::onRelationsLoaded()
4580 {
4581  mEditFormConfig.onRelationsLoaded();
4582 }
4583 
4584 void QgsVectorLayer::onSymbolsCounted()
4585 {
4586  if ( mFeatureCounter )
4587  {
4588  mSymbolFeatureCounted = true;
4589  mSymbolFeatureCountMap = mFeatureCounter->symbolFeatureCountMap();
4590  mSymbolFeatureIdMap = mFeatureCounter->symbolFeatureIdMap();
4592  }
4593 }
4594 
4595 QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const
4596 {
4597  return QgsProject::instance()->relationManager()->referencingRelations( this, idx );
4598 }
4599 
4600 int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
4601 {
4602  return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
4603 }
4604 
4605 QString QgsVectorLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
4606 {
4607  return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
4608 }
4609 
4610 bool QgsVectorLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
4611 {
4612  return QgsProviderRegistry::instance()->deleteStyleById( mProviderKey, mDataSource, styleId, msgError );
4613 }
4614 
4615 
4616 void QgsVectorLayer::saveStyleToDatabase( const QString &name, const QString &description,
4617  bool useAsDefault, const QString &uiFileContent, QString &msgError )
4618 {
4619 
4620  QString sldStyle, qmlStyle;
4621  QDomDocument qmlDocument, sldDocument;
4622  QgsReadWriteContext context;
4623  exportNamedStyle( qmlDocument, msgError, context );
4624  if ( !msgError.isNull() )
4625  {
4626  return;
4627  }
4628  qmlStyle = qmlDocument.toString();
4629 
4630  this->exportSldStyle( sldDocument, msgError );
4631  if ( !msgError.isNull() )
4632  {
4633  return;
4634  }
4635  sldStyle = sldDocument.toString();
4636 
4638  mDataSource, qmlStyle, sldStyle, name,
4639  description, uiFileContent, useAsDefault, msgError );
4640 }
4641 
4642 
4643 
4644 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, QgsMapLayer::StyleCategories categories )
4645 {
4646  return loadNamedStyle( theURI, resultFlag, false, categories );
4647 }
4648 
4649 bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
4650 {
4651  bool rc = false;
4652 
4653  QString joinKey = mAuxiliaryLayerKey;
4654  if ( !key.isEmpty() )
4655  joinKey = key;
4656 
4657  if ( storage.isValid() && !joinKey.isEmpty() )
4658  {
4659  QgsAuxiliaryLayer *alayer = nullptr;
4660 
4661  int idx = fields().lookupField( joinKey );
4662 
4663  if ( idx >= 0 )
4664  {
4665  alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
4666 
4667  if ( alayer )
4668  {
4669  setAuxiliaryLayer( alayer );
4670  rc = true;
4671  }
4672  }
4673  }
4674 
4675  return rc;
4676 }
4677 
4679 {
4680  mAuxiliaryLayerKey.clear();
4681 
4682  if ( mAuxiliaryLayer )
4683  removeJoin( mAuxiliaryLayer->id() );
4684 
4685  if ( alayer )
4686  {
4687  addJoin( alayer->joinInfo() );
4688 
4689  if ( !alayer->isEditable() )
4690  alayer->startEditing();
4691 
4692  mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
4693  }
4694 
4695  mAuxiliaryLayer.reset( alayer );
4696  if ( mAuxiliaryLayer )
4697  mAuxiliaryLayer->setParent( this );
4698  updateFields();
4699 }
4700 
4702 {
4703  return mAuxiliaryLayer.get();
4704 }
4705 
4707 {
4708  return mAuxiliaryLayer.get();
4709 }
4710 
4711 QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories )
4712 {
4713  QgsDataSourceUri dsUri( theURI );
4714  if ( !loadFromLocalDB && mDataProvider && mDataProvider->isSaveAndLoadStyleToDatabaseSupported() )
4715  {
4716  QString qml, errorMsg;
4718  if ( !qml.isEmpty() )
4719  {
4720  QDomDocument myDocument( QStringLiteral( "qgis" ) );
4721  myDocument.setContent( qml );
4722  resultFlag = importNamedStyle( myDocument, errorMsg );
4723  return QObject::tr( "Loaded from Provider" );
4724  }
4725  }
4726  return QgsMapLayer::loadNamedStyle( theURI, resultFlag, categories );
4727 }
4728 
4729 QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
4730 {
4731  if ( mDataProvider )
4732  return mDataProvider->dependencies() + mDependencies;
4733  return mDependencies;
4734 }
4735 
4736 void QgsVectorLayer::emitDataChanged()
4737 {
4738  if ( mDataChangedFired )
4739  return;
4740 
4741  mDataChangedFired = true;
4742  emit dataChanged();
4743  mDataChangedFired = false;
4744 }
4745 
4746 bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
4747 {
4748  QSet<QgsMapLayerDependency> deps;
4749  const auto constODeps = oDeps;
4750  for ( const QgsMapLayerDependency &dep : constODeps )
4751  {
4752  if ( dep.origin() == QgsMapLayerDependency::FromUser )
4753  deps << dep;
4754  }
4755 
4756  QSet<QgsMapLayerDependency> toAdd = deps - dependencies();
4757 
4758  // disconnect layers that are not present in the list of dependencies anymore
4759  for ( const QgsMapLayerDependency &dep : qgis::as_const( mDependencies ) )
4760  {
4761  QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
4762  if ( !lyr )
4763  continue;
4764  disconnect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
4765  disconnect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
4766  disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
4767  disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
4769  }
4770 
4771  // assign new dependencies
4772  if ( mDataProvider )
4773  mDependencies = mDataProvider->dependencies() + deps;
4774  else
4775  mDependencies = deps;
4776  emit dependenciesChanged();
4777 
4778  // connect to new layers
4779  for ( const QgsMapLayerDependency &dep : qgis::as_const( mDependencies ) )
4780  {
4781  QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
4782  if ( !lyr )
4783  continue;
4784  connect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
4785  connect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
4786  connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
4787  connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
4789  }
4790 
4791  // if new layers are present, emit a data change
4792  if ( ! toAdd.isEmpty() )
4793  emitDataChanged();
4794 
4795  return true;
4796 }
4797 
4798 QgsFieldConstraints::Constraints QgsVectorLayer::fieldConstraints( int fieldIndex ) const
4799 {
4800  if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
4801  return nullptr;
4802 
4803  QgsFieldConstraints::Constraints constraints = mFields.at( fieldIndex ).constraints().constraints();
4804 
4805  // make sure provider constraints are always present!
4806  if ( mFields.fieldOrigin( fieldIndex ) == QgsFields::OriginProvider )
4807  {
4808  constraints |= mDataProvider->fieldConstraints( mFields.fieldOriginIndex( fieldIndex ) );
4809  }
4810 
4811  return constraints;
4812 }
4813 
4814 QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> QgsVectorLayer::fieldConstraintsAndStrength( int fieldIndex ) const
4815 {
4816  QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > m;
4817 
4818  if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
4819  return m;
4820 
4821  QString name = mFields.at( fieldIndex ).name();
4822 
4823  QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator conIt = mFieldConstraintStrength.constBegin();
4824  for ( ; conIt != mFieldConstraintStrength.constEnd(); ++conIt )
4825  {
4826  if ( conIt.key().first == name )
4827  {
4828  m[ conIt.key().second ] = mFieldConstraintStrength.value( conIt.key() );
4829  }
4830  }
4831 
4832  return m;
4833 }
4834 
4836 {
4837  if ( index < 0 || index >= mFields.count() )
4838  return;
4839 
4840  QString name = mFields.at( index ).name();
4841 
4842  // add constraint to existing constraints
4843  QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, nullptr );
4844  constraints |= constraint;
4845  mFieldConstraints.insert( name, constraints );
4846 
4847  mFieldConstraintStrength.insert( qMakePair( name, constraint ), strength );
4848 
4849  updateFields();
4850 }
4851 
4853 {
4854  if ( index < 0 || index >= mFields.count() )
4855  return;
4856 
4857  QString name = mFields.at( index ).name();
4858 
4859  // remove constraint from existing constraints
4860  QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, nullptr );
4861  constraints &= ~constraint;
4862  mFieldConstraints.insert( name, constraints );
4863 
4864  mFieldConstraintStrength.remove( qMakePair( name, constraint ) );
4865 
4866  updateFields();
4867 }
4868 
4869 QString QgsVectorLayer::constraintExpression( int index ) const
4870 {
4871  if ( index < 0 || index >= mFields.count() )
4872  return QString();
4873 
4874  return mFields.at( index ).constraints().constraintExpression();
4875 }
4876 
4877 QString QgsVectorLayer::constraintDescription( int index ) const
4878 {
4879  if ( index < 0 || index >= mFields.count() )
4880  return QString();
4881 
4882  return mFields.at( index ).constraints().constraintDescription();
4883 }
4884 
4885 void QgsVectorLayer::setConstraintExpression( int index, const QString &expression, const QString &description )
4886 {
4887  if ( index < 0 || index >= mFields.count() )
4888  return;
4889 
4890  if ( expression.isEmpty() )
4891  {
4892  mFieldConstraintExpressions.remove( mFields.at( index ).name() );
4893  }
4894  else
4895  {
4896  mFieldConstraintExpressions.insert( mFields.at( index ).name(), qMakePair( expression, description ) );
4897  }
4898  updateFields();
4899 }
4900 
4902 {
4903  if ( index < 0 || index >= mFields.count() )
4904  return;
4905 
4906  if ( setup.isNull() )
4907  mFieldWidgetSetups.remove( mFields.at( index ).name() );
4908  else
4909  mFieldWidgetSetups.insert( mFields.at( index ).name(), setup );
4910  updateFields();
4911 }
4912 
4914 {
4915 
4916  if ( index < 0 || index >= mFields.count() )
4917  return QgsEditorWidgetSetup();
4918 
4919  return mFields.at( index ).editorWidgetSetup();
4920 }
4921 
4922 QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties()
4923 {
4925  if ( customProperty( QStringLiteral( "labeling" ) ).toString() == QLatin1String( "pal" ) )
4926  {
4927  if ( customProperty( QStringLiteral( "labeling/enabled" ), QVariant( false ) ).toBool() )
4928  {
4929  // try to load from custom properties
4930  QgsPalLayerSettings settings;
4931  settings.readFromLayerCustomProperties( this );
4932  labeling = new QgsVectorLayerSimpleLabeling( settings );
4933  }
4934 
4935  // also clear old-style labeling config
4936  removeCustomProperty( QStringLiteral( "labeling" ) );
4937  const auto constCustomPropertyKeys = customPropertyKeys();
4938  for ( const QString &key : constCustomPropertyKeys )
4939  {
4940  if ( key.startsWith( QLatin1String( "labeling/" ) ) )
4941  removeCustomProperty( key );
4942  }
4943  }
4944 
4945  return labeling;
4946 }
4947 
4949 {
4950  return mAllowCommit;
4951 }
4952 
4954 {
4955  if ( mAllowCommit == allowCommit )
4956  return;
4957 
4958  mAllowCommit = allowCommit;
4959  emit allowCommitChanged();
4960 }
4961 
4963 {
4964  return mGeometryOptions.get();
4965 }
4966 
4968 {
4969  mReadExtentFromXml = readExtentFromXml;
4970 }
4971 
4973 {
4974  return mReadExtentFromXml;
4975 }
4976 
4977 void QgsVectorLayer::onDirtyTransaction( const QString &sql, const QString &name )
4978 {
4980  if ( tr && mEditBuffer )
4981  {
4982  qobject_cast<QgsVectorLayerEditPassthrough *>( mEditBuffer )->update( tr, sql, name );
4983  }
4984 }
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:324
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const FINAL
Writes vector layer specific state to project file Dom node.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features in joined layers.
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:183
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...
void opacityChanged(double opacity)
Emitted when the layer&#39;s opacity is changed, where opacity is a value between 0 (transparent) and 1 (...
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
double xOffset
Horizontal offset of label.
QString encoding() const
Gets 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
Writes just the style information for the layer into the document.
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.
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.
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:79
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.
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.
QgsVectorLayerFeatureCounter * countSymbolFeatures()
Count features for symbols.
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:50
bool readSymbology(const QDomNode &layerNode, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
Reads the symbology for the current layer from the Dom node supplied.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
void setExcludeAttributesWms(const QSet< QString > &att)
A set of attributes that are not advertised in WMS requests with QGIS server.
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
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
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:151
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.
QgsWkbTypes::Type wkbType() const override=0
Returns the geometry type which is returned by this layer.
QString contactsSectionHtml() const
Formats the "Contacts" section according to a metadata object.
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.
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.
void editFormConfigChanged()
Will be emitted whenever the edit form configuration of this layer changes.
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.
virtual void updateExtents()
Update the extents of the layer.
QString name
Definition: qgsfield.h:58
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:55
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.
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
Write field ui properties specific state from Dom node.
void beforeRollBack()
Emitted before changes are rolled back.
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.
QSet< QString > excludeAttributesWms() const
A set of attributes that are not advertised in WMS requests with QGIS server.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
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...
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.
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
QString alias
Definition: qgsfield.h:59
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...
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:301
Constraint
Constraints which may be present on a field.
QSet< QString > excludeAttributesWfs() const
A set of attributes that are not advertised in WFS requests with QGIS server.
virtual bool addFeature(QgsFeature &f)
Adds a feature.
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
Definition: qgsfields.h:51
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.
bool deleteFeature(QgsFeatureId fid)
Deletes a feature from the layer (but does not commit it).
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:436
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:571
virtual void readXml(const QDomElement &elem, const QgsReadWriteContext &context)=0
Reads diagram state from a DOM element.
QString mProviderKey
Data provider key (name of the data provider)
Definition: qgsmaplayer.h:1521
QString accessSectionHtml() const
Formats the "Access" section according to a metadata object.
bool deleteStyleById_t(const QString &uri, QString styleID, QString &errCause)
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:121
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).
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:265
void invertSelectionInRectangle(QgsRectangle &rect)
Inverts selection of features found within the search rectangle (in layer&#39;s coordinates) ...
void subsetStringChanged()
Emitted when the layer&#39;s subset string has changed.
QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
bool commitChanges()
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
virtual QSet< QgsMapLayerDependency > dependencies() const
Gets the list of layer ids on which this layer depends.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
QString linksSectionHtml() const
Formats the "Links" section according to a metadata object.
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context)
store renderer info to XML element
EditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
virtual void setEncoding(const QString &e)
Set encoding used for accessing data from layer.
bool startEditing()
Makes the layer editable.
void setSimplifyHints(SimplifyHints simplifyHints)
Sets the simplification hints of the vector layer managed.
void setFont(const QFont &font)
Sets the font used for rendering text.
QgsVectorLayer(const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib="ogr", const QgsVectorLayer::LayerOptions &options=QgsVectorLayer::LayerOptions())
Constructor - creates a vector layer.
bool deleteAttributes(const QList< int > &attrs)
Deletes a list of attribute fields (but does not commit it)
VertexMarkerType
Editing vertex markers.
void removeExpressionField(int index)
Removes an expression field.
void setFeatureBlendMode(QPainter::CompositionMode blendMode)
Sets the blending mode used for rendering each feature.
QVariant evaluate()
Evaluate the feature and return the result.
void readCustomProperties(const QDomNode &layerNode, const QString &keyStartsWith=QString())
Read custom properties from project file.
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
virtual QgsAttributeList pkAttributeIndexes() const
Returns list of indexes of fields that make up the primary key.
Remove from current selection.
void writeXml(QDomElement &layerElem, QDomDocument &doc) const
Writes the diagram settings to a DOM element.
QString comment
Definition: qgsfield.h:57
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects...
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
~QgsVectorLayer() override
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) const FINAL
Writes the symbology for the layer into the document provided.
Class providing some utility methods to manage auxiliary storage.
SimplifyHint
Simplification flags for fast rendering of features.
Utility class for calculating aggregates for a field (or expression) over the features from a vector ...
double yOffset
Vertical offset of label.
void setLabeling(QgsAbstractVectorLayerLabeling *labeling)
Sets labeling configuration.
Provider can create feature renderers using backend-specific formatting information. Since QGIS 3.2. See QgsVectorDataProvider::createRenderer().
void readCustomSymbology(const QDomElement &element, QString &errorMessage)
Signal emitted whenever the symbology (QML-file) for this layer is being read.
QString evalErrorString() const
Returns evaluation error.
Aliases, widgets, WMS/WFS, expressions, constraints, virtual fields.
Definition: qgsmaplayer.h:155
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool deleteFeatures(const QgsFeatureIds &fids)
Deletes a set of features from the layer (but does not commit it)
virtual const QgsLayerMetadata & metadata() const
Returns a reference to the layer&#39;s metadata store.
void readXml(const QDomNode &layer_node)
Reads joins from project file.
void raiseError(const QString &msg) const
Signals an error in this provider.
void configChanged()
Emitted whenever the configuration is changed.
void setDiagramRenderer(QgsDiagramRenderer *r)
Sets diagram rendering object (takes ownership)
Container of fields for a vector layer.
Definition: qgsfields.h:42
virtual void rollBack()
Stop editing and discard the edits.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:121
void selectByIds(const QgsFeatureIds &ids, SelectBehavior behavior=SetSelection)
Selects matching features using a list of feature IDs.
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
virtual QgsFeatureRenderer * createRenderer(const QVariantMap &configuration=QVariantMap()) const
Creates a new vector layer feature renderer, using provider backend specific information.
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:50
void beforeRemovingExpressionField(int idx)
Will be emitted, when an expression field is going to be deleted from this vector layer...
long featureCount() const FINAL
Returns feature count including changes which have not yet been committed If you need only the count ...
QString decodedSource(const QString &source, const QString &provider, const QgsReadWriteContext &context) const FINAL
Called by readLayerXML(), used by derived classes to decode provider&#39;s specific data source from proj...
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not committed.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
Allows entering a context category and takes care of leaving this category on deletion of the class...
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:438
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > fieldConstraintsAndStrength(int fieldIndex) const
Returns a map of constraint with their strength for a specific field of the layer.
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the scope.
QString getStyleById(const QString &providerKey, const QString &uri, QString styleId, QString &errCause)
Gets a layer style defined by styleId.
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
Stores information about constraints which may be present on a field.
Field comes from the underlying data provider of the vector layer (originIndex = index in provider&#39;s ...
Definition: qgsfields.h:49
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
bool isAuxiliaryField(int index, int &srcIndex) const
Returns true if the field comes from the auxiliary layer, false otherwise.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
static const int EditingCapabilities
Bitmask of all provider&#39;s editing capabilities.
void resolveReferences(QgsProject *project) FINAL
Resolves references to other layers (kept as layer IDs after reading XML) into layer objects...
bool isValid() const
Returns the status of the layer.
An interface for classes which can visit style entity (e.g.
QgsFields fields
Definition: qgsfeature.h:66
QgsChangedAttributesMap changedAttributeValues() const
Returns a map of features with changed attributes values which are not committed. ...
void beforeCommitChanges()
Emitted before changes are committed to the data provider.
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition: qgis.cpp:222
QgsFeatureList selectedFeatures() const
Returns a copy of the user-selected features.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
Emitted when features are deleted from the provider.
QUuid addAction(QgsAction::ActionType type, const QString &name, const QString &command, bool capture=false)
Add an action with the given name and action details.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Emitted when attributes are deleted from the provider.
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
void setConnection(const QString &aHost, const QString &aPort, const QString &aDatabase, const QString &aUsername, const QString &aPassword, SslMode sslmode=SslPrefer, const QString &authConfigId=QString())
Sets all connection related members at once.
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Inserts a new vertex before the given vertex number, in the given ring, item (first number is index 0...
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:597
void editCommandEnded()
Signal emitted, when an edit command successfully ended.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
OperationResult
Success or failure of a geometry operation.
Definition: qgsgeometry.h:133
QString username() const
Returns the username stored in the URI.
QgsFieldConstraints::Constraints fieldConstraints(int fieldIndex) const
Returns any constraints which are present for a specified field index.
QgsFeatureIds deletedFeatureIds() const
Returns a list of deleted feature IDs which are not committed.
void invertSelection()
Selects not selected features and deselects selected ones.
void setParameters(const AggregateParameters &parameters)
Sets all aggregate parameters from a parameter bundle.
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition: qgis.cpp:154
Attribute table settings: choice and order of columns, conditional styling.
Definition: qgsmaplayer.h:160
It has not been specified where the field comes from.
Definition: qgsfields.h:48
void deselect(QgsFeatureId featureId)
Deselects feature by its ID.
Constraint was set at data provider.
void styleChanged()
Signal emitted whenever a change affects the layer&#39;s style.
Field has an expression constraint set. See constraintExpression().
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
bool writeXml(QDomNode &layerNode) const
Writes the stored expressions out in XML format.
virtual QgsRectangle extent() const
Returns the extent of the layer.
void setMapTipTemplate(const QString &mapTipTemplate)
The mapTip is a pretty, html representation for feature information.
void writeCustomProperties(QDomNode &layerNode, QDomDocument &doc) const
Write custom properties to project file.
void removeSelection()
Clear selection.
QString attributeAlias(int index) const
Returns the alias of an attribute name or a null string if there is no alias.
Manages joined fields for a vector layer.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
virtual QgsLayerMetadata layerMetadata() const
Returns layer metadata collected from the provider&#39;s source.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
void setAuxiliaryLayer(QgsAuxiliaryLayer *layer=nullptr)
Sets the current auxiliary layer.
QgsDataProvider * createProvider(const QString &providerKey, const QString &dataSource, const QgsDataProvider::ProviderOptions &options=QgsDataProvider::ProviderOptions())
Creates a new instance of a provider.
int length
Definition: qgsfield.h:54
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
bool updateFeature(QgsFeature &feature, bool skipDefaultValues=false)
Updates an existing feature in the layer, replacing the attributes and geometry for the feature with ...
static QgsTaskManager * taskManager()
Returns the application&#39;s task manager, used for managing application wide background task handling...
void dataChanged()
Emitted whenever a change is made to the data provider which may have caused changes in the provider&#39;...
Base class for feedback objects to be used for cancellation of something running in a worker thread...
Definition: qgsfeedback.h:44
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
void featureAdded(QgsFeatureId fid)
virtual int listStylesInDatabase(QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError)
Lists all the style in db split into related to the layer and not related to.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsRectangle mExtent
Extent of the layer.
Definition: qgsmaplayer.h:1469
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
void setExcludeAttributesWfs(const QSet< QString > &att)
A set of attributes that are not advertised in WFS requests with QGIS server.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changes attribute value in joined layers.
Q_DECL_DEPRECATED void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Update the data source of the layer.
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
QString host() const
Returns the host name stored in the URI.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,0,0,0) is returned.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
float maximumScale() const
Gets the maximum scale at which the layer should be simplified.
virtual void updateExtents(bool force=false)
Update the extents for the layer.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
bool readXml(const QDomNode &layer_node)
Reads the actions in in XML format.
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
void setSize(double size)
Sets the size for rendered text.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue)
Returns the value corresponding to the given key of an enum.
Definition: qgis.h:448
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
QgsGeometry getGeometry(QgsFeatureId fid) const
Queries the layer for the geometry at the given id.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
#define FALLTHROUGH
Definition: qgis.h:666
QgsCoordinateTransformContext transformContext() const
Returns data provider coordinate transform context.
void writeCommonStyle(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) const
Write style data common to all layer types.
const QgsFeatureIds & selectedFeatureIds() const
Returns a list of the selected features IDs in this layer.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature&#39;s geometry within the layer&#39;s edit buffer (but does not immediately commit the chan...
void readStyleManager(const QDomNode &layerNode)
Read style manager&#39;s configuration (if any). To be called by subclasses.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted...
bool rollBack(bool deleteBuffer=true)
Stops a current editing operation and discards any uncommitted edits.
bool readStyle(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories) FINAL
Reads the style for the current layer from the Dom node supplied.
void attributeAdded(int idx)
bool equals(const QgsGeometry &geometry) const
Test if this geometry is exactly equal to another geometry.
bool deleteFeature(QgsFeatureId fid) const
Deletes a feature from joined layers.
void select(QgsFeatureId featureId)
Selects feature by its ID.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
bool allowCommit() const
Controls, if the layer is allowed to commit changes.
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:105
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:161
void featureBlendModeChanged(QPainter::CompositionMode blendMode)
Signal emitted when setFeatureBlendMode() is called.
QString displayName() const
Returns the name to use when displaying this field.
Definition: qgsfield.cpp:87
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer&#39;s metadata store.
static QgsFeatureRenderer * load(QDomElement &symbologyElem, const QgsReadWriteContext &context)
create a renderer from XML element
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap())
Changes attributes&#39; values in joined layers.
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer&#39;s spatial reference system.
QSet< QgsMapLayerDependency > mDependencies
List of layers that may modify this layer on modification.
Definition: qgsmaplayer.h:1508
void beforeModifiedCheck() const
Emitted when the layer is checked for modifications. Use for last-minute additions.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
void reload() FINAL
Synchronises with changes in the datasource.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
virtual bool isValid() const =0
Returns true if this is a valid layer.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
QString dataComment() const
Returns a description for this layer as defined in the data provider.
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer&#39;s relations, where the foreign key is on this layer.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
static QString geometryDisplayString(GeometryType type)
Returns a display string for a geometry type.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
bool deleteFeatures(const QgsFeatureIds &fids) const
Deletes a list of features from joined layers.
void afterRollBack()
Emitted after changes are rolled back.
virtual void setExtent(const QgsRectangle &rect)
Sets the extent.
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:35
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
double opacity() const
Returns the opacity for the vector layer, where opacity is a value between 0 (totally transparent) an...
Geometry validation configuration.
Definition: qgsmaplayer.h:163
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
Emitted when features are added to the provider.
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) FINAL
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context...
void readXml(const QDomElement &elem)
Reads the diagram settings from a DOM element.
int listStyles(const QString &providerKey, const QString &uri, QStringList &ids, QStringList &names, QStringList &descriptions, QString &errCause)
Lists stored layer styles in the provider defined by providerKey and uri.
bool setDependencies(const QSet< QgsMapLayerDependency > &layers) FINAL
Sets the list of dependencies.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
bool writeSld(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsStringMap &props=QgsStringMap()) const
Writes the symbology of the layer into the document provided in SLD 1.1 format.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
QgsGeometry::OperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the labeling...
Defines left outer join from our vector layer to some other vector layer.
QgsGeometry::OperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
virtual bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it).
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void beforeEditingStarted()
Emitted before editing on this layer is started.
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:812
QgsGeometryMap mChangedGeometries
Changed geometries which are not committed.
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0)...
Don&#39;t resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:531
void setColor(const QColor &color)
Sets the color that text will be rendered in.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QgsAttributeList primaryKeyAttributes() const
Returns the list of attributes which make up the layer&#39;s primary keys.
void setLabelsEnabled(bool enabled)
Sets whether labels should be enabled for the layer.
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves expressions to xml under the layer node.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
virtual bool changeGeometry(QgsFeatureId fid, const QgsGeometry &geom)
Change feature&#39;s geometry.
The QgsMapLayerLegend class is abstract interface for implementations of legends for one map layer...
virtual QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const =0
Returns labeling configuration as XML element.
void setFieldAlias(int index, const QString &aliasString)
Sets an alias (a display name) for attributes to display in dialogs.