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