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