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