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