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 && mDataProvider && !mDataProvider->hasMetadata() && 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<const QgsPointXY>::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 : 0 : QgsGeometry::OperationResult QgsVectorLayer::addPart( const QVector<QgsPointXY> &points )
1290 : : {
1291 : 0 : return addPart( vectorPointXY2pointSequence( points ) );
1292 : 0 : }
1293 : :
1294 : 0 : QgsGeometry::OperationResult QgsVectorLayer::addPart( const QgsPointSequence &points )
1295 : : {
1296 : 0 : if ( !isValid() || !mEditBuffer || !mDataProvider )
1297 : 0 : return QgsGeometry::OperationResult::LayerNotEditable;
1298 : :
1299 : : //number of selected features must be 1
1300 : :
1301 : 0 : if ( mSelectedFeatureIds.empty() )
1302 : : {
1303 : 0 : QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1304 : 0 : return QgsGeometry::OperationResult::SelectionIsEmpty;
1305 : : }
1306 : 0 : else if ( mSelectedFeatureIds.size() > 1 )
1307 : : {
1308 : 0 : QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1309 : 0 : return QgsGeometry::OperationResult::SelectionIsGreaterThanOne;
1310 : : }
1311 : :
1312 : 0 : QgsVectorLayerEditUtils utils( this );
1313 : 0 : QgsGeometry::OperationResult result = utils.addPart( points, *mSelectedFeatureIds.constBegin() );
1314 : :
1315 : 0 : if ( result == QgsGeometry::OperationResult::Success )
1316 : 0 : updateExtents();
1317 : 0 : return result;
1318 : 0 : }
1319 : :
1320 : 0 : QgsGeometry::OperationResult QgsVectorLayer::addPart( QgsCurve *ring )
1321 : : {
1322 : 0 : if ( !isValid() || !mEditBuffer || !mDataProvider )
1323 : 0 : return QgsGeometry::OperationResult::LayerNotEditable;
1324 : :
1325 : : //number of selected features must be 1
1326 : :
1327 : 0 : if ( mSelectedFeatureIds.empty() )
1328 : : {
1329 : 0 : QgsDebugMsgLevel( QStringLiteral( "Number of selected features <1" ), 3 );
1330 : 0 : return QgsGeometry::OperationResult::SelectionIsEmpty;
1331 : : }
1332 : 0 : else if ( mSelectedFeatureIds.size() > 1 )
1333 : : {
1334 : 0 : QgsDebugMsgLevel( QStringLiteral( "Number of selected features >1" ), 3 );
1335 : 0 : return QgsGeometry::OperationResult::SelectionIsGreaterThanOne;
1336 : : }
1337 : :
1338 : 0 : QgsVectorLayerEditUtils utils( this );
1339 : 0 : QgsGeometry::OperationResult result = utils.addPart( ring, *mSelectedFeatureIds.constBegin() );
1340 : :
1341 : 0 : if ( result == QgsGeometry::OperationResult::Success )
1342 : 0 : updateExtents();
1343 : 0 : return result;
1344 : 0 : }
1345 : :
1346 : 0 : int QgsVectorLayer::translateFeature( QgsFeatureId featureId, double dx, double dy )
1347 : : {
1348 : 0 : if ( !isValid() || !mEditBuffer || !mDataProvider )
1349 : 0 : return QgsGeometry::OperationResult::LayerNotEditable;
1350 : :
1351 : 0 : QgsVectorLayerEditUtils utils( this );
1352 : 0 : int result = utils.translateFeature( featureId, dx, dy );
1353 : :
1354 : 0 : if ( result == QgsGeometry::OperationResult::Success )
1355 : 0 : updateExtents();
1356 : 0 : return result;
1357 : 0 : }
1358 : :
1359 : 0 : QgsGeometry::OperationResult QgsVectorLayer::splitParts( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1360 : : {
1361 : 0 : return splitParts( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1362 : 0 : }
1363 : 0 : QgsGeometry::OperationResult QgsVectorLayer::splitParts( const QgsPointSequence &splitLine, bool topologicalEditing )
1364 : : {
1365 : 0 : if ( !isValid() || !mEditBuffer || !mDataProvider )
1366 : 0 : return QgsGeometry::OperationResult::LayerNotEditable;
1367 : :
1368 : 0 : QgsVectorLayerEditUtils utils( this );
1369 : 0 : return utils.splitParts( splitLine, topologicalEditing );
1370 : 0 : }
1371 : 0 : QgsGeometry::OperationResult QgsVectorLayer::splitFeatures( const QVector<QgsPointXY> &splitLine, bool topologicalEditing )
1372 : : {
1373 : 0 : return splitFeatures( vectorPointXY2pointSequence( splitLine ), topologicalEditing );
1374 : 0 : }
1375 : :
1376 : 0 : QgsGeometry::OperationResult QgsVectorLayer::splitFeatures( const QgsPointSequence &splitLine, bool topologicalEditing )
1377 : : {
1378 : 0 : QgsLineString splitLineString( splitLine );
1379 : 0 : QgsPointSequence topologyTestPoints;
1380 : 0 : bool preserveCircular = false;
1381 : 0 : return splitFeatures( &splitLineString, topologyTestPoints, preserveCircular, topologicalEditing );
1382 : 0 : }
1383 : :
1384 : 0 : QgsGeometry::OperationResult QgsVectorLayer::splitFeatures( const QgsCurve *curve, QgsPointSequence &topologyTestPoints, bool preserveCircular, bool topologicalEditing )
1385 : : {
1386 : 0 : if ( !isValid() || !mEditBuffer || !mDataProvider )
1387 : 0 : return QgsGeometry::OperationResult::LayerNotEditable;
1388 : :
1389 : 0 : QgsVectorLayerEditUtils utils( this );
1390 : 0 : return utils.splitFeatures( curve, topologyTestPoints, preserveCircular, topologicalEditing );
1391 : 0 : }
1392 : :
1393 : 0 : int QgsVectorLayer::addTopologicalPoints( const QgsGeometry &geom )
1394 : : {
1395 : 0 : if ( !isValid() || !mEditBuffer || !mDataProvider )
1396 : 0 : return -1;
1397 : :
1398 : 0 : QgsVectorLayerEditUtils utils( this );
1399 : 0 : return utils.addTopologicalPoints( geom );
1400 : 0 : }
1401 : :
1402 : 0 : int QgsVectorLayer::addTopologicalPoints( const QgsPointXY &p )
1403 : : {
1404 : 0 : return addTopologicalPoints( QgsPoint( p ) );
1405 : 0 : }
1406 : :
1407 : 0 : int QgsVectorLayer::addTopologicalPoints( const QgsPoint &p )
1408 : : {
1409 : 0 : if ( !isValid() || !mEditBuffer || !mDataProvider )
1410 : 0 : return -1;
1411 : :
1412 : 0 : QgsVectorLayerEditUtils utils( this );
1413 : 0 : return utils.addTopologicalPoints( p );
1414 : 0 : }
1415 : :
1416 : 0 : int QgsVectorLayer::addTopologicalPoints( const QgsPointSequence &ps )
1417 : : {
1418 : 0 : if ( !mValid || !mEditBuffer || !mDataProvider )
1419 : 0 : return -1;
1420 : :
1421 : 0 : QgsVectorLayerEditUtils utils( this );
1422 : 0 : return utils.addTopologicalPoints( ps );
1423 : 0 : }
1424 : :
1425 : 0 : void QgsVectorLayer::setLabeling( QgsAbstractVectorLayerLabeling *labeling )
1426 : : {
1427 : 0 : if ( mLabeling == labeling )
1428 : 0 : return;
1429 : :
1430 : 0 : delete mLabeling;
1431 : 0 : mLabeling = labeling;
1432 : 0 : }
1433 : :
1434 : 2 : bool QgsVectorLayer::startEditing()
1435 : : {
1436 : 2 : if ( !isValid() || !mDataProvider )
1437 : : {
1438 : 0 : return false;
1439 : : }
1440 : :
1441 : : // allow editing if provider supports any of the capabilities
1442 : 2 : if ( !supportsEditing() )
1443 : : {
1444 : 0 : return false;
1445 : : }
1446 : :
1447 : 2 : if ( mEditBuffer )
1448 : : {
1449 : : // editing already underway
1450 : 1 : return false;
1451 : : }
1452 : :
1453 : 1 : emit beforeEditingStarted();
1454 : :
1455 : 1 : mDataProvider->enterUpdateMode();
1456 : :
1457 : 1 : if ( mDataProvider->transaction() )
1458 : : {
1459 : 0 : mEditBuffer = new QgsVectorLayerEditPassthrough( this );
1460 : :
1461 : 0 : connect( mDataProvider->transaction(), &QgsTransaction::dirtied, this, &QgsVectorLayer::onDirtyTransaction, Qt::UniqueConnection );
1462 : 0 : }
1463 : : else
1464 : : {
1465 : 1 : mEditBuffer = new QgsVectorLayerEditBuffer( this );
1466 : : }
1467 : : // forward signals
1468 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::invalidateSymbolCountedFlag );
1469 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::layerModified, this, &QgsVectorLayer::layerModified ); // TODO[MD]: necessary?
1470 : : //connect( mEditBuffer, SIGNAL( layerModified() ), this, SLOT( triggerRepaint() ) ); // TODO[MD]: works well?
1471 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureAdded, this, &QgsVectorLayer::featureAdded );
1472 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::featureDeleted, this, &QgsVectorLayer::onFeatureDeleted );
1473 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::geometryChanged, this, &QgsVectorLayer::geometryChanged );
1474 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::attributeValueChanged, this, &QgsVectorLayer::attributeValueChanged );
1475 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::attributeAdded, this, &QgsVectorLayer::attributeAdded );
1476 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::attributeDeleted, this, &QgsVectorLayer::attributeDeleted );
1477 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::committedAttributesDeleted, this, &QgsVectorLayer::committedAttributesDeleted );
1478 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::committedAttributesAdded, this, &QgsVectorLayer::committedAttributesAdded );
1479 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::committedFeaturesAdded, this, &QgsVectorLayer::committedFeaturesAdded );
1480 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::committedFeaturesRemoved, this, &QgsVectorLayer::committedFeaturesRemoved );
1481 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::committedAttributeValuesChanges, this, &QgsVectorLayer::committedAttributeValuesChanges );
1482 : 1 : connect( mEditBuffer, &QgsVectorLayerEditBuffer::committedGeometriesChanges, this, &QgsVectorLayer::committedGeometriesChanges );
1483 : :
1484 : 1 : updateFields();
1485 : :
1486 : 1 : emit editingStarted();
1487 : :
1488 : 1 : return true;
1489 : 2 : }
1490 : :
1491 : 1 : void QgsVectorLayer::setTransformContext( const QgsCoordinateTransformContext &transformContext )
1492 : : {
1493 : 1 : if ( mDataProvider )
1494 : 1 : mDataProvider->setTransformContext( transformContext );
1495 : 1 : }
1496 : :
1497 : 0 : QgsFeatureSource::SpatialIndexPresence QgsVectorLayer::hasSpatialIndex() const
1498 : : {
1499 : 0 : return mDataProvider ? mDataProvider->hasSpatialIndex() : QgsFeatureSource::SpatialIndexUnknown;
1500 : : }
1501 : :
1502 : 0 : bool QgsVectorLayer::accept( QgsStyleEntityVisitorInterface *visitor ) const
1503 : : {
1504 : 0 : if ( mRenderer )
1505 : 0 : if ( !mRenderer->accept( visitor ) )
1506 : 0 : return false;
1507 : :
1508 : 0 : if ( mLabeling )
1509 : 0 : if ( !mLabeling->accept( visitor ) )
1510 : 0 : return false;
1511 : :
1512 : 0 : return true;
1513 : 0 : }
1514 : :
1515 : 0 : bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &context )
1516 : : {
1517 : 0 : QgsDebugMsgLevel( QStringLiteral( "Datasource in QgsVectorLayer::readXml: %1" ).arg( mDataSource.toLocal8Bit().data() ), 3 );
1518 : :
1519 : : //process provider key
1520 : 0 : QDomNode pkeyNode = layer_node.namedItem( QStringLiteral( "provider" ) );
1521 : :
1522 : 0 : if ( pkeyNode.isNull() )
1523 : : {
1524 : 0 : mProviderKey.clear();
1525 : 0 : }
1526 : : else
1527 : : {
1528 : 0 : QDomElement pkeyElt = pkeyNode.toElement();
1529 : 0 : mProviderKey = pkeyElt.text();
1530 : 0 : }
1531 : :
1532 : : // determine type of vector layer
1533 : 0 : if ( !mProviderKey.isNull() )
1534 : : {
1535 : : // if the provider string isn't empty, then we successfully
1536 : : // got the stored provider
1537 : 0 : }
1538 : 0 : else if ( mDataSource.contains( QLatin1String( "dbname=" ) ) )
1539 : : {
1540 : 0 : mProviderKey = QStringLiteral( "postgres" );
1541 : 0 : }
1542 : : else
1543 : : {
1544 : 0 : mProviderKey = QStringLiteral( "ogr" );
1545 : : }
1546 : :
1547 : 0 : QgsDataProvider::ProviderOptions options { context.transformContext() };
1548 : 0 : QgsDataProvider::ReadFlags flags;
1549 : 0 : if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
1550 : : {
1551 : 0 : flags |= QgsDataProvider::FlagTrustDataSource;
1552 : 0 : }
1553 : 0 : if ( ( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) || !setDataProvider( mProviderKey, options, flags ) )
1554 : : {
1555 : 0 : if ( !( mReadFlags & QgsMapLayer::FlagDontResolveLayers ) )
1556 : : {
1557 : 0 : QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
1558 : 0 : }
1559 : 0 : const QDomElement elem = layer_node.toElement();
1560 : :
1561 : : // for invalid layer sources, we fallback to stored wkbType if available
1562 : 0 : if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
1563 : 0 : mWkbType = qgsEnumKeyToValue( elem.attribute( QStringLiteral( "wkbType" ) ), mWkbType );
1564 : 0 : }
1565 : :
1566 : 0 : QDomElement pkeyElem = pkeyNode.toElement();
1567 : 0 : if ( !pkeyElem.isNull() )
1568 : : {
1569 : 0 : QString encodingString = pkeyElem.attribute( QStringLiteral( "encoding" ) );
1570 : 0 : if ( mDataProvider && !encodingString.isEmpty() )
1571 : : {
1572 : 0 : mDataProvider->setEncoding( encodingString );
1573 : 0 : }
1574 : 0 : }
1575 : :
1576 : : // load vector joins - does not resolve references to layers yet
1577 : 0 : mJoinBuffer->readXml( layer_node );
1578 : :
1579 : 0 : updateFields();
1580 : :
1581 : : // If style doesn't include a legend, we'll need to make a default one later...
1582 : 0 : mSetLegendFromStyle = false;
1583 : :
1584 : 0 : QString errorMsg;
1585 : 0 : if ( !readSymbology( layer_node, errorMsg, context ) )
1586 : : {
1587 : 0 : return false;
1588 : : }
1589 : :
1590 : 0 : readStyleManager( layer_node );
1591 : :
1592 : 0 : QDomNode depsNode = layer_node.namedItem( QStringLiteral( "dataDependencies" ) );
1593 : 0 : QDomNodeList depsNodes = depsNode.childNodes();
1594 : 0 : QSet<QgsMapLayerDependency> sources;
1595 : 0 : for ( int i = 0; i < depsNodes.count(); i++ )
1596 : : {
1597 : 0 : QString source = depsNodes.at( i ).toElement().attribute( QStringLiteral( "id" ) );
1598 : 0 : sources << QgsMapLayerDependency( source );
1599 : 0 : }
1600 : 0 : setDependencies( sources );
1601 : :
1602 : 0 : if ( !mSetLegendFromStyle )
1603 : 0 : setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) );
1604 : :
1605 : : // read extent
1606 : 0 : if ( mReadExtentFromXml )
1607 : : {
1608 : 0 : QDomNode extentNode = layer_node.namedItem( QStringLiteral( "extent" ) );
1609 : 0 : if ( !extentNode.isNull() )
1610 : : {
1611 : 0 : mXmlExtent = QgsXmlUtils::readRectangle( extentNode.toElement() );
1612 : 0 : }
1613 : 0 : }
1614 : :
1615 : : // auxiliary layer
1616 : 0 : const QDomNode asNode = layer_node.namedItem( QStringLiteral( "auxiliaryLayer" ) );
1617 : 0 : const QDomElement asElem = asNode.toElement();
1618 : 0 : if ( !asElem.isNull() )
1619 : : {
1620 : 0 : mAuxiliaryLayerKey = asElem.attribute( QStringLiteral( "key" ) );
1621 : 0 : }
1622 : :
1623 : : // QGIS Server WMS Dimensions
1624 : 0 : mServerProperties->readXml( layer_node );
1625 : :
1626 : 0 : return isValid(); // should be true if read successfully
1627 : :
1628 : 0 : } // void QgsVectorLayer::readXml
1629 : :
1630 : :
1631 : 0 : void QgsVectorLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag )
1632 : : {
1633 : 0 : QgsDataProvider::ProviderOptions options;
1634 : 0 : setDataSource( dataSource, baseName, provider, options, loadDefaultStyleFlag );
1635 : 0 : }
1636 : :
1637 : 78 : void QgsVectorLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
1638 : : {
1639 : 78 : QgsWkbTypes::GeometryType geomType = geometryType();
1640 : :
1641 : 78 : mDataSource = dataSource;
1642 : 78 : setName( baseName );
1643 : :
1644 : 78 : QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags();
1645 : 78 : if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
1646 : : {
1647 : 0 : flags |= QgsDataProvider::FlagTrustDataSource;
1648 : 0 : }
1649 : 78 : setDataProvider( provider, options, flags );
1650 : :
1651 : 78 : if ( !isValid() )
1652 : : {
1653 : 0 : emit dataSourceChanged();
1654 : 0 : return;
1655 : : }
1656 : :
1657 : : // Always set crs
1658 : 78 : setCoordinateSystem();
1659 : :
1660 : : // reset style if loading default style, style is missing, or geometry type is has changed (and layer is valid)
1661 : 78 : if ( !renderer() || !legend() || ( isValid() && geomType != geometryType() ) || loadDefaultStyleFlag )
1662 : : {
1663 : 78 : std::unique_ptr< QgsScopedRuntimeProfile > profile;
1664 : 156 : if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1665 : 0 : profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
1666 : :
1667 : 78 : bool defaultLoadedFlag = false;
1668 : :
1669 : 78 : if ( loadDefaultStyleFlag && isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1670 : : {
1671 : : // first try to create a renderer directly from the data provider
1672 : 0 : std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1673 : 0 : if ( defaultRenderer )
1674 : : {
1675 : 0 : defaultLoadedFlag = true;
1676 : 0 : setRenderer( defaultRenderer.release() );
1677 : 0 : }
1678 : 0 : }
1679 : :
1680 : : // need to check whether the default style included a legend, and if not, we need to make a default legend
1681 : : // later...
1682 : 78 : mSetLegendFromStyle = false;
1683 : :
1684 : : // else check if there is a default style / propertysheet defined
1685 : : // for this layer and if so apply it
1686 : 78 : if ( !defaultLoadedFlag && loadDefaultStyleFlag )
1687 : : {
1688 : 78 : loadDefaultStyle( defaultLoadedFlag );
1689 : 78 : }
1690 : :
1691 : : // if the default style failed to load or was disabled use some very basic defaults
1692 : 78 : if ( !defaultLoadedFlag && isSpatial() )
1693 : : {
1694 : : // add single symbol renderer
1695 : 78 : setRenderer( QgsFeatureRenderer::defaultRenderer( geometryType() ) );
1696 : 78 : }
1697 : :
1698 : 78 : if ( !mSetLegendFromStyle )
1699 : 78 : setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) );
1700 : :
1701 : 78 : if ( mDataProvider->capabilities() & QgsVectorDataProvider::CreateLabeling )
1702 : : {
1703 : 0 : std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
1704 : 0 : if ( defaultLabeling )
1705 : : {
1706 : 0 : setLabeling( defaultLabeling.release() );
1707 : 0 : setLabelsEnabled( true );
1708 : 0 : }
1709 : 0 : }
1710 : 78 : }
1711 : :
1712 : 78 : emit dataSourceChanged();
1713 : 78 : triggerRepaint();
1714 : 78 : }
1715 : :
1716 : 78 : QString QgsVectorLayer::loadDefaultStyle( bool &resultFlag )
1717 : : {
1718 : 78 : if ( isSpatial() && mDataProvider->capabilities() & QgsVectorDataProvider::CreateRenderer )
1719 : : {
1720 : : // first try to create a renderer directly from the data provider
1721 : 0 : std::unique_ptr< QgsFeatureRenderer > defaultRenderer( mDataProvider->createRenderer() );
1722 : 0 : if ( defaultRenderer )
1723 : : {
1724 : 0 : resultFlag = true;
1725 : 0 : setRenderer( defaultRenderer.release() );
1726 : 0 : return QString();
1727 : : }
1728 : 0 : }
1729 : :
1730 : 78 : return QgsMapLayer::loadDefaultStyle( resultFlag );
1731 : 78 : }
1732 : :
1733 : :
1734 : 78 : bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
1735 : : {
1736 : 78 : mProviderKey = provider;
1737 : 78 : delete mDataProvider;
1738 : :
1739 : : // For Postgres provider primary key unicity is tested at construction time,
1740 : : // so it has to be set before initializing the provider,
1741 : : // this manipulation is necessary to preserve default behavior when
1742 : : // "trust layer metadata" project level option is set and checkPrimaryKeyUnicity
1743 : : // was not explicitly passed in the uri
1744 : 78 : if ( provider.compare( QLatin1String( "postgres" ) ) == 0 )
1745 : : {
1746 : 0 : const QString checkUnicityKey { QStringLiteral( "checkPrimaryKeyUnicity" ) };
1747 : 0 : QgsDataSourceUri uri( mDataSource );
1748 : 0 : if ( ! uri.hasParam( checkUnicityKey ) )
1749 : : {
1750 : 0 : uri.setParam( checkUnicityKey, mReadExtentFromXml ? "0" : "1" );
1751 : 0 : mDataSource = uri.uri( false );
1752 : 0 : }
1753 : 0 : }
1754 : :
1755 : 78 : std::unique_ptr< QgsScopedRuntimeProfile > profile;
1756 : 156 : if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1757 : 0 : profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Create %1 provider" ).arg( provider ), QStringLiteral( "projectload" ) );
1758 : :
1759 : 78 : mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, mDataSource, options, flags ) );
1760 : 78 : if ( !mDataProvider )
1761 : : {
1762 : 0 : setValid( false );
1763 : 0 : QgsDebugMsgLevel( QStringLiteral( "Unable to get data provider" ), 2 );
1764 : 0 : return false;
1765 : : }
1766 : :
1767 : 78 : mDataProvider->setParent( this );
1768 : 78 : connect( mDataProvider, &QgsVectorDataProvider::raiseError, this, &QgsVectorLayer::raiseError );
1769 : :
1770 : 78 : QgsDebugMsgLevel( QStringLiteral( "Instantiated the data provider plugin" ), 2 );
1771 : :
1772 : 78 : setValid( mDataProvider->isValid() );
1773 : 78 : if ( !isValid() )
1774 : : {
1775 : 0 : QgsDebugMsgLevel( QStringLiteral( "Invalid provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
1776 : 0 : return false;
1777 : : }
1778 : :
1779 : 78 : if ( profile )
1780 : 0 : profile->switchTask( tr( "Read layer metadata" ) );
1781 : 78 : if ( mDataProvider->capabilities() & QgsVectorDataProvider::ReadLayerMetadata )
1782 : : {
1783 : 64 : setMetadata( mDataProvider->layerMetadata() );
1784 : 64 : QgsDebugMsgLevel( QStringLiteral( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
1785 : 64 : }
1786 : :
1787 : : // TODO: Check if the provider has the capability to send fullExtentCalculated
1788 : 78 : connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [ = ] { updateExtents(); } );
1789 : :
1790 : : // get and store the feature type
1791 : 78 : mWkbType = mDataProvider->wkbType();
1792 : :
1793 : 78 : if ( profile )
1794 : 0 : profile->switchTask( tr( "Read layer fields" ) );
1795 : 78 : updateFields();
1796 : :
1797 : 78 : if ( mProviderKey == QLatin1String( "postgres" ) )
1798 : : {
1799 : : // update datasource from data provider computed one
1800 : 0 : mDataSource = mDataProvider->dataSourceUri( false );
1801 : :
1802 : 0 : QgsDebugMsgLevel( QStringLiteral( "Beautifying layer name %1" ).arg( name() ), 3 );
1803 : :
1804 : : // adjust the display name for postgres layers
1805 : 0 : QRegExp reg( R"lit("[^"]+"\."([^"] + )"( \([^)]+\))?)lit" );
1806 : 0 : if ( reg.indexIn( name() ) >= 0 )
1807 : : {
1808 : 0 : QStringList stuff = reg.capturedTexts();
1809 : 0 : QString lName = stuff[1];
1810 : :
1811 : 0 : const QMap<QString, QgsMapLayer *> &layers = QgsProject::instance()->mapLayers();
1812 : :
1813 : 0 : QMap<QString, QgsMapLayer *>::const_iterator it;
1814 : 0 : for ( it = layers.constBegin(); it != layers.constEnd() && ( *it )->name() != lName; ++it )
1815 : : ;
1816 : :
1817 : 0 : if ( it != layers.constEnd() && stuff.size() > 2 )
1818 : : {
1819 : 0 : lName += '.' + stuff[2].mid( 2, stuff[2].length() - 3 );
1820 : 0 : }
1821 : :
1822 : 0 : if ( !lName.isEmpty() )
1823 : 0 : setName( lName );
1824 : 0 : }
1825 : 0 : QgsDebugMsgLevel( QStringLiteral( "Beautified layer name %1" ).arg( name() ), 3 );
1826 : 0 : }
1827 : 78 : else if ( mProviderKey == QLatin1String( "osm" ) )
1828 : : {
1829 : : // make sure that the "observer" has been removed from URI to avoid crashes
1830 : 0 : mDataSource = mDataProvider->dataSourceUri();
1831 : 0 : }
1832 : 78 : else if ( provider == QLatin1String( "ogr" ) )
1833 : : {
1834 : : // make sure that the /vsigzip or /vsizip is added to uri, if applicable
1835 : 64 : mDataSource = mDataProvider->dataSourceUri();
1836 : 64 : if ( mDataSource.right( 10 ) == QLatin1String( "|layerid=0" ) )
1837 : 0 : mDataSource.chop( 10 );
1838 : 64 : }
1839 : 14 : else if ( provider == QLatin1String( "memory" ) )
1840 : : {
1841 : : // required so that source differs between memory layers
1842 : 28 : mDataSource = mDataSource + QStringLiteral( "&uid=%1" ).arg( QUuid::createUuid().toString() );
1843 : 14 : }
1844 : :
1845 : 78 : connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::emitDataChanged );
1846 : 78 : connect( mDataProvider, &QgsVectorDataProvider::dataChanged, this, &QgsVectorLayer::removeSelection );
1847 : :
1848 : 78 : return true;
1849 : 78 : } // QgsVectorLayer:: setDataProvider
1850 : :
1851 : :
1852 : :
1853 : :
1854 : : /* virtual */
1855 : 0 : bool QgsVectorLayer::writeXml( QDomNode &layer_node,
1856 : : QDomDocument &document,
1857 : : const QgsReadWriteContext &context ) const
1858 : : {
1859 : : // first get the layer element so that we can append the type attribute
1860 : :
1861 : 0 : QDomElement mapLayerNode = layer_node.toElement();
1862 : :
1863 : 0 : if ( mapLayerNode.isNull() || ( "maplayer" != mapLayerNode.nodeName() ) )
1864 : : {
1865 : 0 : QgsDebugMsgLevel( QStringLiteral( "can't find <maplayer>" ), 2 );
1866 : 0 : return false;
1867 : : }
1868 : :
1869 : 0 : mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::VectorLayer ) );
1870 : :
1871 : : // set the geometry type
1872 : 0 : mapLayerNode.setAttribute( QStringLiteral( "geometry" ), QgsWkbTypes::geometryDisplayString( geometryType() ) );
1873 : 0 : mapLayerNode.setAttribute( QStringLiteral( "wkbType" ), qgsEnumValueToKey( wkbType() ) );
1874 : :
1875 : : // add provider node
1876 : 0 : if ( mDataProvider )
1877 : : {
1878 : 0 : QDomElement provider = document.createElement( QStringLiteral( "provider" ) );
1879 : 0 : provider.setAttribute( QStringLiteral( "encoding" ), mDataProvider->encoding() );
1880 : 0 : QDomText providerText = document.createTextNode( providerType() );
1881 : 0 : provider.appendChild( providerText );
1882 : 0 : layer_node.appendChild( provider );
1883 : 0 : }
1884 : :
1885 : : //save joins
1886 : 0 : mJoinBuffer->writeXml( layer_node, document );
1887 : :
1888 : : // dependencies
1889 : 0 : QDomElement dependenciesElement = document.createElement( QStringLiteral( "layerDependencies" ) );
1890 : 0 : const auto constDependencies = dependencies();
1891 : 0 : for ( const QgsMapLayerDependency &dep : constDependencies )
1892 : : {
1893 : 0 : if ( dep.type() != QgsMapLayerDependency::PresenceDependency )
1894 : 0 : continue;
1895 : 0 : QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
1896 : 0 : depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
1897 : 0 : dependenciesElement.appendChild( depElem );
1898 : 0 : }
1899 : 0 : layer_node.appendChild( dependenciesElement );
1900 : :
1901 : : // change dependencies
1902 : 0 : QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
1903 : 0 : for ( const QgsMapLayerDependency &dep : constDependencies )
1904 : : {
1905 : 0 : if ( dep.type() != QgsMapLayerDependency::DataDependency )
1906 : 0 : continue;
1907 : 0 : QDomElement depElem = document.createElement( QStringLiteral( "layer" ) );
1908 : 0 : depElem.setAttribute( QStringLiteral( "id" ), dep.layerId() );
1909 : 0 : dataDependenciesElement.appendChild( depElem );
1910 : 0 : }
1911 : 0 : layer_node.appendChild( dataDependenciesElement );
1912 : :
1913 : : // save expression fields
1914 : 0 : mExpressionFieldBuffer->writeXml( layer_node, document );
1915 : :
1916 : 0 : writeStyleManager( layer_node, document );
1917 : :
1918 : : // auxiliary layer
1919 : 0 : QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
1920 : 0 : if ( mAuxiliaryLayer )
1921 : : {
1922 : 0 : const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
1923 : 0 : asElem.setAttribute( QStringLiteral( "key" ), pkField );
1924 : 0 : }
1925 : 0 : layer_node.appendChild( asElem );
1926 : :
1927 : : // save QGIS Server WMS Dimension definitions
1928 : 0 : mServerProperties->writeXml( layer_node, document );
1929 : :
1930 : : // renderer specific settings
1931 : 0 : QString errorMsg;
1932 : 0 : return writeSymbology( layer_node, document, errorMsg, context );
1933 : 0 : }
1934 : :
1935 : 0 : QString QgsVectorLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const
1936 : : {
1937 : 0 : QString src( source );
1938 : :
1939 : : // TODO: what about postgres, mysql and others, they should not go through writePath()
1940 : 0 : if ( providerType() == QLatin1String( "spatialite" ) )
1941 : : {
1942 : 0 : QgsDataSourceUri uri( src );
1943 : 0 : QString database = context.pathResolver().writePath( uri.database() );
1944 : 0 : uri.setConnection( uri.host(), uri.port(), database, uri.username(), uri.password() );
1945 : 0 : src = uri.uri();
1946 : 0 : }
1947 : 0 : else if ( providerType() == QLatin1String( "ogr" ) )
1948 : : {
1949 : 0 : QStringList theURIParts = src.split( '|' );
1950 : 0 : theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
1951 : 0 : src = theURIParts.join( QLatin1Char( '|' ) );
1952 : 0 : }
1953 : 0 : else if ( providerType() == QLatin1String( "gpx" ) )
1954 : : {
1955 : 0 : QStringList theURIParts = src.split( '?' );
1956 : 0 : theURIParts[0] = context.pathResolver().writePath( theURIParts[0] );
1957 : 0 : src = theURIParts.join( QLatin1Char( '?' ) );
1958 : 0 : }
1959 : 0 : else if ( providerType() == QLatin1String( "delimitedtext" ) )
1960 : : {
1961 : 0 : QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
1962 : 0 : QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().writePath( urlSource.toLocalFile() ) );
1963 : 0 : urlDest.setQuery( urlSource.query() );
1964 : 0 : src = QString::fromLatin1( urlDest.toEncoded() );
1965 : 0 : }
1966 : 0 : else if ( providerType() == QLatin1String( "memory" ) )
1967 : : {
1968 : : // Refetch the source from the provider, because adding fields actually changes the source for this provider.
1969 : 0 : src = dataProvider()->dataSourceUri();
1970 : 0 : }
1971 : 0 : else if ( providerType() == QLatin1String( "virtual" ) )
1972 : : {
1973 : 0 : QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
1974 : 0 : QStringList theURIParts;
1975 : :
1976 : 0 : QUrlQuery query = QUrlQuery( urlSource.query() );
1977 : 0 : QList<QPair<QString, QString> > queryItems = query.queryItems();
1978 : :
1979 : 0 : for ( int i = 0; i < queryItems.size(); i++ )
1980 : : {
1981 : 0 : QString key = queryItems.at( i ).first;
1982 : 0 : QString value = queryItems.at( i ).second;
1983 : 0 : if ( key == QLatin1String( "layer" ) )
1984 : : {
1985 : : // syntax: provider:url_encoded_source_URI(:name(:encoding)?)?
1986 : 0 : theURIParts = value.split( ':' );
1987 : 0 : theURIParts[1] = QUrl::fromPercentEncoding( theURIParts[1].toUtf8() );
1988 : :
1989 : 0 : if ( theURIParts[0] == QLatin1String( "delimitedtext" ) )
1990 : : {
1991 : 0 : QUrl urlSource = QUrl( theURIParts[1] );
1992 : 0 : QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().writePath( urlSource.toLocalFile() ) );
1993 : 0 : urlDest.setQuery( urlSource.query() );
1994 : 0 : theURIParts[1] = QUrl::toPercentEncoding( urlDest.toString(), QByteArray( "" ), QByteArray( ":" ) );
1995 : 0 : }
1996 : : else
1997 : : {
1998 : 0 : theURIParts[1] = context.pathResolver().writePath( theURIParts[1] );
1999 : 0 : theURIParts[1] = QUrl::toPercentEncoding( theURIParts[1] );
2000 : : }
2001 : :
2002 : 0 : queryItems[i].second = theURIParts.join( QLatin1Char( ':' ) ) ;
2003 : 0 : }
2004 : 0 : }
2005 : :
2006 : 0 : query.setQueryItems( queryItems );
2007 : :
2008 : 0 : QUrl urlDest = QUrl( urlSource );
2009 : 0 : urlDest.setQuery( query.query() );
2010 : 0 : src = QString::fromLatin1( urlDest.toEncoded() );
2011 : 0 : }
2012 : : else
2013 : : {
2014 : 0 : src = context.pathResolver().writePath( src );
2015 : : }
2016 : :
2017 : 0 : return src;
2018 : 0 : }
2019 : :
2020 : 0 : QString QgsVectorLayer::decodedSource( const QString &source, const QString &provider, const QgsReadWriteContext &context ) const
2021 : : {
2022 : 0 : QString src( source );
2023 : :
2024 : 0 : if ( provider == QLatin1String( "spatialite" ) )
2025 : : {
2026 : 0 : QgsDataSourceUri uri( src );
2027 : 0 : uri.setDatabase( context.pathResolver().readPath( uri.database() ) );
2028 : 0 : src = uri.uri();
2029 : 0 : }
2030 : 0 : else if ( provider == QLatin1String( "ogr" ) )
2031 : : {
2032 : 0 : QStringList theURIParts = src.split( '|' );
2033 : 0 : theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
2034 : 0 : src = theURIParts.join( QLatin1Char( '|' ) );
2035 : 0 : }
2036 : 0 : else if ( provider == QLatin1String( "gpx" ) )
2037 : : {
2038 : 0 : QStringList theURIParts = src.split( '?' );
2039 : 0 : theURIParts[0] = context.pathResolver().readPath( theURIParts[0] );
2040 : 0 : src = theURIParts.join( QLatin1Char( '?' ) );
2041 : 0 : }
2042 : 0 : else if ( provider == QLatin1String( "delimitedtext" ) )
2043 : : {
2044 : 0 : QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
2045 : :
2046 : 0 : if ( !src.startsWith( QLatin1String( "file:" ) ) )
2047 : : {
2048 : 0 : QUrl file = QUrl::fromLocalFile( src.left( src.indexOf( '?' ) ) );
2049 : 0 : urlSource.setScheme( QStringLiteral( "file" ) );
2050 : 0 : urlSource.setPath( file.path() );
2051 : 0 : }
2052 : :
2053 : 0 : QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().readPath( urlSource.toLocalFile() ) );
2054 : 0 : urlDest.setQuery( urlSource.query() );
2055 : 0 : src = QString::fromLatin1( urlDest.toEncoded() );
2056 : 0 : }
2057 : 0 : else if ( provider == QLatin1String( "virtual" ) )
2058 : : {
2059 : 0 : QUrl urlSource = QUrl::fromEncoded( src.toLatin1() );
2060 : 0 : QStringList theURIParts;
2061 : :
2062 : 0 : QUrlQuery query = QUrlQuery( urlSource.query() );
2063 : 0 : QList<QPair<QString, QString> > queryItems = query.queryItems();
2064 : :
2065 : 0 : for ( int i = 0; i < queryItems.size(); i++ )
2066 : : {
2067 : 0 : QString key = queryItems.at( i ).first;
2068 : 0 : QString value = queryItems.at( i ).second;
2069 : 0 : if ( key == QLatin1String( "layer" ) )
2070 : : {
2071 : : // syntax: provider:url_encoded_source_URI(:name(:encoding)?)?
2072 : 0 : theURIParts = value.split( ':' );
2073 : 0 : theURIParts[1] = QUrl::fromPercentEncoding( theURIParts[1].toUtf8() );
2074 : :
2075 : 0 : if ( theURIParts[0] == QLatin1String( "delimitedtext" ) )
2076 : : {
2077 : 0 : QUrl urlSource = QUrl( theURIParts[1] );
2078 : :
2079 : 0 : if ( !theURIParts[1].startsWith( QLatin1String( "file:" ) ) )
2080 : : {
2081 : 0 : QUrl file = QUrl::fromLocalFile( theURIParts[1].left( theURIParts[1].indexOf( '?' ) ) );
2082 : 0 : urlSource.setScheme( QStringLiteral( "file" ) );
2083 : 0 : urlSource.setPath( file.path() );
2084 : 0 : }
2085 : :
2086 : 0 : QUrl urlDest = QUrl::fromLocalFile( context.pathResolver().readPath( urlSource.toLocalFile() ) );
2087 : 0 : urlDest.setQuery( urlSource.query() );
2088 : :
2089 : 0 : theURIParts[1] = urlDest.toString();
2090 : 0 : }
2091 : : else
2092 : : {
2093 : 0 : theURIParts[1] = context.pathResolver().readPath( theURIParts[1] );
2094 : : }
2095 : :
2096 : 0 : theURIParts[1] = QUrl::toPercentEncoding( theURIParts[1] );
2097 : 0 : queryItems[i].second = theURIParts.join( QLatin1Char( ':' ) ) ;
2098 : 0 : }
2099 : 0 : }
2100 : :
2101 : 0 : query.setQueryItems( queryItems );
2102 : :
2103 : 0 : QUrl urlDest = QUrl( urlSource );
2104 : 0 : urlDest.setQuery( query.query() );
2105 : 0 : src = QString::fromLatin1( urlDest.toEncoded() );
2106 : 0 : }
2107 : : else
2108 : : {
2109 : 0 : src = context.pathResolver().readPath( src );
2110 : : }
2111 : :
2112 : 0 : return src;
2113 : 0 : }
2114 : :
2115 : :
2116 : :
2117 : 0 : void QgsVectorLayer::resolveReferences( QgsProject *project )
2118 : : {
2119 : 0 : QgsMapLayer::resolveReferences( project );
2120 : 0 : mJoinBuffer->resolveReferences( project );
2121 : 0 : }
2122 : :
2123 : :
2124 : 0 : bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMessage,
2125 : : QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2126 : : {
2127 : 0 : QgsReadWriteContextCategoryPopper p = context.enterCategory( tr( "Symbology" ) );
2128 : :
2129 : 0 : if ( categories.testFlag( Fields ) )
2130 : : {
2131 : 0 : if ( !mExpressionFieldBuffer )
2132 : 0 : mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
2133 : 0 : mExpressionFieldBuffer->readXml( layerNode );
2134 : :
2135 : 0 : updateFields();
2136 : 0 : }
2137 : :
2138 : 0 : if ( categories.testFlag( Relations ) )
2139 : : {
2140 : :
2141 : 0 : const QgsPathResolver resolver { QgsProject::instance()->pathResolver() };
2142 : :
2143 : : // Restore referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2144 : 0 : QDomNodeList referencedLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencedLayers" ) );
2145 : 0 : if ( referencedLayersNodeList.size() > 0 )
2146 : : {
2147 : 0 : const QDomNodeList relationNodes { referencedLayersNodeList.at( 0 ).childNodes() };
2148 : 0 : for ( int i = 0; i < relationNodes.length(); ++i )
2149 : : {
2150 : 0 : const QDomElement relationElement = relationNodes.at( i ).toElement();
2151 : :
2152 : 0 : mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referencing, relationElement, resolver ) );
2153 : 0 : }
2154 : 0 : }
2155 : :
2156 : : // Restore referencing layers: relations where "this" is the parent layer (the referenced part where the FK points to)
2157 : 0 : QDomNodeList referencingLayersNodeList = layerNode.toElement().elementsByTagName( QStringLiteral( "referencingLayers" ) );
2158 : 0 : if ( referencingLayersNodeList.size() > 0 )
2159 : : {
2160 : 0 : const QDomNodeList relationNodes { referencingLayersNodeList.at( 0 ).childNodes() };
2161 : 0 : for ( int i = 0; i < relationNodes.length(); ++i )
2162 : : {
2163 : 0 : const QDomElement relationElement = relationNodes.at( i ).toElement();
2164 : 0 : mWeakRelations.push_back( QgsWeakRelation::readXml( this, QgsWeakRelation::Referenced, relationElement, resolver ) );
2165 : 0 : }
2166 : 0 : }
2167 : 0 : }
2168 : :
2169 : 0 : QDomElement layerElement = layerNode.toElement();
2170 : :
2171 : 0 : readCommonStyle( layerElement, context, categories );
2172 : :
2173 : 0 : readStyle( layerNode, errorMessage, context, categories );
2174 : :
2175 : 0 : if ( categories.testFlag( MapTips ) )
2176 : 0 : mMapTipTemplate = layerNode.namedItem( QStringLiteral( "mapTip" ) ).toElement().text();
2177 : :
2178 : 0 : if ( categories.testFlag( LayerConfiguration ) )
2179 : 0 : mDisplayExpression = layerNode.namedItem( QStringLiteral( "previewExpression" ) ).toElement().text();
2180 : :
2181 : : // Try to migrate pre QGIS 3.0 display field property
2182 : 0 : QString displayField = layerNode.namedItem( QStringLiteral( "displayfield" ) ).toElement().text();
2183 : 0 : if ( mFields.lookupField( displayField ) < 0 )
2184 : : {
2185 : : // if it's not a field, it's a maptip
2186 : 0 : if ( mMapTipTemplate.isEmpty() && categories.testFlag( MapTips ) )
2187 : 0 : mMapTipTemplate = displayField;
2188 : 0 : }
2189 : : else
2190 : : {
2191 : 0 : if ( mDisplayExpression.isEmpty() && categories.testFlag( LayerConfiguration ) )
2192 : 0 : mDisplayExpression = QgsExpression::quotedColumnRef( displayField );
2193 : : }
2194 : :
2195 : : // process the attribute actions
2196 : 0 : if ( categories.testFlag( Actions ) )
2197 : 0 : mActions->readXml( layerNode );
2198 : :
2199 : 0 : if ( categories.testFlag( Fields ) )
2200 : : {
2201 : 0 : mAttributeAliasMap.clear();
2202 : 0 : QDomNode aliasesNode = layerNode.namedItem( QStringLiteral( "aliases" ) );
2203 : 0 : if ( !aliasesNode.isNull() )
2204 : : {
2205 : 0 : QDomElement aliasElem;
2206 : :
2207 : 0 : QDomNodeList aliasNodeList = aliasesNode.toElement().elementsByTagName( QStringLiteral( "alias" ) );
2208 : 0 : for ( int i = 0; i < aliasNodeList.size(); ++i )
2209 : : {
2210 : 0 : aliasElem = aliasNodeList.at( i ).toElement();
2211 : :
2212 : 0 : QString field;
2213 : 0 : if ( aliasElem.hasAttribute( QStringLiteral( "field" ) ) )
2214 : : {
2215 : 0 : field = aliasElem.attribute( QStringLiteral( "field" ) );
2216 : 0 : }
2217 : : else
2218 : : {
2219 : 0 : int index = aliasElem.attribute( QStringLiteral( "index" ) ).toInt();
2220 : :
2221 : 0 : if ( index >= 0 && index < fields().count() )
2222 : 0 : field = fields().at( index ).name();
2223 : : }
2224 : :
2225 : 0 : QString alias;
2226 : :
2227 : 0 : if ( !aliasElem.attribute( QStringLiteral( "name" ) ).isEmpty() )
2228 : : {
2229 : : //if it has alias
2230 : 0 : alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), aliasElem.attribute( QStringLiteral( "name" ) ) );
2231 : 0 : QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + aliasElem.attribute( QStringLiteral( "name" ) ), 3 );
2232 : 0 : }
2233 : : else
2234 : : {
2235 : : //if it has no alias, it should be the fields translation
2236 : 0 : alias = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ), field );
2237 : 0 : QgsDebugMsgLevel( "context" + QStringLiteral( "project:layers:%1:fieldaliases" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text() ) + " source " + field, 3 );
2238 : : //if it gets the exact field value, there has been no translation (or not even translation loaded) - so no alias should be generated;
2239 : 0 : if ( alias == aliasElem.attribute( QStringLiteral( "field" ) ) )
2240 : 0 : alias.clear();
2241 : : }
2242 : :
2243 : 0 : QgsDebugMsgLevel( "field " + field + " origalias " + aliasElem.attribute( QStringLiteral( "name" ) ) + " trans " + alias, 3 );
2244 : 0 : mAttributeAliasMap.insert( field, alias );
2245 : 0 : }
2246 : 0 : }
2247 : :
2248 : : // default expressions
2249 : 0 : mDefaultExpressionMap.clear();
2250 : 0 : QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) );
2251 : 0 : if ( !defaultsNode.isNull() )
2252 : : {
2253 : 0 : QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( QStringLiteral( "default" ) );
2254 : 0 : for ( int i = 0; i < defaultNodeList.size(); ++i )
2255 : : {
2256 : 0 : QDomElement defaultElem = defaultNodeList.at( i ).toElement();
2257 : :
2258 : 0 : QString field = defaultElem.attribute( QStringLiteral( "field" ), QString() );
2259 : 0 : QString expression = defaultElem.attribute( QStringLiteral( "expression" ), QString() );
2260 : 0 : bool applyOnUpdate = defaultElem.attribute( QStringLiteral( "applyOnUpdate" ), QStringLiteral( "0" ) ) == QLatin1String( "1" );
2261 : 0 : if ( field.isEmpty() || expression.isEmpty() )
2262 : 0 : continue;
2263 : :
2264 : 0 : mDefaultExpressionMap.insert( field, QgsDefaultValue( expression, applyOnUpdate ) );
2265 : 0 : }
2266 : 0 : }
2267 : :
2268 : : // constraints
2269 : 0 : mFieldConstraints.clear();
2270 : 0 : mFieldConstraintStrength.clear();
2271 : 0 : QDomNode constraintsNode = layerNode.namedItem( QStringLiteral( "constraints" ) );
2272 : 0 : if ( !constraintsNode.isNull() )
2273 : : {
2274 : 0 : QDomNodeList constraintNodeList = constraintsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2275 : 0 : for ( int i = 0; i < constraintNodeList.size(); ++i )
2276 : : {
2277 : 0 : QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2278 : :
2279 : 0 : QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2280 : 0 : int constraints = constraintElem.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
2281 : 0 : if ( field.isEmpty() || constraints == 0 )
2282 : 0 : continue;
2283 : :
2284 : 0 : mFieldConstraints.insert( field, static_cast< QgsFieldConstraints::Constraints >( constraints ) );
2285 : :
2286 : 0 : int uniqueStrength = constraintElem.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
2287 : 0 : int notNullStrength = constraintElem.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
2288 : 0 : int expStrength = constraintElem.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
2289 : :
2290 : 0 : mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintUnique ), static_cast< QgsFieldConstraints::ConstraintStrength >( uniqueStrength ) );
2291 : 0 : mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintNotNull ), static_cast< QgsFieldConstraints::ConstraintStrength >( notNullStrength ) );
2292 : 0 : mFieldConstraintStrength.insert( qMakePair( field, QgsFieldConstraints::ConstraintExpression ), static_cast< QgsFieldConstraints::ConstraintStrength >( expStrength ) );
2293 : 0 : }
2294 : 0 : }
2295 : 0 : mFieldConstraintExpressions.clear();
2296 : 0 : QDomNode constraintExpressionsNode = layerNode.namedItem( QStringLiteral( "constraintExpressions" ) );
2297 : 0 : if ( !constraintExpressionsNode.isNull() )
2298 : : {
2299 : 0 : QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( QStringLiteral( "constraint" ) );
2300 : 0 : for ( int i = 0; i < constraintNodeList.size(); ++i )
2301 : : {
2302 : 0 : QDomElement constraintElem = constraintNodeList.at( i ).toElement();
2303 : :
2304 : 0 : QString field = constraintElem.attribute( QStringLiteral( "field" ), QString() );
2305 : 0 : QString exp = constraintElem.attribute( QStringLiteral( "exp" ), QString() );
2306 : 0 : QString desc = constraintElem.attribute( QStringLiteral( "desc" ), QString() );
2307 : 0 : if ( field.isEmpty() || exp.isEmpty() )
2308 : 0 : continue;
2309 : :
2310 : 0 : mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
2311 : 0 : }
2312 : 0 : }
2313 : :
2314 : 0 : updateFields();
2315 : 0 : }
2316 : :
2317 : : // load field configuration
2318 : 0 : if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2319 : : {
2320 : 0 : QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
2321 : 0 : QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
2322 : 0 : for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
2323 : : {
2324 : 0 : const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
2325 : 0 : const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();
2326 : :
2327 : 0 : QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
2328 : :
2329 : 0 : if ( categories.testFlag( Fields ) )
2330 : 0 : mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), QgsField::ConfigurationFlag::None );
2331 : :
2332 : : // Load editor widget configuration
2333 : 0 : if ( categories.testFlag( Forms ) )
2334 : : {
2335 : 0 : const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
2336 : 0 : const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
2337 : 0 : const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
2338 : 0 : QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
2339 : 0 : if ( widgetType == QLatin1String( "ValueRelation" ) )
2340 : : {
2341 : 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() );
2342 : 0 : }
2343 : 0 : QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
2344 : 0 : mFieldWidgetSetups[fieldName] = setup;
2345 : 0 : }
2346 : 0 : }
2347 : 0 : }
2348 : :
2349 : : // Legacy reading for QGIS 3.14 and older projects
2350 : : // Attributes excluded from WMS and WFS
2351 : 0 : if ( categories.testFlag( Fields ) )
2352 : : {
2353 : 0 : const QList<QPair<QString, QgsField::ConfigurationFlag>> legacyConfig
2354 : 0 : {
2355 : 0 : qMakePair( QStringLiteral( "excludeAttributesWMS" ), QgsField::ConfigurationFlag::HideFromWms ),
2356 : 0 : qMakePair( QStringLiteral( "excludeAttributesWFS" ), QgsField::ConfigurationFlag::HideFromWfs )
2357 : : };
2358 : 0 : for ( const auto &config : legacyConfig )
2359 : : {
2360 : 0 : QDomNode excludeNode = layerNode.namedItem( config.first );
2361 : 0 : if ( !excludeNode.isNull() )
2362 : : {
2363 : 0 : QDomNodeList attributeNodeList = excludeNode.toElement().elementsByTagName( QStringLiteral( "attribute" ) );
2364 : 0 : for ( int i = 0; i < attributeNodeList.size(); ++i )
2365 : : {
2366 : 0 : QString fieldName = attributeNodeList.at( i ).toElement().text();
2367 : 0 : if ( !mFieldConfigurationFlags.contains( fieldName ) )
2368 : 0 : mFieldConfigurationFlags[fieldName] = config.second;
2369 : : else
2370 : 0 : mFieldConfigurationFlags[fieldName].setFlag( config.second, true );
2371 : 0 : }
2372 : 0 : }
2373 : 0 : }
2374 : 0 : }
2375 : :
2376 : 0 : if ( categories.testFlag( GeometryOptions ) )
2377 : 0 : mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
2378 : :
2379 : 0 : if ( categories.testFlag( Forms ) )
2380 : 0 : mEditFormConfig.readXml( layerNode, context );
2381 : :
2382 : 0 : if ( categories.testFlag( AttributeTable ) )
2383 : : {
2384 : 0 : mAttributeTableConfig.readXml( layerNode );
2385 : 0 : mConditionalStyles->readXml( layerNode, context );
2386 : 0 : mStoredExpressionManager->readXml( layerNode );
2387 : 0 : }
2388 : :
2389 : 0 : if ( categories.testFlag( CustomProperties ) )
2390 : 0 : readCustomProperties( layerNode, QStringLiteral( "variable" ) );
2391 : :
2392 : 0 : QDomElement mapLayerNode = layerNode.toElement();
2393 : 0 : if ( categories.testFlag( LayerConfiguration )
2394 : 0 : && mapLayerNode.attribute( QStringLiteral( "readOnly" ), QStringLiteral( "0" ) ).toInt() == 1 )
2395 : 0 : mReadOnly = true;
2396 : :
2397 : 0 : updateFields();
2398 : :
2399 : 0 : if ( categories.testFlag( Legend ) )
2400 : : {
2401 : 0 : const QDomElement legendElem = layerNode.firstChildElement( QStringLiteral( "legend" ) );
2402 : 0 : if ( !legendElem.isNull() )
2403 : : {
2404 : 0 : std::unique_ptr< QgsMapLayerLegend > legend( QgsMapLayerLegend::defaultVectorLegend( this ) );
2405 : 0 : legend->readXml( legendElem, context );
2406 : 0 : setLegend( legend.release() );
2407 : 0 : mSetLegendFromStyle = true;
2408 : 0 : }
2409 : 0 : }
2410 : :
2411 : : return true;
2412 : 0 : }
2413 : :
2414 : 0 : bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage,
2415 : : QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
2416 : : {
2417 : 0 : bool result = true;
2418 : 0 : emit readCustomSymbology( node.toElement(), errorMessage );
2419 : :
2420 : : // we must try to restore a renderer if our geometry type is unknown
2421 : : // as this allows the renderer to be correctly restored even for layers
2422 : : // with broken sources
2423 : 0 : if ( isSpatial() || mWkbType == QgsWkbTypes::Unknown )
2424 : : {
2425 : : // try renderer v2 first
2426 : 0 : if ( categories.testFlag( Symbology ) )
2427 : : {
2428 : 0 : QDomElement rendererElement = node.firstChildElement( RENDERER_TAG_NAME );
2429 : 0 : if ( !rendererElement.isNull() )
2430 : : {
2431 : 0 : QgsFeatureRenderer *r = QgsFeatureRenderer::load( rendererElement, context );
2432 : 0 : if ( r )
2433 : : {
2434 : 0 : setRenderer( r );
2435 : 0 : }
2436 : : else
2437 : : {
2438 : 0 : result = false;
2439 : : }
2440 : 0 : }
2441 : : // make sure layer has a renderer - if none exists, fallback to a default renderer
2442 : 0 : if ( isSpatial() && !renderer() )
2443 : : {
2444 : 0 : setRenderer( QgsFeatureRenderer::defaultRenderer( geometryType() ) );
2445 : 0 : }
2446 : 0 : }
2447 : :
2448 : : // read labeling definition
2449 : 0 : if ( categories.testFlag( Labeling ) )
2450 : : {
2451 : 0 : QDomElement labelingElement = node.firstChildElement( QStringLiteral( "labeling" ) );
2452 : 0 : QgsAbstractVectorLayerLabeling *labeling = nullptr;
2453 : 0 : if ( labelingElement.isNull() ||
2454 : 0 : ( labelingElement.attribute( QStringLiteral( "type" ) ) == QLatin1String( "simple" ) && labelingElement.firstChildElement( QStringLiteral( "settings" ) ).isNull() ) )
2455 : : {
2456 : : // make sure we have custom properties for labeling for 2.x projects
2457 : : // (custom properties should be already loaded when reading the whole layer from XML,
2458 : : // but when reading style, custom properties are not read)
2459 : 0 : readCustomProperties( node, QStringLiteral( "labeling" ) );
2460 : :
2461 : : // support for pre-QGIS 3 labeling configurations written in custom properties
2462 : 0 : labeling = readLabelingFromCustomProperties();
2463 : 0 : }
2464 : : else
2465 : : {
2466 : 0 : labeling = QgsAbstractVectorLayerLabeling::create( labelingElement, context );
2467 : : }
2468 : 0 : setLabeling( labeling );
2469 : :
2470 : 0 : if ( node.toElement().hasAttribute( QStringLiteral( "labelsEnabled" ) ) )
2471 : 0 : mLabelsEnabled = node.toElement().attribute( QStringLiteral( "labelsEnabled" ) ).toInt();
2472 : : else
2473 : 0 : mLabelsEnabled = true;
2474 : 0 : }
2475 : :
2476 : 0 : if ( categories.testFlag( Symbology ) )
2477 : : {
2478 : : // get and set the blend mode if it exists
2479 : 0 : QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
2480 : 0 : if ( !blendModeNode.isNull() )
2481 : : {
2482 : 0 : QDomElement e = blendModeNode.toElement();
2483 : 0 : setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
2484 : 0 : }
2485 : :
2486 : : // get and set the feature blend mode if it exists
2487 : 0 : QDomNode featureBlendModeNode = node.namedItem( QStringLiteral( "featureBlendMode" ) );
2488 : 0 : if ( !featureBlendModeNode.isNull() )
2489 : : {
2490 : 0 : QDomElement e = featureBlendModeNode.toElement();
2491 : 0 : setFeatureBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
2492 : 0 : }
2493 : 0 : }
2494 : :
2495 : : // get and set the layer transparency and scale visibility if they exists
2496 : 0 : if ( categories.testFlag( Rendering ) )
2497 : : {
2498 : 0 : QDomNode layerTransparencyNode = node.namedItem( QStringLiteral( "layerTransparency" ) );
2499 : 0 : if ( !layerTransparencyNode.isNull() )
2500 : : {
2501 : 0 : QDomElement e = layerTransparencyNode.toElement();
2502 : 0 : setOpacity( 1.0 - e.text().toInt() / 100.0 );
2503 : 0 : }
2504 : 0 : QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
2505 : 0 : if ( !layerOpacityNode.isNull() )
2506 : : {
2507 : 0 : QDomElement e = layerOpacityNode.toElement();
2508 : 0 : setOpacity( e.text().toDouble() );
2509 : 0 : }
2510 : :
2511 : 0 : const bool hasScaleBasedVisibiliy { node.attributes().namedItem( QStringLiteral( "hasScaleBasedVisibilityFlag" ) ).nodeValue() == '1' };
2512 : 0 : setScaleBasedVisibility( hasScaleBasedVisibiliy );
2513 : : bool ok;
2514 : 0 : const double maxScale { node.attributes().namedItem( QStringLiteral( "maxScale" ) ).nodeValue().toDouble( &ok ) };
2515 : 0 : if ( ok )
2516 : : {
2517 : 0 : setMaximumScale( maxScale );
2518 : 0 : }
2519 : 0 : const double minScale { node.attributes().namedItem( QStringLiteral( "minScale" ) ).nodeValue().toDouble( &ok ) };
2520 : 0 : if ( ok )
2521 : : {
2522 : 0 : setMinimumScale( minScale );
2523 : 0 : }
2524 : 0 : }
2525 : :
2526 : 0 : if ( categories.testFlag( Rendering ) )
2527 : : {
2528 : 0 : QDomElement e = node.toElement();
2529 : :
2530 : : // get the simplification drawing settings
2531 : 0 : mSimplifyMethod.setSimplifyHints( static_cast< QgsVectorSimplifyMethod::SimplifyHints >( e.attribute( QStringLiteral( "simplifyDrawingHints" ), QStringLiteral( "1" ) ).toInt() ) );
2532 : 0 : mSimplifyMethod.setSimplifyAlgorithm( static_cast< QgsVectorSimplifyMethod::SimplifyAlgorithm >( e.attribute( QStringLiteral( "simplifyAlgorithm" ), QStringLiteral( "0" ) ).toInt() ) );
2533 : 0 : mSimplifyMethod.setThreshold( e.attribute( QStringLiteral( "simplifyDrawingTol" ), QStringLiteral( "1" ) ).toFloat() );
2534 : 0 : mSimplifyMethod.setForceLocalOptimization( e.attribute( QStringLiteral( "simplifyLocal" ), QStringLiteral( "1" ) ).toInt() );
2535 : 0 : mSimplifyMethod.setMaximumScale( e.attribute( QStringLiteral( "simplifyMaxScale" ), QStringLiteral( "1" ) ).toFloat() );
2536 : 0 : }
2537 : :
2538 : : //diagram renderer and diagram layer settings
2539 : 0 : if ( categories.testFlag( Diagrams ) )
2540 : : {
2541 : 0 : delete mDiagramRenderer;
2542 : 0 : mDiagramRenderer = nullptr;
2543 : 0 : QDomElement singleCatDiagramElem = node.firstChildElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) );
2544 : 0 : if ( !singleCatDiagramElem.isNull() )
2545 : : {
2546 : 0 : mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
2547 : 0 : mDiagramRenderer->readXml( singleCatDiagramElem, context );
2548 : 0 : }
2549 : 0 : QDomElement linearDiagramElem = node.firstChildElement( QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) );
2550 : 0 : if ( !linearDiagramElem.isNull() )
2551 : : {
2552 : 0 : if ( linearDiagramElem.hasAttribute( QStringLiteral( "classificationAttribute" ) ) )
2553 : : {
2554 : : // fix project from before QGIS 3.0
2555 : 0 : int idx = linearDiagramElem.attribute( QStringLiteral( "classificationAttribute" ) ).toInt();
2556 : 0 : if ( idx >= 0 && idx < mFields.count() )
2557 : 0 : linearDiagramElem.setAttribute( QStringLiteral( "classificationField" ), mFields.at( idx ).name() );
2558 : 0 : }
2559 : :
2560 : 0 : mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
2561 : 0 : mDiagramRenderer->readXml( linearDiagramElem, context );
2562 : 0 : }
2563 : :
2564 : 0 : if ( mDiagramRenderer )
2565 : : {
2566 : 0 : QDomElement diagramSettingsElem = node.firstChildElement( QStringLiteral( "DiagramLayerSettings" ) );
2567 : 0 : if ( !diagramSettingsElem.isNull() )
2568 : : {
2569 : 0 : bool oldXPos = diagramSettingsElem.hasAttribute( QStringLiteral( "xPosColumn" ) );
2570 : 0 : bool oldYPos = diagramSettingsElem.hasAttribute( QStringLiteral( "yPosColumn" ) );
2571 : 0 : bool oldShow = diagramSettingsElem.hasAttribute( QStringLiteral( "showColumn" ) );
2572 : 0 : if ( oldXPos || oldYPos || oldShow )
2573 : : {
2574 : : // fix project from before QGIS 3.0
2575 : 0 : QgsPropertyCollection ddp;
2576 : 0 : if ( oldXPos )
2577 : : {
2578 : 0 : int xPosColumn = diagramSettingsElem.attribute( QStringLiteral( "xPosColumn" ) ).toInt();
2579 : 0 : if ( xPosColumn >= 0 && xPosColumn < mFields.count() )
2580 : 0 : ddp.setProperty( QgsDiagramLayerSettings::PositionX, QgsProperty::fromField( mFields.at( xPosColumn ).name(), true ) );
2581 : 0 : }
2582 : 0 : if ( oldYPos )
2583 : : {
2584 : 0 : int yPosColumn = diagramSettingsElem.attribute( QStringLiteral( "yPosColumn" ) ).toInt();
2585 : 0 : if ( yPosColumn >= 0 && yPosColumn < mFields.count() )
2586 : 0 : ddp.setProperty( QgsDiagramLayerSettings::PositionY, QgsProperty::fromField( mFields.at( yPosColumn ).name(), true ) );
2587 : 0 : }
2588 : 0 : if ( oldShow )
2589 : : {
2590 : 0 : int showColumn = diagramSettingsElem.attribute( QStringLiteral( "showColumn" ) ).toInt();
2591 : 0 : if ( showColumn >= 0 && showColumn < mFields.count() )
2592 : 0 : ddp.setProperty( QgsDiagramLayerSettings::Show, QgsProperty::fromField( mFields.at( showColumn ).name(), true ) );
2593 : 0 : }
2594 : 0 : QDomElement propertiesElem = diagramSettingsElem.ownerDocument().createElement( QStringLiteral( "properties" ) );
2595 : 0 : QgsPropertiesDefinition defs = QgsPropertiesDefinition
2596 : 0 : {
2597 : 0 : { QgsDiagramLayerSettings::PositionX, QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
2598 : 0 : { QgsDiagramLayerSettings::PositionY, QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
2599 : 0 : { QgsDiagramLayerSettings::Show, QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
2600 : : };
2601 : 0 : ddp.writeXml( propertiesElem, defs );
2602 : 0 : diagramSettingsElem.appendChild( propertiesElem );
2603 : 0 : }
2604 : :
2605 : 0 : delete mDiagramLayerSettings;
2606 : 0 : mDiagramLayerSettings = new QgsDiagramLayerSettings();
2607 : 0 : mDiagramLayerSettings->readXml( diagramSettingsElem );
2608 : 0 : }
2609 : 0 : }
2610 : 0 : }
2611 : : // end diagram
2612 : 0 : }
2613 : 0 : return result;
2614 : 0 : }
2615 : :
2616 : :
2617 : 0 : bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2618 : : const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2619 : : {
2620 : 0 : QDomElement layerElement = node.toElement();
2621 : 0 : writeCommonStyle( layerElement, doc, context, categories );
2622 : :
2623 : 0 : ( void )writeStyle( node, doc, errorMessage, context, categories );
2624 : :
2625 : 0 : if ( categories.testFlag( GeometryOptions ) )
2626 : 0 : mGeometryOptions->writeXml( node );
2627 : :
2628 : 0 : if ( categories.testFlag( Legend ) && legend() )
2629 : : {
2630 : 0 : QDomElement legendElement = legend()->writeXml( doc, context );
2631 : 0 : if ( !legendElement.isNull() )
2632 : 0 : node.appendChild( legendElement );
2633 : 0 : }
2634 : :
2635 : : // Relation information for both referenced and referencing sides
2636 : 0 : if ( categories.testFlag( Relations ) )
2637 : : {
2638 : : // Store referenced layers: relations where "this" is the child layer (the referencing part, that holds the FK)
2639 : 0 : QDomElement referencedLayersElement = doc.createElement( QStringLiteral( "referencedLayers" ) );
2640 : 0 : node.appendChild( referencedLayersElement );
2641 : :
2642 : 0 : const auto constReferencingRelations { QgsProject::instance()->relationManager()->referencingRelations( this ) };
2643 : 0 : for ( const auto &rel : constReferencingRelations )
2644 : : {
2645 : 0 : if ( rel.type() == QgsRelation::Normal )
2646 : : {
2647 : 0 : QgsWeakRelation::writeXml( this, QgsWeakRelation::Referencing, rel, referencedLayersElement, doc );
2648 : 0 : }
2649 : : }
2650 : :
2651 : : // Store referencing layers: relations where "this" is the parent layer (the referenced part, that holds the FK)
2652 : 0 : QDomElement referencingLayersElement = doc.createElement( QStringLiteral( "referencingLayers" ) );
2653 : 0 : node.appendChild( referencedLayersElement );
2654 : :
2655 : 0 : const auto constReferencedRelations { QgsProject::instance()->relationManager()->referencedRelations( this ) };
2656 : 0 : for ( const auto &rel : constReferencedRelations )
2657 : : {
2658 : 0 : if ( rel.type() == QgsRelation::Normal )
2659 : : {
2660 : 0 : QgsWeakRelation::writeXml( this, QgsWeakRelation::Referenced, rel, referencingLayersElement, doc );
2661 : 0 : }
2662 : : }
2663 : :
2664 : 0 : }
2665 : :
2666 : : // write field configurations
2667 : 0 : if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
2668 : : {
2669 : 0 : QDomElement fieldConfigurationElement;
2670 : : // field configuration flag
2671 : 0 : fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
2672 : 0 : node.appendChild( fieldConfigurationElement );
2673 : :
2674 : 0 : for ( const QgsField &field : std::as_const( mFields ) )
2675 : : {
2676 : 0 : QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
2677 : 0 : fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
2678 : 0 : fieldConfigurationElement.appendChild( fieldElement );
2679 : :
2680 : 0 : if ( categories.testFlag( Fields ) )
2681 : : {
2682 : 0 : fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );
2683 : 0 : }
2684 : :
2685 : 0 : if ( categories.testFlag( Forms ) )
2686 : : {
2687 : 0 : QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
2688 : :
2689 : : // TODO : wrap this part in an if to only save if it was user-modified
2690 : 0 : QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
2691 : 0 : fieldElement.appendChild( editWidgetElement );
2692 : 0 : editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
2693 : 0 : QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
2694 : :
2695 : 0 : editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
2696 : 0 : editWidgetElement.appendChild( editWidgetConfigElement );
2697 : : // END TODO : wrap this part in an if to only save if it was user-modified
2698 : 0 : }
2699 : 0 : }
2700 : 0 : }
2701 : :
2702 : 0 : if ( categories.testFlag( Fields ) )
2703 : : {
2704 : : //attribute aliases
2705 : 0 : QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
2706 : 0 : for ( const QgsField &field : std::as_const( mFields ) )
2707 : : {
2708 : 0 : QDomElement aliasEntryElem = doc.createElement( QStringLiteral( "alias" ) );
2709 : 0 : aliasEntryElem.setAttribute( QStringLiteral( "field" ), field.name() );
2710 : 0 : aliasEntryElem.setAttribute( QStringLiteral( "index" ), mFields.indexFromName( field.name() ) );
2711 : 0 : aliasEntryElem.setAttribute( QStringLiteral( "name" ), field.alias() );
2712 : 0 : aliasElem.appendChild( aliasEntryElem );
2713 : 0 : }
2714 : 0 : node.appendChild( aliasElem );
2715 : :
2716 : : //default expressions
2717 : 0 : QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) );
2718 : 0 : for ( const QgsField &field : std::as_const( mFields ) )
2719 : : {
2720 : 0 : QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
2721 : 0 : defaultElem.setAttribute( QStringLiteral( "field" ), field.name() );
2722 : 0 : defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
2723 : 0 : defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
2724 : 0 : defaultsElem.appendChild( defaultElem );
2725 : 0 : }
2726 : 0 : node.appendChild( defaultsElem );
2727 : :
2728 : : // constraints
2729 : 0 : QDomElement constraintsElem = doc.createElement( QStringLiteral( "constraints" ) );
2730 : 0 : for ( const QgsField &field : std::as_const( mFields ) )
2731 : : {
2732 : 0 : QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
2733 : 0 : constraintElem.setAttribute( QStringLiteral( "field" ), field.name() );
2734 : 0 : constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
2735 : 0 : constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
2736 : 0 : constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
2737 : 0 : constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
2738 : 0 : constraintsElem.appendChild( constraintElem );
2739 : 0 : }
2740 : 0 : node.appendChild( constraintsElem );
2741 : :
2742 : : // constraint expressions
2743 : 0 : QDomElement constraintExpressionsElem = doc.createElement( QStringLiteral( "constraintExpressions" ) );
2744 : 0 : for ( const QgsField &field : std::as_const( mFields ) )
2745 : : {
2746 : 0 : QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraint" ) );
2747 : 0 : constraintExpressionElem.setAttribute( QStringLiteral( "field" ), field.name() );
2748 : 0 : constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
2749 : 0 : constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
2750 : 0 : constraintExpressionsElem.appendChild( constraintExpressionElem );
2751 : 0 : }
2752 : 0 : node.appendChild( constraintExpressionsElem );
2753 : :
2754 : : // save expression fields
2755 : 0 : if ( !mExpressionFieldBuffer )
2756 : : {
2757 : : // can happen when saving style on a invalid layer
2758 : 0 : QgsExpressionFieldBuffer dummy;
2759 : 0 : dummy.writeXml( node, doc );
2760 : 0 : }
2761 : : else
2762 : : {
2763 : 0 : mExpressionFieldBuffer->writeXml( node, doc );
2764 : : }
2765 : 0 : }
2766 : :
2767 : : // add attribute actions
2768 : 0 : if ( categories.testFlag( Actions ) )
2769 : 0 : mActions->writeXml( node );
2770 : :
2771 : 0 : if ( categories.testFlag( AttributeTable ) )
2772 : : {
2773 : 0 : mAttributeTableConfig.writeXml( node );
2774 : 0 : mConditionalStyles->writeXml( node, doc, context );
2775 : 0 : mStoredExpressionManager->writeXml( node );
2776 : 0 : }
2777 : :
2778 : 0 : if ( categories.testFlag( Forms ) )
2779 : 0 : mEditFormConfig.writeXml( node, context );
2780 : :
2781 : : // save readonly state
2782 : 0 : if ( categories.testFlag( LayerConfiguration ) )
2783 : 0 : node.toElement().setAttribute( QStringLiteral( "readOnly" ), mReadOnly );
2784 : :
2785 : : // save preview expression
2786 : 0 : if ( categories.testFlag( LayerConfiguration ) )
2787 : : {
2788 : 0 : QDomElement prevExpElem = doc.createElement( QStringLiteral( "previewExpression" ) );
2789 : 0 : QDomText prevExpText = doc.createTextNode( mDisplayExpression );
2790 : 0 : prevExpElem.appendChild( prevExpText );
2791 : 0 : node.appendChild( prevExpElem );
2792 : 0 : }
2793 : :
2794 : : // save map tip
2795 : 0 : if ( categories.testFlag( MapTips ) )
2796 : : {
2797 : 0 : QDomElement mapTipElem = doc.createElement( QStringLiteral( "mapTip" ) );
2798 : 0 : QDomText mapTipText = doc.createTextNode( mMapTipTemplate );
2799 : 0 : mapTipElem.appendChild( mapTipText );
2800 : 0 : node.toElement().appendChild( mapTipElem );
2801 : 0 : }
2802 : :
2803 : : return true;
2804 : 0 : }
2805 : :
2806 : 0 : bool QgsVectorLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage,
2807 : : const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
2808 : : {
2809 : 0 : QDomElement mapLayerNode = node.toElement();
2810 : :
2811 : 0 : emit writeCustomSymbology( mapLayerNode, doc, errorMessage );
2812 : :
2813 : : // we must try to write the renderer if our geometry type is unknown
2814 : : // as this allows the renderer to be correctly restored even for layers
2815 : : // with broken sources
2816 : 0 : if ( isSpatial() || mWkbType == QgsWkbTypes::Unknown )
2817 : : {
2818 : 0 : if ( categories.testFlag( Symbology ) )
2819 : : {
2820 : 0 : if ( mRenderer )
2821 : : {
2822 : 0 : QDomElement rendererElement = mRenderer->save( doc, context );
2823 : 0 : node.appendChild( rendererElement );
2824 : 0 : }
2825 : 0 : }
2826 : :
2827 : 0 : if ( categories.testFlag( Labeling ) )
2828 : : {
2829 : 0 : if ( mLabeling )
2830 : : {
2831 : 0 : QDomElement labelingElement = mLabeling->save( doc, context );
2832 : 0 : node.appendChild( labelingElement );
2833 : 0 : }
2834 : 0 : mapLayerNode.setAttribute( QStringLiteral( "labelsEnabled" ), mLabelsEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
2835 : 0 : }
2836 : :
2837 : : // save the simplification drawing settings
2838 : 0 : if ( categories.testFlag( Rendering ) )
2839 : : {
2840 : 78 : mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingHints" ), QString::number( mSimplifyMethod.simplifyHints() ) );
2841 : 0 : mapLayerNode.setAttribute( QStringLiteral( "simplifyAlgorithm" ), QString::number( mSimplifyMethod.simplifyAlgorithm() ) );
2842 : 0 : mapLayerNode.setAttribute( QStringLiteral( "simplifyDrawingTol" ), QString::number( mSimplifyMethod.threshold() ) );
2843 : 78 : mapLayerNode.setAttribute( QStringLiteral( "simplifyLocal" ), mSimplifyMethod.forceLocalOptimization() ? 1 : 0 );
2844 : 0 : mapLayerNode.setAttribute( QStringLiteral( "simplifyMaxScale" ), QString::number( mSimplifyMethod.maximumScale() ) );
2845 : 0 : }
2846 : :
2847 : : //save customproperties
2848 : 0 : if ( categories.testFlag( CustomProperties ) )
2849 : : {
2850 : 0 : writeCustomProperties( node, doc );
2851 : 0 : }
2852 : :
2853 : 0 : if ( categories.testFlag( Symbology ) )
2854 : 78 : {
2855 : : // add the blend mode field
2856 : 0 : QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
2857 : 78 : QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
2858 : 0 : blendModeElem.appendChild( blendModeText );
2859 : 0 : node.appendChild( blendModeElem );
2860 : :
2861 : : // add the feature blend mode field
2862 : 0 : QDomElement featureBlendModeElem = doc.createElement( QStringLiteral( "featureBlendMode" ) );
2863 : 0 : QDomText featureBlendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( featureBlendMode() ) ) );
2864 : 0 : featureBlendModeElem.appendChild( featureBlendModeText );
2865 : 0 : node.appendChild( featureBlendModeElem );
2866 : 0 : }
2867 : :
2868 : : // add the layer opacity and scale visibility
2869 : 0 : if ( categories.testFlag( Rendering ) )
2870 : : {
2871 : 0 : QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
2872 : 0 : QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
2873 : 0 : layerOpacityElem.appendChild( layerOpacityText );
2874 : 0 : node.appendChild( layerOpacityElem );
2875 : 0 : mapLayerNode.setAttribute( QStringLiteral( "hasScaleBasedVisibilityFlag" ), hasScaleBasedVisibility() ? 1 : 0 );
2876 : 0 : mapLayerNode.setAttribute( QStringLiteral( "maxScale" ), maximumScale() );
2877 : 0 : mapLayerNode.setAttribute( QStringLiteral( "minScale" ), minimumScale() );
2878 : 0 : }
2879 : :
2880 : 0 : if ( categories.testFlag( Diagrams ) && mDiagramRenderer )
2881 : : {
2882 : 0 : mDiagramRenderer->writeXml( mapLayerNode, doc, context );
2883 : 0 : if ( mDiagramLayerSettings )
2884 : 0 : mDiagramLayerSettings->writeXml( mapLayerNode, doc );
2885 : 0 : }
2886 : 0 : }
2887 : : return true;
2888 : 0 : }
2889 : :
2890 : 0 : bool QgsVectorLayer::readSld( const QDomNode &node, QString &errorMessage )
2891 : : {
2892 : : // get the Name element
2893 : 0 : QDomElement nameElem = node.firstChildElement( QStringLiteral( "Name" ) );
2894 : 0 : if ( nameElem.isNull() )
2895 : : {
2896 : 0 : errorMessage = QStringLiteral( "Warning: Name element not found within NamedLayer while it's required." );
2897 : 0 : }
2898 : :
2899 : 78 : if ( isSpatial() )
2900 : : {
2901 : 0 : QgsFeatureRenderer *r = QgsFeatureRenderer::loadSld( node, geometryType(), errorMessage );
2902 : 78 : if ( !r )
2903 : 0 : return false;
2904 : :
2905 : 0 : setRenderer( r );
2906 : :
2907 : : // labeling
2908 : 78 : readSldLabeling( node );
2909 : 0 : }
2910 : 0 : return true;
2911 : 78 : }
2912 : :
2913 : 0 : bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QVariantMap &props ) const
2914 : 78 : {
2915 : 0 : Q_UNUSED( errorMessage )
2916 : :
2917 : 78 : QVariantMap localProps = QVariantMap( props );
2918 : 0 : if ( hasScaleBasedVisibility() )
2919 : : {
2920 : 78 : QgsSymbolLayerUtils::mergeScaleDependencies( maximumScale(), minimumScale(), localProps );
2921 : 0 : }
2922 : :
2923 : 0 : if ( isSpatial() )
2924 : : {
2925 : 78 : // store the Name element
2926 : 0 : QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
2927 : 0 : nameNode.appendChild( doc.createTextNode( name() ) );
2928 : 0 : node.appendChild( nameNode );
2929 : :
2930 : 78 : QDomElement userStyleElem = doc.createElement( QStringLiteral( "UserStyle" ) );
2931 : 0 : node.appendChild( userStyleElem );
2932 : :
2933 : 0 : QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
2934 : 0 : nameElem.appendChild( doc.createTextNode( name() ) );
2935 : :
2936 : 78 : userStyleElem.appendChild( nameElem );
2937 : :
2938 : 0 : QDomElement featureTypeStyleElem = doc.createElement( QStringLiteral( "se:FeatureTypeStyle" ) );
2939 : 78 : userStyleElem.appendChild( featureTypeStyleElem );
2940 : :
2941 : 0 : mRenderer->toSld( doc, featureTypeStyleElem, localProps );
2942 : 78 : if ( labelsEnabled() )
2943 : : {
2944 : 78 : mLabeling->toSld( featureTypeStyleElem, localProps );
2945 : 78 : }
2946 : 0 : }
2947 : : return true;
2948 : 0 : }
2949 : :
2950 : :
2951 : 1 : bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool skipDefaultValue )
2952 : : {
2953 : 1 : if ( !mEditBuffer || !mDataProvider )
2954 : 78 : {
2955 : 0 : return false;
2956 : : }
2957 : :
2958 : 1 : if ( mGeometryOptions->isActive() )
2959 : 0 : mGeometryOptions->apply( geom );
2960 : :
2961 : 79 : updateExtents();
2962 : :
2963 : 1 : bool result = mEditBuffer->changeGeometry( fid, geom );
2964 : :
2965 : 1 : if ( result )
2966 : : {
2967 : 1 : updateExtents();
2968 : 1 : if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
2969 : 0 : updateDefaultValues( fid );
2970 : 1 : }
2971 : 1 : return result;
2972 : 79 : }
2973 : :
2974 : :
2975 : 0 : bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues )
2976 : 78 : {
2977 : 0 : bool result = false;
2978 : :
2979 : 78 : switch ( fields().fieldOrigin( field ) )
2980 : : {
2981 : : case QgsFields::OriginJoin:
2982 : 0 : result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
2983 : 0 : if ( result )
2984 : 78 : emit attributeValueChanged( fid, field, newValue );
2985 : 0 : break;
2986 : :
2987 : : case QgsFields::OriginProvider:
2988 : 78 : case QgsFields::OriginEdit:
2989 : : case QgsFields::OriginExpression:
2990 : : {
2991 : 0 : if ( mEditBuffer && mDataProvider )
2992 : 0 : result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
2993 : 0 : break;
2994 : : }
2995 : :
2996 : : case QgsFields::OriginUnknown:
2997 : 0 : break;
2998 : : }
2999 : :
3000 : 0 : if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3001 : 0 : updateDefaultValues( fid );
3002 : :
3003 : 0 : return result;
3004 : 0 : }
3005 : :
3006 : 0 : bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues, bool skipDefaultValues )
3007 : : {
3008 : 0 : bool result = true;
3009 : :
3010 : 0 : QgsAttributeMap newValuesJoin;
3011 : 0 : QgsAttributeMap oldValuesJoin;
3012 : :
3013 : 0 : QgsAttributeMap newValuesNotJoin;
3014 : 0 : QgsAttributeMap oldValuesNotJoin;
3015 : :
3016 : 0 : for ( auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
3017 : : {
3018 : 0 : const int field = it.key();
3019 : 0 : const QVariant newValue = it.value();
3020 : 0 : QVariant oldValue;
3021 : :
3022 : 0 : if ( oldValues.contains( field ) )
3023 : 0 : oldValue = oldValues[field];
3024 : :
3025 : 0 : switch ( fields().fieldOrigin( field ) )
3026 : : {
3027 : : case QgsFields::OriginJoin:
3028 : 0 : newValuesJoin[field] = newValue;
3029 : 0 : oldValuesJoin[field] = oldValue;
3030 : 0 : break;
3031 : :
3032 : : case QgsFields::OriginProvider:
3033 : : case QgsFields::OriginEdit:
3034 : : case QgsFields::OriginExpression:
3035 : : {
3036 : 0 : newValuesNotJoin[field] = newValue;
3037 : 0 : oldValuesNotJoin[field] = oldValue;
3038 : 0 : break;
3039 : : }
3040 : :
3041 : : case QgsFields::OriginUnknown:
3042 : 0 : break;
3043 : : }
3044 : 0 : }
3045 : :
3046 : 0 : if ( ! newValuesJoin.isEmpty() && mJoinBuffer )
3047 : : {
3048 : 0 : result = mJoinBuffer->changeAttributeValues( fid, newValuesJoin, oldValuesJoin );
3049 : 0 : }
3050 : :
3051 : 0 : if ( ! newValuesNotJoin.isEmpty() && mEditBuffer && mDataProvider )
3052 : : {
3053 : 0 : result &= mEditBuffer->changeAttributeValues( fid, newValuesNotJoin, oldValues );
3054 : 0 : }
3055 : :
3056 : 0 : if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
3057 : : {
3058 : 0 : updateDefaultValues( fid );
3059 : 0 : }
3060 : :
3061 : 0 : return result;
3062 : 0 : }
3063 : :
3064 : 0 : bool QgsVectorLayer::addAttribute( const QgsField &field )
3065 : : {
3066 : 0 : if ( !mEditBuffer || !mDataProvider )
3067 : 0 : return false;
3068 : :
3069 : 0 : return mEditBuffer->addAttribute( field );
3070 : 0 : }
3071 : :
3072 : 0 : void QgsVectorLayer::removeFieldAlias( int attIndex )
3073 : : {
3074 : 0 : if ( attIndex < 0 || attIndex >= fields().count() )
3075 : 0 : return;
3076 : :
3077 : 0 : QString name = fields().at( attIndex ).name();
3078 : 0 : mFields[ attIndex ].setAlias( QString() );
3079 : 0 : if ( mAttributeAliasMap.contains( name ) )
3080 : : {
3081 : 0 : mAttributeAliasMap.remove( name );
3082 : 0 : updateFields();
3083 : 0 : mEditFormConfig.setFields( mFields );
3084 : 0 : emit layerModified();
3085 : 0 : }
3086 : 0 : }
3087 : :
3088 : 0 : bool QgsVectorLayer::renameAttribute( int index, const QString &newName )
3089 : : {
3090 : 0 : if ( index < 0 || index >= fields().count() )
3091 : 0 : return false;
3092 : :
3093 : 0 : switch ( mFields.fieldOrigin( index ) )
3094 : : {
3095 : : case QgsFields::OriginExpression:
3096 : : {
3097 : 0 : if ( mExpressionFieldBuffer )
3098 : : {
3099 : 0 : int oi = mFields.fieldOriginIndex( index );
3100 : 0 : mExpressionFieldBuffer->renameExpression( oi, newName );
3101 : 0 : updateFields();
3102 : 0 : return true;
3103 : : }
3104 : : else
3105 : : {
3106 : 0 : return false;
3107 : : }
3108 : : }
3109 : :
3110 : : case QgsFields::OriginProvider:
3111 : : case QgsFields::OriginEdit:
3112 : :
3113 : 0 : if ( !mEditBuffer || !mDataProvider )
3114 : 0 : return false;
3115 : :
3116 : 0 : return mEditBuffer->renameAttribute( index, newName );
3117 : :
3118 : : case QgsFields::OriginJoin:
3119 : : case QgsFields::OriginUnknown:
3120 : 0 : return false;
3121 : :
3122 : : }
3123 : :
3124 : 0 : return false; // avoid warning
3125 : 0 : }
3126 : :
3127 : 0 : void QgsVectorLayer::setFieldAlias( int attIndex, const QString &aliasString )
3128 : : {
3129 : 0 : if ( attIndex < 0 || attIndex >= fields().count() )
3130 : 0 : return;
3131 : :
3132 : 0 : QString name = fields().at( attIndex ).name();
3133 : :
3134 : 0 : mAttributeAliasMap.insert( name, aliasString );
3135 : 0 : mFields[ attIndex ].setAlias( aliasString );
3136 : 0 : mEditFormConfig.setFields( mFields );
3137 : 0 : emit layerModified(); // TODO[MD]: should have a different signal?
3138 : 0 : }
3139 : :
3140 : 0 : QString QgsVectorLayer::attributeAlias( int index ) const
3141 : : {
3142 : 0 : if ( index < 0 || index >= fields().count() )
3143 : 0 : return QString();
3144 : :
3145 : 0 : return fields().at( index ).alias();
3146 : 0 : }
3147 : :
3148 : 0 : QString QgsVectorLayer::attributeDisplayName( int index ) const
3149 : : {
3150 : 0 : if ( index >= 0 && index < mFields.count() )
3151 : 0 : return mFields.at( index ).displayName();
3152 : : else
3153 : 0 : return QString();
3154 : 0 : }
3155 : :
3156 : 0 : QgsStringMap QgsVectorLayer::attributeAliases() const
3157 : : {
3158 : 0 : return mAttributeAliasMap;
3159 : : }
3160 : :
3161 : 0 : QSet<QString> QgsVectorLayer::excludeAttributesWms() const
3162 : : {
3163 : 0 : QSet<QString> excludeList;
3164 : 0 : QMap< QString, QgsField::ConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3165 : 0 : for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3166 : : {
3167 : 0 : if ( flagsIt->testFlag( QgsField::ConfigurationFlag::HideFromWms ) )
3168 : : {
3169 : 0 : excludeList << flagsIt.key();
3170 : 0 : }
3171 : 0 : }
3172 : 0 : return excludeList;
3173 : 0 : }
3174 : :
3175 : 0 : void QgsVectorLayer::setExcludeAttributesWms( const QSet<QString> &att )
3176 : : {
3177 : 0 : QMap< QString, QgsField::ConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3178 : 0 : for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3179 : : {
3180 : 0 : flagsIt->setFlag( QgsField::ConfigurationFlag::HideFromWms, att.contains( flagsIt.key() ) );
3181 : 0 : }
3182 : 0 : updateFields();
3183 : 0 : }
3184 : :
3185 : 0 : QSet<QString> QgsVectorLayer::excludeAttributesWfs() const
3186 : : {
3187 : 0 : QSet<QString> excludeList;
3188 : 0 : QMap< QString, QgsField::ConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3189 : 0 : for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3190 : : {
3191 : 0 : if ( flagsIt->testFlag( QgsField::ConfigurationFlag::HideFromWfs ) )
3192 : : {
3193 : 0 : excludeList << flagsIt.key();
3194 : 0 : }
3195 : 0 : }
3196 : 0 : return excludeList;
3197 : 0 : }
3198 : :
3199 : 0 : void QgsVectorLayer::setExcludeAttributesWfs( const QSet<QString> &att )
3200 : : {
3201 : 0 : QMap< QString, QgsField::ConfigurationFlags >::iterator flagsIt = mFieldConfigurationFlags.begin();
3202 : 0 : for ( ; flagsIt != mFieldConfigurationFlags.end(); ++flagsIt )
3203 : : {
3204 : 0 : flagsIt->setFlag( QgsField::ConfigurationFlag::HideFromWfs, att.contains( flagsIt.key() ) );
3205 : 0 : }
3206 : 0 : updateFields();
3207 : 0 : }
3208 : :
3209 : 0 : bool QgsVectorLayer::deleteAttribute( int index )
3210 : : {
3211 : 0 : if ( index < 0 || index >= fields().count() )
3212 : 0 : return false;
3213 : :
3214 : 0 : if ( mFields.fieldOrigin( index ) == QgsFields::OriginExpression )
3215 : : {
3216 : 0 : removeExpressionField( index );
3217 : 0 : return true;
3218 : : }
3219 : :
3220 : 0 : if ( !mEditBuffer || !mDataProvider )
3221 : 0 : return false;
3222 : :
3223 : 0 : return mEditBuffer->deleteAttribute( index );
3224 : 0 : }
3225 : :
3226 : 0 : bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
3227 : : {
3228 : 0 : bool deleted = false;
3229 : :
3230 : : // Remove multiple occurrences of same attribute
3231 : 0 : QList<int> attrList = qgis::setToList( qgis::listToSet( attrs ) );
3232 : :
3233 : 0 : std::sort( attrList.begin(), attrList.end(), std::greater<int>() );
3234 : :
3235 : 0 : for ( int attr : std::as_const( attrList ) )
3236 : : {
3237 : 0 : if ( deleteAttribute( attr ) )
3238 : : {
3239 : 0 : deleted = true;
3240 : 0 : }
3241 : : }
3242 : :
3243 : 0 : return deleted;
3244 : 0 : }
3245 : :
3246 : 0 : bool QgsVectorLayer::deleteFeatureCascade( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
3247 : : {
3248 : 0 : if ( !mEditBuffer )
3249 : 0 : return false;
3250 : :
3251 : 0 : if ( context && context->cascade )
3252 : : {
3253 : 0 : const QList<QgsRelation> relations = context->project->relationManager()->referencedRelations( this );
3254 : 0 : const bool hasRelationsOrJoins = !relations.empty() || mJoinBuffer->containsJoins();
3255 : 0 : if ( hasRelationsOrJoins )
3256 : : {
3257 : 0 : if ( context->mHandledFeatures.contains( this ) )
3258 : : {
3259 : 0 : QgsFeatureIds &handledFeatureIds = context->mHandledFeatures[ this ];
3260 : 0 : if ( handledFeatureIds.contains( fid ) )
3261 : : {
3262 : : // avoid endless recursion
3263 : 0 : return false;
3264 : : }
3265 : : else
3266 : : {
3267 : : // add feature id
3268 : 0 : handledFeatureIds << fid;
3269 : : }
3270 : 0 : }
3271 : : else
3272 : : {
3273 : : // add layer and feature id
3274 : 0 : context->mHandledFeatures.insert( this, QgsFeatureIds() << fid );
3275 : : }
3276 : :
3277 : 0 : for ( const QgsRelation &relation : relations )
3278 : : {
3279 : : //check if composition (and not association)
3280 : 0 : if ( relation.strength() == QgsRelation::Composition )
3281 : : {
3282 : : //get features connected over this relation
3283 : 0 : QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
3284 : 0 : QgsFeatureIds childFeatureIds;
3285 : 0 : QgsFeature childFeature;
3286 : 0 : while ( relatedFeaturesIt.nextFeature( childFeature ) )
3287 : : {
3288 : 0 : childFeatureIds.insert( childFeature.id() );
3289 : : }
3290 : 0 : if ( childFeatureIds.count() > 0 )
3291 : : {
3292 : 0 : relation.referencingLayer()->startEditing();
3293 : 0 : relation.referencingLayer()->deleteFeatures( childFeatureIds, context );
3294 : 0 : }
3295 : 0 : }
3296 : : }
3297 : 0 : }
3298 : 0 : }
3299 : :
3300 : 0 : if ( mJoinBuffer->containsJoins() )
3301 : 0 : mJoinBuffer->deleteFeature( fid, context );
3302 : :
3303 : 0 : bool res = mEditBuffer->deleteFeature( fid );
3304 : :
3305 : 0 : return res;
3306 : 0 : }
3307 : :
3308 : 0 : bool QgsVectorLayer::deleteFeature( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context )
3309 : : {
3310 : 0 : if ( !mEditBuffer )
3311 : 0 : return false;
3312 : :
3313 : 0 : bool res = deleteFeatureCascade( fid, context );
3314 : :
3315 : 0 : if ( res )
3316 : : {
3317 : 0 : mSelectedFeatureIds.remove( fid ); // remove it from selection
3318 : 0 : updateExtents();
3319 : 0 : }
3320 : :
3321 : 0 : return res;
3322 : 0 : }
3323 : :
3324 : 0 : bool QgsVectorLayer::deleteFeatures( const QgsFeatureIds &fids, QgsVectorLayer::DeleteContext *context )
3325 : : {
3326 : 0 : bool res = true;
3327 : 0 : const auto constFids = fids;
3328 : 0 : for ( QgsFeatureId fid : constFids )
3329 : 0 : res = deleteFeatureCascade( fid, context ) && res;
3330 : :
3331 : 0 : if ( res )
3332 : : {
3333 : 0 : mSelectedFeatureIds.subtract( fids ); // remove it from selection
3334 : 0 : updateExtents();
3335 : 0 : }
3336 : :
3337 : 0 : return res;
3338 : 0 : }
3339 : :
3340 : 401 : QgsFields QgsVectorLayer::fields() const
3341 : : {
3342 : 401 : return mFields;
3343 : : }
3344 : :
3345 : 0 : QgsAttributeList QgsVectorLayer::primaryKeyAttributes() const
3346 : : {
3347 : 0 : QgsAttributeList pkAttributesList;
3348 : 0 : if ( !mDataProvider )
3349 : 0 : return pkAttributesList;
3350 : :
3351 : 0 : QgsAttributeList providerIndexes = mDataProvider->pkAttributeIndexes();
3352 : 0 : for ( int i = 0; i < mFields.count(); ++i )
3353 : : {
3354 : 0 : if ( mFields.fieldOrigin( i ) == QgsFields::OriginProvider &&
3355 : 0 : providerIndexes.contains( mFields.fieldOriginIndex( i ) ) )
3356 : 0 : pkAttributesList << i;
3357 : 0 : }
3358 : :
3359 : 0 : return pkAttributesList;
3360 : 0 : }
3361 : :
3362 : 2 : long QgsVectorLayer::featureCount() const
3363 : : {
3364 : 2 : if ( ! mDataProvider )
3365 : 0 : return -1;
3366 : 4 : return mDataProvider->featureCount() +
3367 : 2 : ( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures().size() - mEditBuffer->deletedFeatureIds().size() : 0 );
3368 : 2 : }
3369 : :
3370 : 0 : QgsFeatureSource::FeatureAvailability QgsVectorLayer::hasFeatures() const
3371 : : {
3372 : 0 : const QgsFeatureIds deletedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->deletedFeatureIds() : QgsFeatureIds() );
3373 : 0 : const QgsFeatureMap addedFeatures( mEditBuffer && ! mDataProvider->transaction() ? mEditBuffer->addedFeatures() : QgsFeatureMap() );
3374 : :
3375 : 0 : if ( mEditBuffer && !deletedFeatures.empty() )
3376 : : {
3377 : 0 : if ( addedFeatures.size() > deletedFeatures.size() )
3378 : 0 : return QgsFeatureSource::FeatureAvailability::FeaturesAvailable;
3379 : : else
3380 : 0 : return QgsFeatureSource::FeatureAvailability::FeaturesMaybeAvailable;
3381 : : }
3382 : :
3383 : 0 : if ( ( !mEditBuffer || addedFeatures.empty() ) && mDataProvider && mDataProvider->empty() )
3384 : 0 : return QgsFeatureSource::FeatureAvailability::NoFeaturesAvailable;
3385 : : else
3386 : 0 : return QgsFeatureSource::FeatureAvailability::FeaturesAvailable;
3387 : 0 : }
3388 : :
3389 : 0 : bool QgsVectorLayer::commitChanges( bool stopEditing )
3390 : : {
3391 : 0 : mCommitErrors.clear();
3392 : :
3393 : 0 : if ( !mDataProvider )
3394 : : {
3395 : 0 : mCommitErrors << tr( "ERROR: no provider" );
3396 : 0 : return false;
3397 : : }
3398 : :
3399 : 0 : if ( !mEditBuffer )
3400 : : {
3401 : 0 : mCommitErrors << tr( "ERROR: layer not editable" );
3402 : 0 : return false;
3403 : : }
3404 : :
3405 : 0 : emit beforeCommitChanges( stopEditing );
3406 : :
3407 : 0 : if ( !mAllowCommit )
3408 : 0 : return false;
3409 : :
3410 : 0 : bool success = mEditBuffer->commitChanges( mCommitErrors );
3411 : :
3412 : 0 : if ( success )
3413 : : {
3414 : 0 : if ( stopEditing )
3415 : : {
3416 : 0 : delete mEditBuffer;
3417 : 0 : mEditBuffer = nullptr;
3418 : 0 : }
3419 : 0 : undoStack()->clear();
3420 : 0 : emit afterCommitChanges();
3421 : 0 : if ( stopEditing )
3422 : 0 : emit editingStopped();
3423 : 0 : }
3424 : : else
3425 : : {
3426 : 0 : QgsMessageLog::logMessage( tr( "Commit errors:\n %1" ).arg( mCommitErrors.join( QLatin1String( "\n " ) ) ) );
3427 : : }
3428 : :
3429 : 0 : updateFields();
3430 : 0 : mDataProvider->updateExtents();
3431 : :
3432 : 0 : mDataProvider->leaveUpdateMode();
3433 : :
3434 : 0 : triggerRepaint();
3435 : :
3436 : 0 : return success;
3437 : 0 : }
3438 : :
3439 : 0 : QStringList QgsVectorLayer::commitErrors() const
3440 : : {
3441 : 0 : return mCommitErrors;
3442 : : }
3443 : :
3444 : 0 : bool QgsVectorLayer::rollBack( bool deleteBuffer )
3445 : : {
3446 : 0 : if ( !mEditBuffer )
3447 : : {
3448 : 0 : return false;
3449 : : }
3450 : :
3451 : 0 : if ( !mDataProvider )
3452 : : {
3453 : 0 : mCommitErrors << tr( "ERROR: no provider" );
3454 : 0 : return false;
3455 : : }
3456 : :
3457 : 0 : bool rollbackExtent = !mDataProvider->transaction() && ( !mEditBuffer->deletedFeatureIds().isEmpty() ||
3458 : 0 : !mEditBuffer->addedFeatures().isEmpty() ||
3459 : 0 : !mEditBuffer->changedGeometries().isEmpty() );
3460 : :
3461 : 0 : emit beforeRollBack();
3462 : :
3463 : 0 : mEditBuffer->rollBack();
3464 : :
3465 : 0 : emit afterRollBack();
3466 : :
3467 : 0 : if ( isModified() )
3468 : : {
3469 : : // new undo stack roll back method
3470 : : // old method of calling every undo could cause many canvas refreshes
3471 : 0 : undoStack()->setIndex( 0 );
3472 : 0 : }
3473 : :
3474 : 0 : updateFields();
3475 : :
3476 : 0 : if ( deleteBuffer )
3477 : : {
3478 : 0 : delete mEditBuffer;
3479 : 0 : mEditBuffer = nullptr;
3480 : 0 : undoStack()->clear();
3481 : 0 : }
3482 : 0 : emit editingStopped();
3483 : :
3484 : 0 : if ( rollbackExtent )
3485 : 0 : updateExtents();
3486 : :
3487 : 0 : mDataProvider->leaveUpdateMode();
3488 : :
3489 : 0 : triggerRepaint();
3490 : 0 : return true;
3491 : 0 : }
3492 : :
3493 : 0 : int QgsVectorLayer::selectedFeatureCount() const
3494 : : {
3495 : 0 : return mSelectedFeatureIds.size();
3496 : : }
3497 : :
3498 : 0 : const QgsFeatureIds &QgsVectorLayer::selectedFeatureIds() const
3499 : : {
3500 : 0 : return mSelectedFeatureIds;
3501 : : }
3502 : :
3503 : 0 : QgsFeatureList QgsVectorLayer::selectedFeatures() const
3504 : : {
3505 : 0 : QgsFeatureList features;
3506 : 0 : features.reserve( mSelectedFeatureIds.count() );
3507 : 0 : QgsFeature f;
3508 : :
3509 : 0 : if ( mSelectedFeatureIds.count() <= 8 )
3510 : : {
3511 : : // for small amount of selected features, fetch them directly
3512 : : // because request with FilterFids would go iterate over the whole layer
3513 : 0 : const auto constMSelectedFeatureIds = mSelectedFeatureIds;
3514 : 0 : for ( QgsFeatureId fid : constMSelectedFeatureIds )
3515 : : {
3516 : 0 : getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f );
3517 : 0 : features << f;
3518 : : }
3519 : 0 : }
3520 : : else
3521 : : {
3522 : 0 : QgsFeatureIterator it = getSelectedFeatures();
3523 : :
3524 : 0 : while ( it.nextFeature( f ) )
3525 : : {
3526 : 0 : features.push_back( f );
3527 : : }
3528 : 0 : }
3529 : :
3530 : 0 : return features;
3531 : 0 : }
3532 : :
3533 : 0 : QgsFeatureIterator QgsVectorLayer::getSelectedFeatures( QgsFeatureRequest request ) const
3534 : : {
3535 : 0 : if ( mSelectedFeatureIds.isEmpty() )
3536 : 0 : return QgsFeatureIterator();
3537 : :
3538 : 0 : if ( geometryType() == QgsWkbTypes::NullGeometry )
3539 : 0 : request.setFlags( QgsFeatureRequest::NoGeometry );
3540 : :
3541 : 0 : if ( mSelectedFeatureIds.count() == 1 )
3542 : 0 : request.setFilterFid( *mSelectedFeatureIds.constBegin() );
3543 : : else
3544 : 0 : request.setFilterFids( mSelectedFeatureIds );
3545 : :
3546 : 0 : return getFeatures( request );
3547 : 0 : }
3548 : :
3549 : 1 : bool QgsVectorLayer::addFeatures( QgsFeatureList &features, Flags )
3550 : : {
3551 : 1 : if ( !mEditBuffer || !mDataProvider )
3552 : 0 : return false;
3553 : :
3554 : 1 : if ( mGeometryOptions->isActive() )
3555 : : {
3556 : 0 : for ( auto feature = features.begin(); feature != features.end(); ++feature )
3557 : : {
3558 : 0 : QgsGeometry geom = feature->geometry();
3559 : 0 : mGeometryOptions->apply( geom );
3560 : 0 : feature->setGeometry( geom );
3561 : 0 : }
3562 : 0 : }
3563 : :
3564 : 1 : bool res = mEditBuffer->addFeatures( features );
3565 : 1 : updateExtents();
3566 : :
3567 : 1 : if ( res && mJoinBuffer->containsJoins() )
3568 : 0 : res = mJoinBuffer->addFeatures( features );
3569 : :
3570 : 1 : return res;
3571 : 1 : }
3572 : :
3573 : 78 : void QgsVectorLayer::setCoordinateSystem()
3574 : : {
3575 : : // if layer is not spatial, it has not CRS!
3576 : 78 : setCrs( ( isSpatial() && mDataProvider ) ? mDataProvider->crs() : QgsCoordinateReferenceSystem() );
3577 : 78 : }
3578 : :
3579 : 0 : QString QgsVectorLayer::displayField() const
3580 : : {
3581 : 0 : QgsExpression exp( displayExpression() );
3582 : 0 : if ( exp.isField() )
3583 : : {
3584 : 0 : return static_cast<const QgsExpressionNodeColumnRef *>( exp.rootNode() )->name();
3585 : : }
3586 : :
3587 : 0 : return QString();
3588 : 0 : }
3589 : :
3590 : 0 : void QgsVectorLayer::setDisplayExpression( const QString &displayExpression )
3591 : : {
3592 : 0 : if ( mDisplayExpression == displayExpression )
3593 : 0 : return;
3594 : :
3595 : 0 : mDisplayExpression = displayExpression;
3596 : 0 : emit displayExpressionChanged();
3597 : 0 : }
3598 : :
3599 : 0 : QString QgsVectorLayer::displayExpression() const
3600 : : {
3601 : 0 : if ( !mDisplayExpression.isEmpty() || mFields.isEmpty() )
3602 : : {
3603 : 0 : return mDisplayExpression;
3604 : : }
3605 : : else
3606 : : {
3607 : 0 : const QString candidateName = QgsVectorLayerUtils::guessFriendlyIdentifierField( mFields );
3608 : 0 : if ( !candidateName.isEmpty() )
3609 : : {
3610 : 0 : return QgsExpression::quotedColumnRef( candidateName );
3611 : : }
3612 : : else
3613 : : {
3614 : 0 : return QString();
3615 : : }
3616 : 0 : }
3617 : 0 : }
3618 : :
3619 : 1 : bool QgsVectorLayer::isEditable() const
3620 : : {
3621 : 1 : return ( mEditBuffer && mDataProvider );
3622 : : }
3623 : :
3624 : 558 : bool QgsVectorLayer::isSpatial() const
3625 : : {
3626 : 558 : QgsWkbTypes::GeometryType t = geometryType();
3627 : 558 : return t != QgsWkbTypes::NullGeometry && t != QgsWkbTypes::UnknownGeometry;
3628 : : }
3629 : :
3630 : 0 : bool QgsVectorLayer::isReadOnly() const
3631 : : {
3632 : 0 : return mReadOnly;
3633 : : }
3634 : :
3635 : 0 : bool QgsVectorLayer::setReadOnly( bool readonly )
3636 : : {
3637 : : // exit if the layer is in editing mode
3638 : 0 : if ( readonly && mEditBuffer )
3639 : 0 : return false;
3640 : :
3641 : 0 : mReadOnly = readonly;
3642 : 0 : emit readOnlyChanged();
3643 : 0 : return true;
3644 : 0 : }
3645 : :
3646 : 2 : bool QgsVectorLayer::supportsEditing()
3647 : : {
3648 : 2 : if ( ! mDataProvider )
3649 : 0 : return false;
3650 : :
3651 : 2 : return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && ! mReadOnly;
3652 : 2 : }
3653 : :
3654 : 0 : bool QgsVectorLayer::isModified() const
3655 : : {
3656 : 0 : emit beforeModifiedCheck();
3657 : 0 : return mEditBuffer && mEditBuffer->isModified();
3658 : : }
3659 : :
3660 : 0 : bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
3661 : : {
3662 : 0 : bool auxiliaryField = false;
3663 : 0 : srcIndex = -1;
3664 : :
3665 : 0 : if ( !auxiliaryLayer() )
3666 : 0 : return auxiliaryField;
3667 : :
3668 : 0 : if ( index >= 0 && fields().fieldOrigin( index ) == QgsFields::OriginJoin )
3669 : : {
3670 : 0 : const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
3671 : :
3672 : 0 : if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
3673 : 0 : auxiliaryField = true;
3674 : 0 : }
3675 : :
3676 : 0 : return auxiliaryField;
3677 : 0 : }
3678 : :
3679 : 78 : void QgsVectorLayer::setRenderer( QgsFeatureRenderer *r )
3680 : : {
3681 : : // we must allow setting a renderer if our geometry type is unknown
3682 : : // as this allows the renderer to be correctly set even for layers
3683 : : // with broken sources
3684 : 78 : if ( !isSpatial() && mWkbType != QgsWkbTypes::Unknown )
3685 : 0 : return;
3686 : :
3687 : 78 : if ( r != mRenderer )
3688 : : {
3689 : 78 : delete mRenderer;
3690 : 78 : mRenderer = r;
3691 : 78 : mSymbolFeatureCounted = false;
3692 : 78 : mSymbolFeatureCountMap.clear();
3693 : 78 : mSymbolFeatureIdMap.clear();
3694 : :
3695 : 78 : emit rendererChanged();
3696 : 78 : emit styleChanged();
3697 : 78 : }
3698 : 78 : }
3699 : :
3700 : 0 : void QgsVectorLayer::addFeatureRendererGenerator( QgsFeatureRendererGenerator *generator )
3701 : : {
3702 : 0 : mRendererGenerators << generator;
3703 : 0 : }
3704 : :
3705 : 0 : void QgsVectorLayer::removeFeatureRendererGenerator( const QString &id )
3706 : : {
3707 : 0 : for ( int i = mRendererGenerators.count() - 1; i >= 0; --i )
3708 : : {
3709 : 0 : if ( mRendererGenerators.at( i )->id() == id )
3710 : : {
3711 : 0 : delete mRendererGenerators.at( i );
3712 : 0 : mRendererGenerators.removeAt( i );
3713 : 0 : }
3714 : 0 : }
3715 : 0 : }
3716 : :
3717 : 0 : QList<const QgsFeatureRendererGenerator *> QgsVectorLayer::featureRendererGenerators() const
3718 : : {
3719 : 0 : QList< const QgsFeatureRendererGenerator * > res;
3720 : 0 : for ( const QgsFeatureRendererGenerator *generator : mRendererGenerators )
3721 : 0 : res << generator;
3722 : 0 : return res;
3723 : 0 : }
3724 : :
3725 : 0 : void QgsVectorLayer::beginEditCommand( const QString &text )
3726 : : {
3727 : 0 : if ( !mDataProvider )
3728 : : {
3729 : 0 : return;
3730 : : }
3731 : 0 : if ( mDataProvider->transaction() )
3732 : : {
3733 : 0 : QString ignoredError;
3734 : 0 : mDataProvider->transaction()->createSavepoint( ignoredError );
3735 : 0 : }
3736 : 0 : undoStack()->beginMacro( text );
3737 : 0 : mEditCommandActive = true;
3738 : 0 : emit editCommandStarted( text );
3739 : 0 : }
3740 : :
3741 : 0 : void QgsVectorLayer::endEditCommand()
3742 : : {
3743 : 0 : if ( !mDataProvider )
3744 : : {
3745 : 0 : return;
3746 : : }
3747 : 0 : undoStack()->endMacro();
3748 : 0 : mEditCommandActive = false;
3749 : 0 : if ( !mDeletedFids.isEmpty() )
3750 : : {
3751 : 0 : emit featuresDeleted( mDeletedFids );
3752 : 0 : mDeletedFids.clear();
3753 : 0 : }
3754 : 0 : emit editCommandEnded();
3755 : 0 : }
3756 : :
3757 : 0 : void QgsVectorLayer::destroyEditCommand()
3758 : : {
3759 : 0 : if ( !mDataProvider )
3760 : : {
3761 : 0 : return;
3762 : : }
3763 : 0 : undoStack()->endMacro();
3764 : 0 : undoStack()->undo();
3765 : :
3766 : : // it's not directly possible to pop the last command off the stack (the destroyed one)
3767 : : // and delete, so we add a dummy obsolete command to force this to occur.
3768 : : // Pushing the new command deletes the destroyed one, and since the new
3769 : : // command is obsolete it's automatically deleted by the undo stack.
3770 : 0 : std::unique_ptr< QUndoCommand > command = std::make_unique< QUndoCommand >();
3771 : 0 : command->setObsolete( true );
3772 : 0 : undoStack()->push( command.release() );
3773 : :
3774 : 0 : mEditCommandActive = false;
3775 : 0 : mDeletedFids.clear();
3776 : 0 : emit editCommandDestroyed();
3777 : 0 : }
3778 : :
3779 : 0 : bool QgsVectorLayer::addJoin( const QgsVectorLayerJoinInfo &joinInfo )
3780 : : {
3781 : 0 : return mJoinBuffer->addJoin( joinInfo );
3782 : : }
3783 : :
3784 : :
3785 : 0 : bool QgsVectorLayer::removeJoin( const QString &joinLayerId )
3786 : : {
3787 : 0 : return mJoinBuffer->removeJoin( joinLayerId );
3788 : : }
3789 : :
3790 : 0 : const QList< QgsVectorLayerJoinInfo > QgsVectorLayer::vectorJoins() const
3791 : : {
3792 : 0 : return mJoinBuffer->vectorJoins();
3793 : : }
3794 : :
3795 : 0 : int QgsVectorLayer::addExpressionField( const QString &exp, const QgsField &fld )
3796 : : {
3797 : 0 : emit beforeAddingExpressionField( fld.name() );
3798 : 0 : mExpressionFieldBuffer->addExpression( exp, fld );
3799 : 0 : updateFields();
3800 : 0 : int idx = mFields.indexFromName( fld.name() );
3801 : 0 : emit attributeAdded( idx );
3802 : 0 : return idx;
3803 : 0 : }
3804 : :
3805 : 0 : void QgsVectorLayer::removeExpressionField( int index )
3806 : : {
3807 : 0 : emit beforeRemovingExpressionField( index );
3808 : 0 : int oi = mFields.fieldOriginIndex( index );
3809 : 0 : mExpressionFieldBuffer->removeExpression( oi );
3810 : 0 : updateFields();
3811 : 0 : emit attributeDeleted( index );
3812 : 0 : }
3813 : :
3814 : 0 : QString QgsVectorLayer::expressionField( int index ) const
3815 : : {
3816 : 0 : int oi = mFields.fieldOriginIndex( index );
3817 : 0 : if ( oi < 0 || oi >= mExpressionFieldBuffer->expressions().size() )
3818 : 0 : return QString();
3819 : :
3820 : 0 : return mExpressionFieldBuffer->expressions().at( oi ).cachedExpression.expression();
3821 : 0 : }
3822 : :
3823 : 0 : void QgsVectorLayer::updateExpressionField( int index, const QString &exp )
3824 : : {
3825 : 0 : int oi = mFields.fieldOriginIndex( index );
3826 : 0 : mExpressionFieldBuffer->updateExpression( oi, exp );
3827 : 0 : }
3828 : :
3829 : 79 : void QgsVectorLayer::updateFields()
3830 : : {
3831 : 79 : if ( !mDataProvider )
3832 : 0 : return;
3833 : :
3834 : 79 : QgsFields oldFields = mFields;
3835 : :
3836 : 79 : mFields = mDataProvider->fields();
3837 : :
3838 : : // added / removed fields
3839 : 79 : if ( mEditBuffer )
3840 : 1 : mEditBuffer->updateFields( mFields );
3841 : :
3842 : : // joined fields
3843 : 79 : if ( mJoinBuffer->containsJoins() )
3844 : 0 : mJoinBuffer->updateFields( mFields );
3845 : :
3846 : 79 : if ( mExpressionFieldBuffer )
3847 : 79 : mExpressionFieldBuffer->updateFields( mFields );
3848 : :
3849 : : // set aliases and default values
3850 : 79 : QMap< QString, QString >::const_iterator aliasIt = mAttributeAliasMap.constBegin();
3851 : 79 : for ( ; aliasIt != mAttributeAliasMap.constEnd(); ++aliasIt )
3852 : : {
3853 : 0 : int index = mFields.lookupField( aliasIt.key() );
3854 : 0 : if ( index < 0 )
3855 : 0 : continue;
3856 : :
3857 : 0 : mFields[ index ].setAlias( aliasIt.value() );
3858 : 0 : }
3859 : :
3860 : : // Update configuration flags
3861 : 79 : QMap< QString, QgsField::ConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin();
3862 : 79 : for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt )
3863 : : {
3864 : 0 : int index = mFields.lookupField( flagsIt.key() );
3865 : 0 : if ( index < 0 )
3866 : 0 : continue;
3867 : :
3868 : 0 : mFields[index].setConfigurationFlags( flagsIt.value() );
3869 : 0 : }
3870 : :
3871 : : // Update default values
3872 : 79 : mDefaultValueOnUpdateFields.clear();
3873 : 79 : QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
3874 : 79 : for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
3875 : : {
3876 : 0 : int index = mFields.lookupField( defaultIt.key() );
3877 : 0 : if ( index < 0 )
3878 : 0 : continue;
3879 : :
3880 : 0 : mFields[ index ].setDefaultValueDefinition( defaultIt.value() );
3881 : 0 : if ( defaultIt.value().applyOnUpdate() )
3882 : 0 : mDefaultValueOnUpdateFields.insert( index );
3883 : 0 : }
3884 : :
3885 : 79 : QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
3886 : 79 : for ( ; constraintIt != mFieldConstraints.constEnd(); ++constraintIt )
3887 : : {
3888 : 0 : int index = mFields.lookupField( constraintIt.key() );
3889 : 0 : if ( index < 0 )
3890 : 0 : continue;
3891 : :
3892 : 0 : QgsFieldConstraints constraints = mFields.at( index ).constraints();
3893 : :
3894 : : // always keep provider constraints intact
3895 : 0 : if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintNotNull ) )
3896 : 0 : constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginLayer );
3897 : 0 : if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintUnique ) )
3898 : 0 : constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginLayer );
3899 : 0 : if ( !( constraints.constraints() & QgsFieldConstraints::ConstraintExpression ) && ( constraintIt.value() & QgsFieldConstraints::ConstraintExpression ) )
3900 : 0 : constraints.setConstraint( QgsFieldConstraints::ConstraintExpression, QgsFieldConstraints::ConstraintOriginLayer );
3901 : 0 : mFields[ index ].setConstraints( constraints );
3902 : 0 : }
3903 : :
3904 : 79 : QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
3905 : 79 : for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
3906 : : {
3907 : 0 : int index = mFields.lookupField( constraintExpIt.key() );
3908 : 0 : if ( index < 0 )
3909 : 0 : continue;
3910 : :
3911 : 0 : QgsFieldConstraints constraints = mFields.at( index ).constraints();
3912 : :
3913 : : // always keep provider constraints intact
3914 : 0 : if ( constraints.constraintOrigin( QgsFieldConstraints::ConstraintExpression ) == QgsFieldConstraints::ConstraintOriginProvider )
3915 : 0 : continue;
3916 : :
3917 : 0 : constraints.setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
3918 : 0 : mFields[ index ].setConstraints( constraints );
3919 : 0 : }
3920 : :
3921 : 79 : QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator constraintStrengthIt = mFieldConstraintStrength.constBegin();
3922 : 79 : for ( ; constraintStrengthIt != mFieldConstraintStrength.constEnd(); ++constraintStrengthIt )
3923 : : {
3924 : 0 : int index = mFields.lookupField( constraintStrengthIt.key().first );
3925 : 0 : if ( index < 0 )
3926 : 0 : continue;
3927 : :
3928 : 0 : QgsFieldConstraints constraints = mFields.at( index ).constraints();
3929 : :
3930 : : // always keep provider constraints intact
3931 : 0 : if ( constraints.constraintOrigin( QgsFieldConstraints::ConstraintExpression ) == QgsFieldConstraints::ConstraintOriginProvider )
3932 : 0 : continue;
3933 : :
3934 : 0 : constraints.setConstraintStrength( constraintStrengthIt.key().second, constraintStrengthIt.value() );
3935 : 0 : mFields[ index ].setConstraints( constraints );
3936 : 0 : }
3937 : :
3938 : 79 : auto fieldWidgetIterator = mFieldWidgetSetups.constBegin();
3939 : 79 : for ( ; fieldWidgetIterator != mFieldWidgetSetups.constEnd(); ++ fieldWidgetIterator )
3940 : : {
3941 : 0 : int index = mFields.indexOf( fieldWidgetIterator.key() );
3942 : 0 : if ( index < 0 )
3943 : 0 : continue;
3944 : :
3945 : 0 : mFields[index].setEditorWidgetSetup( fieldWidgetIterator.value() );
3946 : 0 : }
3947 : :
3948 : 79 : if ( oldFields != mFields )
3949 : : {
3950 : 64 : emit updatedFields();
3951 : 64 : mEditFormConfig.setFields( mFields );
3952 : 64 : }
3953 : 79 : }
3954 : :
3955 : :
3956 : 0 : QVariant QgsVectorLayer::defaultValue( int index, const QgsFeature &feature, QgsExpressionContext *context ) const
3957 : : {
3958 : 0 : if ( index < 0 || index >= mFields.count() || !mDataProvider )
3959 : 0 : return QVariant();
3960 : :
3961 : 0 : QString expression = mFields.at( index ).defaultValueDefinition().expression();
3962 : 0 : if ( expression.isEmpty() )
3963 : 0 : return mDataProvider->defaultValue( index );
3964 : :
3965 : 0 : QgsExpressionContext *evalContext = context;
3966 : 0 : std::unique_ptr< QgsExpressionContext > tempContext;
3967 : 0 : if ( !evalContext )
3968 : : {
3969 : : // no context passed, so we create a default one
3970 : 0 : tempContext.reset( new QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( this ) ) );
3971 : 0 : evalContext = tempContext.get();
3972 : 0 : }
3973 : :
3974 : 0 : if ( feature.isValid() )
3975 : : {
3976 : 0 : QgsExpressionContextScope *featScope = new QgsExpressionContextScope();
3977 : 0 : featScope->setFeature( feature );
3978 : 0 : featScope->setFields( feature.fields() );
3979 : 0 : evalContext->appendScope( featScope );
3980 : 0 : }
3981 : :
3982 : 0 : QVariant val;
3983 : 0 : QgsExpression exp( expression );
3984 : 0 : exp.prepare( evalContext );
3985 : 0 : if ( exp.hasEvalError() )
3986 : : {
3987 : 0 : QgsLogger::warning( "Error evaluating default value: " + exp.evalErrorString() );
3988 : 0 : }
3989 : : else
3990 : : {
3991 : 0 : val = exp.evaluate( evalContext );
3992 : : }
3993 : :
3994 : 0 : if ( feature.isValid() )
3995 : : {
3996 : 0 : delete evalContext->popScope();
3997 : 0 : }
3998 : :
3999 : 0 : return val;
4000 : 0 : }
4001 : :
4002 : 0 : void QgsVectorLayer::setDefaultValueDefinition( int index, const QgsDefaultValue &definition )
4003 : : {
4004 : 0 : if ( index < 0 || index >= mFields.count() )
4005 : 0 : return;
4006 : :
4007 : 0 : if ( definition.isValid() )
4008 : : {
4009 : 0 : mDefaultExpressionMap.insert( mFields.at( index ).name(), definition );
4010 : 0 : }
4011 : : else
4012 : : {
4013 : 0 : mDefaultExpressionMap.remove( mFields.at( index ).name() );
4014 : : }
4015 : 0 : updateFields();
4016 : 0 : }
4017 : :
4018 : 0 : QgsDefaultValue QgsVectorLayer::defaultValueDefinition( int index ) const
4019 : : {
4020 : 0 : if ( index < 0 || index >= mFields.count() )
4021 : 0 : return QgsDefaultValue();
4022 : : else
4023 : 0 : return mFields.at( index ).defaultValueDefinition();
4024 : 0 : }
4025 : :
4026 : 0 : QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
4027 : : {
4028 : 0 : QSet<QVariant> uniqueValues;
4029 : 0 : if ( !mDataProvider )
4030 : : {
4031 : 0 : return uniqueValues;
4032 : : }
4033 : :
4034 : 0 : QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4035 : 0 : switch ( origin )
4036 : : {
4037 : : case QgsFields::OriginUnknown:
4038 : 0 : return uniqueValues;
4039 : :
4040 : : case QgsFields::OriginProvider: //a provider field
4041 : : {
4042 : 0 : uniqueValues = mDataProvider->uniqueValues( index, limit );
4043 : :
4044 : 0 : if ( mEditBuffer && ! mDataProvider->transaction() )
4045 : : {
4046 : 0 : QSet<QString> vals;
4047 : 0 : const auto constUniqueValues = uniqueValues;
4048 : 0 : for ( const QVariant &v : constUniqueValues )
4049 : : {
4050 : 0 : vals << v.toString();
4051 : : }
4052 : :
4053 : 0 : QgsFeatureMap added = mEditBuffer->addedFeatures();
4054 : 0 : QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4055 : 0 : while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4056 : : {
4057 : 0 : addedIt.next();
4058 : 0 : QVariant v = addedIt.value().attribute( index );
4059 : 0 : if ( v.isValid() )
4060 : : {
4061 : 0 : QString vs = v.toString();
4062 : 0 : if ( !vals.contains( vs ) )
4063 : : {
4064 : 0 : vals << vs;
4065 : 0 : uniqueValues << v;
4066 : 0 : }
4067 : 0 : }
4068 : 0 : }
4069 : :
4070 : 0 : QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4071 : 0 : while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
4072 : : {
4073 : 0 : it.next();
4074 : 0 : QVariant v = it.value().value( index );
4075 : 0 : if ( v.isValid() )
4076 : : {
4077 : 0 : QString vs = v.toString();
4078 : 0 : if ( !vals.contains( vs ) )
4079 : : {
4080 : 0 : vals << vs;
4081 : 0 : uniqueValues << v;
4082 : 0 : }
4083 : 0 : }
4084 : 0 : }
4085 : 0 : }
4086 : :
4087 : 0 : return uniqueValues;
4088 : : }
4089 : :
4090 : : case QgsFields::OriginEdit:
4091 : : // the layer is editable, but in certain cases it can still be avoided going through all features
4092 : 0 : if ( mDataProvider->transaction() || (
4093 : 0 : mEditBuffer->deletedFeatureIds().isEmpty() &&
4094 : 0 : mEditBuffer->addedFeatures().isEmpty() &&
4095 : 0 : !mEditBuffer->deletedAttributeIds().contains( index ) &&
4096 : 0 : mEditBuffer->changedAttributeValues().isEmpty() ) )
4097 : : {
4098 : 0 : uniqueValues = mDataProvider->uniqueValues( index, limit );
4099 : 0 : return uniqueValues;
4100 : : }
4101 : : FALLTHROUGH
4102 : : //we need to go through each feature
4103 : : case QgsFields::OriginJoin:
4104 : : case QgsFields::OriginExpression:
4105 : : {
4106 : 0 : QgsAttributeList attList;
4107 : 0 : attList << index;
4108 : :
4109 : 0 : QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
4110 : 0 : .setFlags( QgsFeatureRequest::NoGeometry )
4111 : 0 : .setSubsetOfAttributes( attList ) );
4112 : :
4113 : 0 : QgsFeature f;
4114 : 0 : QVariant currentValue;
4115 : 0 : QHash<QString, QVariant> val;
4116 : 0 : while ( fit.nextFeature( f ) )
4117 : : {
4118 : 0 : currentValue = f.attribute( index );
4119 : 0 : val.insert( currentValue.toString(), currentValue );
4120 : 0 : if ( limit >= 0 && val.size() >= limit )
4121 : : {
4122 : 0 : break;
4123 : : }
4124 : : }
4125 : :
4126 : 0 : return qgis::listToSet( val.values() );
4127 : 0 : }
4128 : : }
4129 : :
4130 : : Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
4131 : 0 : return uniqueValues;
4132 : 0 : }
4133 : :
4134 : 0 : QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
4135 : : {
4136 : 0 : QStringList results;
4137 : 0 : if ( !mDataProvider )
4138 : : {
4139 : 0 : return results;
4140 : : }
4141 : :
4142 : 0 : QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4143 : 0 : switch ( origin )
4144 : : {
4145 : : case QgsFields::OriginUnknown:
4146 : 0 : return results;
4147 : :
4148 : : case QgsFields::OriginProvider: //a provider field
4149 : : {
4150 : 0 : results = mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4151 : :
4152 : 0 : if ( mEditBuffer && ! mDataProvider->transaction() )
4153 : : {
4154 : 0 : QgsFeatureMap added = mEditBuffer->addedFeatures();
4155 : 0 : QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4156 : 0 : while ( addedIt.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4157 : : {
4158 : 0 : addedIt.next();
4159 : 0 : QVariant v = addedIt.value().attribute( index );
4160 : 0 : if ( v.isValid() )
4161 : : {
4162 : 0 : QString vs = v.toString();
4163 : 0 : if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4164 : : {
4165 : 0 : results << vs;
4166 : 0 : }
4167 : 0 : }
4168 : 0 : }
4169 : :
4170 : 0 : QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4171 : 0 : while ( it.hasNext() && ( limit < 0 || results.count() < limit ) && ( !feedback || !feedback->isCanceled() ) )
4172 : : {
4173 : 0 : it.next();
4174 : 0 : QVariant v = it.value().value( index );
4175 : 0 : if ( v.isValid() )
4176 : : {
4177 : 0 : QString vs = v.toString();
4178 : 0 : if ( vs.contains( substring, Qt::CaseInsensitive ) && !results.contains( vs ) )
4179 : : {
4180 : 0 : results << vs;
4181 : 0 : }
4182 : 0 : }
4183 : 0 : }
4184 : 0 : }
4185 : :
4186 : 0 : return results;
4187 : : }
4188 : :
4189 : : case QgsFields::OriginEdit:
4190 : : // the layer is editable, but in certain cases it can still be avoided going through all features
4191 : 0 : if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4192 : 0 : mEditBuffer->addedFeatures().isEmpty() &&
4193 : 0 : !mEditBuffer->deletedAttributeIds().contains( index ) &&
4194 : 0 : mEditBuffer->changedAttributeValues().isEmpty() ) )
4195 : : {
4196 : 0 : return mDataProvider->uniqueStringsMatching( index, substring, limit, feedback );
4197 : : }
4198 : : FALLTHROUGH
4199 : : //we need to go through each feature
4200 : : case QgsFields::OriginJoin:
4201 : : case QgsFields::OriginExpression:
4202 : : {
4203 : 0 : QgsAttributeList attList;
4204 : 0 : attList << index;
4205 : :
4206 : 0 : QgsFeatureRequest request;
4207 : 0 : request.setSubsetOfAttributes( attList );
4208 : 0 : request.setFlags( QgsFeatureRequest::NoGeometry );
4209 : 0 : QString fieldName = mFields.at( index ).name();
4210 : 0 : request.setFilterExpression( QStringLiteral( "\"%1\" ILIKE '%%2%'" ).arg( fieldName, substring ) );
4211 : 0 : QgsFeatureIterator fit = getFeatures( request );
4212 : :
4213 : 0 : QgsFeature f;
4214 : 0 : QString currentValue;
4215 : 0 : while ( fit.nextFeature( f ) )
4216 : : {
4217 : 0 : currentValue = f.attribute( index ).toString();
4218 : 0 : if ( !results.contains( currentValue ) )
4219 : 0 : results << currentValue;
4220 : :
4221 : 0 : if ( ( limit >= 0 && results.size() >= limit ) || ( feedback && feedback->isCanceled() ) )
4222 : : {
4223 : 0 : break;
4224 : : }
4225 : : }
4226 : :
4227 : 0 : return results;
4228 : 0 : }
4229 : : }
4230 : :
4231 : : Q_ASSERT_X( false, "QgsVectorLayer::uniqueStringsMatching()", "Unknown source of the field!" );
4232 : 0 : return results;
4233 : 0 : }
4234 : :
4235 : 0 : QVariant QgsVectorLayer::minimumValue( int index ) const
4236 : : {
4237 : 0 : return minimumOrMaximumValue( index, true );
4238 : : }
4239 : :
4240 : 0 : QVariant QgsVectorLayer::maximumValue( int index ) const
4241 : : {
4242 : 0 : return minimumOrMaximumValue( index, false );
4243 : : }
4244 : :
4245 : 0 : QVariant QgsVectorLayer::minimumOrMaximumValue( int index, bool minimum ) const
4246 : : {
4247 : 0 : if ( !mDataProvider )
4248 : : {
4249 : 0 : return QVariant();
4250 : : }
4251 : :
4252 : 0 : QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
4253 : :
4254 : 0 : switch ( origin )
4255 : : {
4256 : : case QgsFields::OriginUnknown:
4257 : 0 : return QVariant();
4258 : :
4259 : : case QgsFields::OriginProvider: //a provider field
4260 : : {
4261 : 0 : QVariant val = minimum ? mDataProvider->minimumValue( index ) : mDataProvider->maximumValue( index );
4262 : 0 : if ( mEditBuffer && ! mDataProvider->transaction() )
4263 : : {
4264 : 0 : QgsFeatureMap added = mEditBuffer->addedFeatures();
4265 : 0 : QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
4266 : 0 : while ( addedIt.hasNext() )
4267 : : {
4268 : 0 : addedIt.next();
4269 : 0 : QVariant v = addedIt.value().attribute( index );
4270 : 0 : if ( ( v.isValid() && minimum && qgsVariantLessThan( v, val ) )
4271 : 0 : || ( v.isValid() && !minimum && qgsVariantGreaterThan( v, val ) ) )
4272 : : {
4273 : 0 : val = v;
4274 : 0 : }
4275 : 0 : }
4276 : :
4277 : 0 : QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
4278 : 0 : while ( it.hasNext() )
4279 : : {
4280 : 0 : it.next();
4281 : 0 : QVariant v = it.value().value( index );
4282 : 0 : if ( ( v.isValid() && minimum && qgsVariantLessThan( v, val ) )
4283 : 0 : || ( v.isValid() && !minimum && qgsVariantGreaterThan( v, val ) ) )
4284 : : {
4285 : 0 : val = v;
4286 : 0 : }
4287 : 0 : }
4288 : 0 : }
4289 : 0 : return val;
4290 : 0 : }
4291 : :
4292 : : case QgsFields::OriginEdit:
4293 : : {
4294 : : // the layer is editable, but in certain cases it can still be avoided going through all features
4295 : 0 : if ( mDataProvider->transaction() || ( mEditBuffer->deletedFeatureIds().isEmpty() &&
4296 : 0 : mEditBuffer->addedFeatures().isEmpty() &&
4297 : 0 : !mEditBuffer->deletedAttributeIds().contains( index ) &&
4298 : 0 : mEditBuffer->changedAttributeValues().isEmpty() ) )
4299 : : {
4300 : 0 : return minimum ? mDataProvider->minimumValue( index ) : mDataProvider->maximumValue( index );
4301 : : }
4302 : 0 : }
4303 : : FALLTHROUGH
4304 : : // no choice but to go through all features
4305 : : case QgsFields::OriginExpression:
4306 : : case QgsFields::OriginJoin:
4307 : : {
4308 : : // we need to go through each feature
4309 : 0 : QgsAttributeList attList;
4310 : 0 : attList << index;
4311 : :
4312 : 0 : QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
4313 : 0 : .setFlags( QgsFeatureRequest::NoGeometry )
4314 : 0 : .setSubsetOfAttributes( attList ) );
4315 : :
4316 : 0 : QgsFeature f;
4317 : 0 : QVariant value;
4318 : 0 : QVariant currentValue;
4319 : 0 : bool firstValue = true;
4320 : 0 : while ( fit.nextFeature( f ) )
4321 : : {
4322 : 0 : currentValue = f.attribute( index );
4323 : 0 : if ( currentValue.isNull() )
4324 : 0 : continue;
4325 : 0 : if ( firstValue )
4326 : : {
4327 : 0 : value = currentValue;
4328 : 0 : firstValue = false;
4329 : 0 : }
4330 : : else
4331 : : {
4332 : 0 : if ( ( minimum && qgsVariantLessThan( currentValue, value ) ) || ( !minimum && qgsVariantGreaterThan( currentValue, value ) ) )
4333 : : {
4334 : 0 : value = currentValue;
4335 : 0 : }
4336 : : }
4337 : : }
4338 : 0 : return value;
4339 : 0 : }
4340 : : }
4341 : :
4342 : : Q_ASSERT_X( false, "QgsVectorLayer::minimumOrMaximum()", "Unknown source of the field!" );
4343 : 0 : return QVariant();
4344 : 0 : }
4345 : :
4346 : 0 : QVariant QgsVectorLayer::aggregate( QgsAggregateCalculator::Aggregate aggregate, const QString &fieldOrExpression,
4347 : : const QgsAggregateCalculator::AggregateParameters ¶meters, QgsExpressionContext *context,
4348 : : bool *ok, QgsFeatureIds *fids ) const
4349 : : {
4350 : 0 : if ( ok )
4351 : 0 : *ok = false;
4352 : :
4353 : 0 : if ( !mDataProvider )
4354 : : {
4355 : 0 : return QVariant();
4356 : : }
4357 : :
4358 : : // test if we are calculating based on a field
4359 : 0 : int attrIndex = mFields.lookupField( fieldOrExpression );
4360 : 0 : if ( attrIndex >= 0 )
4361 : : {
4362 : : // aggregate is based on a field - if it's a provider field, we could possibly hand over the calculation
4363 : : // to the provider itself
4364 : 0 : QgsFields::FieldOrigin origin = mFields.fieldOrigin( attrIndex );
4365 : 0 : if ( origin == QgsFields::OriginProvider )
4366 : : {
4367 : 0 : bool providerOk = false;
4368 : 0 : QVariant val = mDataProvider->aggregate( aggregate, attrIndex, parameters, context, providerOk, fids );
4369 : 0 : if ( providerOk )
4370 : : {
4371 : : // provider handled calculation
4372 : 0 : if ( ok )
4373 : 0 : *ok = true;
4374 : 0 : return val;
4375 : : }
4376 : 0 : }
4377 : 0 : }
4378 : :
4379 : : // fallback to using aggregate calculator to determine aggregate
4380 : 0 : QgsAggregateCalculator c( this );
4381 : 0 : if ( fids )
4382 : 0 : c.setFidsFilter( *fids );
4383 : 0 : c.setParameters( parameters );
4384 : 0 : return c.calculate( aggregate, fieldOrExpression, context, ok );
4385 : 0 : }
4386 : :
4387 : 0 : void QgsVectorLayer::setFeatureBlendMode( QPainter::CompositionMode featureBlendMode )
4388 : : {
4389 : 0 : if ( mFeatureBlendMode == featureBlendMode )
4390 : 0 : return;
4391 : :
4392 : 0 : mFeatureBlendMode = featureBlendMode;
4393 : 0 : emit featureBlendModeChanged( featureBlendMode );
4394 : 0 : emit styleChanged();
4395 : 0 : }
4396 : :
4397 : 0 : QPainter::CompositionMode QgsVectorLayer::featureBlendMode() const
4398 : : {
4399 : 0 : return mFeatureBlendMode;
4400 : : }
4401 : :
4402 : 0 : void QgsVectorLayer::readSldLabeling( const QDomNode &node )
4403 : : {
4404 : 0 : setLabeling( nullptr ); // start with no labeling
4405 : 0 : setLabelsEnabled( false );
4406 : :
4407 : 0 : QDomElement element = node.toElement();
4408 : 0 : if ( element.isNull() )
4409 : 0 : return;
4410 : :
4411 : 0 : QDomElement userStyleElem = element.firstChildElement( QStringLiteral( "UserStyle" ) );
4412 : 0 : if ( userStyleElem.isNull() )
4413 : : {
4414 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: UserStyle element not found." ), 4 );
4415 : 0 : return;
4416 : : }
4417 : :
4418 : 0 : QDomElement featTypeStyleElem = userStyleElem.firstChildElement( QStringLiteral( "FeatureTypeStyle" ) );
4419 : 0 : if ( featTypeStyleElem.isNull() )
4420 : : {
4421 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: FeatureTypeStyle element not found." ), 4 );
4422 : 0 : return;
4423 : : }
4424 : :
4425 : : // create empty FeatureTypeStyle element to merge TextSymbolizer's Rule's from all FeatureTypeStyle's
4426 : 0 : QDomElement mergedFeatTypeStyle = featTypeStyleElem.cloneNode( false ).toElement();
4427 : :
4428 : : // use the RuleRenderer when more rules are present or the rule
4429 : : // has filters or min/max scale denominators set,
4430 : : // otherwise use the Simple labeling
4431 : 0 : bool needRuleBasedLabeling = false;
4432 : 0 : int ruleCount = 0;
4433 : :
4434 : 0 : while ( !featTypeStyleElem.isNull() )
4435 : : {
4436 : 0 : QDomElement ruleElem = featTypeStyleElem.firstChildElement( QStringLiteral( "Rule" ) );
4437 : 0 : while ( !ruleElem.isNull() )
4438 : : {
4439 : : // test rule children element to check if we need to create RuleRenderer
4440 : : // and if the rule has a symbolizer
4441 : 0 : bool hasTextSymbolizer = false;
4442 : 0 : bool hasRuleBased = false;
4443 : 0 : QDomElement ruleChildElem = ruleElem.firstChildElement();
4444 : 0 : while ( !ruleChildElem.isNull() )
4445 : : {
4446 : : // rule has filter or min/max scale denominator, use the RuleRenderer
4447 : 0 : if ( ruleChildElem.localName() == QLatin1String( "Filter" ) ||
4448 : 0 : ruleChildElem.localName() == QLatin1String( "MinScaleDenominator" ) ||
4449 : 0 : ruleChildElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
4450 : : {
4451 : 0 : hasRuleBased = true;
4452 : 0 : }
4453 : : // rule has a renderer symbolizer, not a text symbolizer
4454 : 0 : else if ( ruleChildElem.localName() == QLatin1String( "TextSymbolizer" ) )
4455 : : {
4456 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: TextSymbolizer element found" ), 4 );
4457 : 0 : hasTextSymbolizer = true;
4458 : 0 : }
4459 : :
4460 : 0 : ruleChildElem = ruleChildElem.nextSiblingElement();
4461 : : }
4462 : :
4463 : 0 : if ( hasTextSymbolizer )
4464 : : {
4465 : 0 : ruleCount++;
4466 : :
4467 : : // append a clone of all Rules to the merged FeatureTypeStyle element
4468 : 0 : mergedFeatTypeStyle.appendChild( ruleElem.cloneNode().toElement() );
4469 : :
4470 : 0 : if ( hasRuleBased )
4471 : : {
4472 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: Filter or Min/MaxScaleDenominator element found: need a RuleBasedLabeling" ), 4 );
4473 : 0 : needRuleBasedLabeling = true;
4474 : 0 : }
4475 : 0 : }
4476 : :
4477 : : // more rules present, use the RuleRenderer
4478 : 0 : if ( ruleCount > 1 )
4479 : : {
4480 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: More Rule elements found: need a RuleBasedLabeling" ), 4 );
4481 : 0 : needRuleBasedLabeling = true;
4482 : 0 : }
4483 : :
4484 : : // not use the rule based labeling if no rules with textSymbolizer
4485 : 0 : if ( ruleCount == 0 )
4486 : : {
4487 : 0 : needRuleBasedLabeling = false;
4488 : 0 : }
4489 : :
4490 : 0 : ruleElem = ruleElem.nextSiblingElement( QStringLiteral( "Rule" ) );
4491 : 0 : }
4492 : 0 : featTypeStyleElem = featTypeStyleElem.nextSiblingElement( QStringLiteral( "FeatureTypeStyle" ) );
4493 : 0 : }
4494 : :
4495 : 0 : if ( ruleCount == 0 )
4496 : : {
4497 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: No TextSymbolizer element." ), 4 );
4498 : 0 : return;
4499 : : }
4500 : :
4501 : 0 : QDomElement ruleElem = mergedFeatTypeStyle.firstChildElement( QStringLiteral( "Rule" ) );
4502 : :
4503 : 0 : if ( needRuleBasedLabeling )
4504 : : {
4505 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: rule based labeling" ), 4 );
4506 : 0 : QgsRuleBasedLabeling::Rule *rootRule = new QgsRuleBasedLabeling::Rule( nullptr );
4507 : 0 : while ( !ruleElem.isNull() )
4508 : : {
4509 : :
4510 : 0 : QString label, description, filterExp;
4511 : 0 : int scaleMinDenom = 0, scaleMaxDenom = 0;
4512 : 0 : QgsPalLayerSettings settings;
4513 : :
4514 : : // retrieve the Rule element child nodes
4515 : 0 : QDomElement childElem = ruleElem.firstChildElement();
4516 : 0 : while ( !childElem.isNull() )
4517 : : {
4518 : 0 : if ( childElem.localName() == QLatin1String( "Name" ) )
4519 : : {
4520 : : // <se:Name> tag contains the rule identifier,
4521 : : // so prefer title tag for the label property value
4522 : 0 : if ( label.isEmpty() )
4523 : 0 : label = childElem.firstChild().nodeValue();
4524 : 0 : }
4525 : 0 : else if ( childElem.localName() == QLatin1String( "Description" ) )
4526 : : {
4527 : : // <se:Description> can contains a title and an abstract
4528 : 0 : QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
4529 : 0 : if ( !titleElem.isNull() )
4530 : : {
4531 : 0 : label = titleElem.firstChild().nodeValue();
4532 : 0 : }
4533 : :
4534 : 0 : QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
4535 : 0 : if ( !abstractElem.isNull() )
4536 : : {
4537 : 0 : description = abstractElem.firstChild().nodeValue();
4538 : 0 : }
4539 : 0 : }
4540 : 0 : else if ( childElem.localName() == QLatin1String( "Abstract" ) )
4541 : : {
4542 : : // <sld:Abstract> (v1.0)
4543 : 0 : description = childElem.firstChild().nodeValue();
4544 : 0 : }
4545 : 0 : else if ( childElem.localName() == QLatin1String( "Title" ) )
4546 : : {
4547 : : // <sld:Title> (v1.0)
4548 : 0 : label = childElem.firstChild().nodeValue();
4549 : 0 : }
4550 : 0 : else if ( childElem.localName() == QLatin1String( "Filter" ) )
4551 : : {
4552 : 0 : QgsExpression *filter = QgsOgcUtils::expressionFromOgcFilter( childElem );
4553 : 0 : if ( filter )
4554 : : {
4555 : 0 : if ( filter->hasParserError() )
4556 : : {
4557 : 0 : QgsDebugMsgLevel( QStringLiteral( "SLD Filter parsing error: %1" ).arg( filter->parserErrorString() ), 3 );
4558 : 0 : }
4559 : : else
4560 : : {
4561 : 0 : filterExp = filter->expression();
4562 : : }
4563 : 0 : delete filter;
4564 : 0 : }
4565 : 0 : }
4566 : 0 : else if ( childElem.localName() == QLatin1String( "MinScaleDenominator" ) )
4567 : : {
4568 : : bool ok;
4569 : 0 : int v = childElem.firstChild().nodeValue().toInt( &ok );
4570 : 0 : if ( ok )
4571 : 0 : scaleMinDenom = v;
4572 : 0 : }
4573 : 0 : else if ( childElem.localName() == QLatin1String( "MaxScaleDenominator" ) )
4574 : : {
4575 : : bool ok;
4576 : 0 : int v = childElem.firstChild().nodeValue().toInt( &ok );
4577 : 0 : if ( ok )
4578 : 0 : scaleMaxDenom = v;
4579 : 0 : }
4580 : 0 : else if ( childElem.localName() == QLatin1String( "TextSymbolizer" ) )
4581 : : {
4582 : 0 : readSldTextSymbolizer( childElem, settings );
4583 : 0 : }
4584 : :
4585 : 0 : childElem = childElem.nextSiblingElement();
4586 : : }
4587 : :
4588 : 0 : QgsRuleBasedLabeling::Rule *ruleLabeling = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( settings ), scaleMinDenom, scaleMaxDenom, filterExp, label );
4589 : 0 : rootRule->appendChild( ruleLabeling );
4590 : :
4591 : 0 : ruleElem = ruleElem.nextSiblingElement();
4592 : 0 : }
4593 : :
4594 : 0 : setLabeling( new QgsRuleBasedLabeling( rootRule ) );
4595 : 0 : setLabelsEnabled( true );
4596 : 0 : }
4597 : : else
4598 : : {
4599 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: simple labeling" ), 4 );
4600 : : // retrieve the TextSymbolizer element child node
4601 : 0 : QDomElement textSymbolizerElem = ruleElem.firstChildElement( QStringLiteral( "TextSymbolizer" ) );
4602 : 0 : QgsPalLayerSettings s;
4603 : 0 : if ( readSldTextSymbolizer( textSymbolizerElem, s ) )
4604 : : {
4605 : 0 : setLabeling( new QgsVectorLayerSimpleLabeling( s ) );
4606 : 0 : setLabelsEnabled( true );
4607 : 0 : }
4608 : 0 : }
4609 : 0 : }
4610 : :
4611 : 0 : bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSettings &settings ) const
4612 : : {
4613 : 0 : if ( node.localName() != QLatin1String( "TextSymbolizer" ) )
4614 : : {
4615 : 0 : QgsDebugMsgLevel( QStringLiteral( "Not a TextSymbolizer element: %1" ).arg( node.localName() ), 3 );
4616 : 0 : return false;
4617 : : }
4618 : 0 : QDomElement textSymbolizerElem = node.toElement();
4619 : : // Label
4620 : 0 : QDomElement labelElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Label" ) );
4621 : 0 : if ( !labelElem.isNull() )
4622 : : {
4623 : 0 : QDomElement propertyNameElem = labelElem.firstChildElement( QStringLiteral( "PropertyName" ) );
4624 : 0 : if ( !propertyNameElem.isNull() )
4625 : : {
4626 : : // set labeling defaults
4627 : :
4628 : : // label attribute
4629 : 0 : QString labelAttribute = propertyNameElem.text();
4630 : 0 : settings.fieldName = labelAttribute;
4631 : 0 : settings.isExpression = false;
4632 : :
4633 : 0 : int fieldIndex = mFields.lookupField( labelAttribute );
4634 : 0 : if ( fieldIndex == -1 )
4635 : : {
4636 : : // label attribute is not in columns, check if it is an expression
4637 : 0 : QgsExpression exp( labelAttribute );
4638 : 0 : if ( !exp.hasEvalError() )
4639 : : {
4640 : 0 : settings.isExpression = true;
4641 : 0 : }
4642 : : else
4643 : : {
4644 : 0 : QgsDebugMsgLevel( QStringLiteral( "SLD label attribute error: %1" ).arg( exp.evalErrorString() ), 3 );
4645 : : }
4646 : 0 : }
4647 : 0 : }
4648 : : else
4649 : : {
4650 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: PropertyName element not found." ), 4 );
4651 : 0 : return false;
4652 : : }
4653 : 0 : }
4654 : : else
4655 : : {
4656 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: Label element not found." ), 4 );
4657 : 0 : return false;
4658 : : }
4659 : :
4660 : 0 : QgsUnitTypes::RenderUnit sldUnitSize = QgsUnitTypes::RenderPixels;
4661 : 0 : if ( textSymbolizerElem.hasAttribute( QStringLiteral( "uom" ) ) )
4662 : : {
4663 : 0 : sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( textSymbolizerElem.attribute( QStringLiteral( "uom" ) ) );
4664 : 0 : }
4665 : :
4666 : 0 : QString fontFamily = QStringLiteral( "Sans-Serif" );
4667 : 0 : int fontPointSize = 10;
4668 : 0 : QgsUnitTypes::RenderUnit fontUnitSize = QgsUnitTypes::RenderPoints;
4669 : 0 : int fontWeight = -1;
4670 : 0 : bool fontItalic = false;
4671 : 0 : bool fontUnderline = false;
4672 : :
4673 : : // Font
4674 : 0 : QDomElement fontElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Font" ) );
4675 : 0 : if ( !fontElem.isNull() )
4676 : : {
4677 : 0 : QgsStringMap fontSvgParams = QgsSymbolLayerUtils::getSvgParameterList( fontElem );
4678 : 0 : for ( QgsStringMap::iterator it = fontSvgParams.begin(); it != fontSvgParams.end(); ++it )
4679 : : {
4680 : 0 : QgsDebugMsgLevel( QStringLiteral( "found fontSvgParams %1: %2" ).arg( it.key(), it.value() ), 4 );
4681 : :
4682 : 0 : if ( it.key() == QLatin1String( "font-family" ) )
4683 : : {
4684 : 0 : fontFamily = it.value();
4685 : 0 : }
4686 : 0 : else if ( it.key() == QLatin1String( "font-style" ) )
4687 : : {
4688 : 0 : fontItalic = ( it.value() == QLatin1String( "italic" ) ) || ( it.value() == QLatin1String( "Italic" ) );
4689 : 0 : }
4690 : 0 : else if ( it.key() == QLatin1String( "font-size" ) )
4691 : : {
4692 : : bool ok;
4693 : 0 : int fontSize = it.value().toInt( &ok );
4694 : 0 : if ( ok )
4695 : : {
4696 : 0 : fontPointSize = fontSize;
4697 : 0 : fontUnitSize = sldUnitSize;
4698 : 0 : }
4699 : 0 : }
4700 : 0 : else if ( it.key() == QLatin1String( "font-weight" ) )
4701 : : {
4702 : 0 : if ( ( it.value() == QLatin1String( "bold" ) ) || ( it.value() == QLatin1String( "Bold" ) ) )
4703 : 0 : fontWeight = QFont::Bold;
4704 : 0 : }
4705 : 0 : else if ( it.key() == QLatin1String( "font-underline" ) )
4706 : : {
4707 : 0 : fontUnderline = ( it.value() == QLatin1String( "underline" ) ) || ( it.value() == QLatin1String( "Underline" ) );
4708 : 0 : }
4709 : 0 : }
4710 : 0 : }
4711 : :
4712 : 0 : QgsTextFormat format;
4713 : 0 : QFont font( fontFamily, fontPointSize, fontWeight, fontItalic );
4714 : 0 : font.setUnderline( fontUnderline );
4715 : 0 : format.setFont( font );
4716 : 0 : format.setSize( fontPointSize );
4717 : 0 : format.setSizeUnit( fontUnitSize );
4718 : :
4719 : : // Fill
4720 : 0 : QDomElement fillElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Fill" ) );
4721 : 0 : QColor textColor;
4722 : 0 : Qt::BrushStyle textBrush = Qt::SolidPattern;
4723 : 0 : QgsSymbolLayerUtils::fillFromSld( fillElem, textBrush, textColor );
4724 : 0 : if ( textColor.isValid() )
4725 : : {
4726 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: textColor %1." ).arg( QVariant( textColor ).toString() ), 4 );
4727 : 0 : format.setColor( textColor );
4728 : 0 : }
4729 : :
4730 : 0 : QgsTextBufferSettings bufferSettings;
4731 : :
4732 : : // Halo
4733 : 0 : QDomElement haloElem = textSymbolizerElem.firstChildElement( QStringLiteral( "Halo" ) );
4734 : 0 : if ( !haloElem.isNull() )
4735 : : {
4736 : 0 : bufferSettings.setEnabled( true );
4737 : 0 : bufferSettings.setSize( 1 );
4738 : :
4739 : 0 : QDomElement radiusElem = haloElem.firstChildElement( QStringLiteral( "Radius" ) );
4740 : 0 : if ( !radiusElem.isNull() )
4741 : : {
4742 : : bool ok;
4743 : 0 : double bufferSize = radiusElem.text().toDouble( &ok );
4744 : 0 : if ( ok )
4745 : : {
4746 : 0 : bufferSettings.setSize( bufferSize );
4747 : 0 : bufferSettings.setSizeUnit( sldUnitSize );
4748 : 0 : }
4749 : 0 : }
4750 : :
4751 : 0 : QDomElement haloFillElem = haloElem.firstChildElement( QStringLiteral( "Fill" ) );
4752 : 0 : QColor bufferColor;
4753 : 0 : Qt::BrushStyle bufferBrush = Qt::SolidPattern;
4754 : 0 : QgsSymbolLayerUtils::fillFromSld( haloFillElem, bufferBrush, bufferColor );
4755 : 0 : if ( bufferColor.isValid() )
4756 : : {
4757 : 0 : QgsDebugMsgLevel( QStringLiteral( "Info: bufferColor %1." ).arg( QVariant( bufferColor ).toString() ), 4 );
4758 : 0 : bufferSettings.setColor( bufferColor );
4759 : 0 : }
4760 : 0 : }
4761 : :
4762 : : // LabelPlacement
4763 : 0 : QDomElement labelPlacementElem = textSymbolizerElem.firstChildElement( QStringLiteral( "LabelPlacement" ) );
4764 : 0 : if ( !labelPlacementElem.isNull() )
4765 : : {
4766 : : // PointPlacement
4767 : 0 : QDomElement pointPlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "PointPlacement" ) );
4768 : 0 : if ( !pointPlacementElem.isNull() )
4769 : : {
4770 : 0 : settings.placement = QgsPalLayerSettings::OverPoint;
4771 : 0 : if ( geometryType() == QgsWkbTypes::LineGeometry )
4772 : : {
4773 : 0 : settings.placement = QgsPalLayerSettings::Horizontal;
4774 : 0 : }
4775 : :
4776 : 0 : QDomElement displacementElem = pointPlacementElem.firstChildElement( QStringLiteral( "Displacement" ) );
4777 : 0 : if ( !displacementElem.isNull() )
4778 : : {
4779 : 0 : QDomElement displacementXElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementX" ) );
4780 : 0 : if ( !displacementXElem.isNull() )
4781 : : {
4782 : : bool ok;
4783 : 0 : double xOffset = displacementXElem.text().toDouble( &ok );
4784 : 0 : if ( ok )
4785 : : {
4786 : 0 : settings.xOffset = xOffset;
4787 : 0 : settings.offsetUnits = sldUnitSize;
4788 : 0 : }
4789 : 0 : }
4790 : 0 : QDomElement displacementYElem = displacementElem.firstChildElement( QStringLiteral( "DisplacementY" ) );
4791 : 0 : if ( !displacementYElem.isNull() )
4792 : : {
4793 : : bool ok;
4794 : 0 : double yOffset = displacementYElem.text().toDouble( &ok );
4795 : 0 : if ( ok )
4796 : : {
4797 : 0 : settings.yOffset = yOffset;
4798 : 0 : settings.offsetUnits = sldUnitSize;
4799 : 0 : }
4800 : 0 : }
4801 : 0 : }
4802 : 0 : QDomElement anchorPointElem = pointPlacementElem.firstChildElement( QStringLiteral( "AnchorPoint" ) );
4803 : 0 : if ( !anchorPointElem.isNull() )
4804 : : {
4805 : 0 : QDomElement anchorPointXElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointX" ) );
4806 : 0 : if ( !anchorPointXElem.isNull() )
4807 : : {
4808 : : bool ok;
4809 : 0 : double xOffset = anchorPointXElem.text().toDouble( &ok );
4810 : 0 : if ( ok )
4811 : : {
4812 : 0 : settings.xOffset = xOffset;
4813 : 0 : settings.offsetUnits = sldUnitSize;
4814 : 0 : }
4815 : 0 : }
4816 : 0 : QDomElement anchorPointYElem = anchorPointElem.firstChildElement( QStringLiteral( "AnchorPointY" ) );
4817 : 0 : if ( !anchorPointYElem.isNull() )
4818 : : {
4819 : : bool ok;
4820 : 0 : double yOffset = anchorPointYElem.text().toDouble( &ok );
4821 : 0 : if ( ok )
4822 : : {
4823 : 0 : settings.yOffset = yOffset;
4824 : 0 : settings.offsetUnits = sldUnitSize;
4825 : 0 : }
4826 : 0 : }
4827 : 0 : }
4828 : :
4829 : 0 : QDomElement rotationElem = pointPlacementElem.firstChildElement( QStringLiteral( "Rotation" ) );
4830 : 0 : if ( !rotationElem.isNull() )
4831 : : {
4832 : : bool ok;
4833 : 0 : double rotation = rotationElem.text().toDouble( &ok );
4834 : 0 : if ( ok )
4835 : : {
4836 : 0 : settings.angleOffset = 360 - rotation;
4837 : 0 : }
4838 : 0 : }
4839 : 0 : }
4840 : : else
4841 : : {
4842 : : // PointPlacement
4843 : 0 : QDomElement linePlacementElem = labelPlacementElem.firstChildElement( QStringLiteral( "LinePlacement" ) );
4844 : 0 : if ( !linePlacementElem.isNull() )
4845 : : {
4846 : 0 : settings.placement = QgsPalLayerSettings::Line;
4847 : 0 : }
4848 : 0 : }
4849 : 0 : }
4850 : :
4851 : : // read vendor options
4852 : 0 : QgsStringMap vendorOptions;
4853 : 0 : QDomElement vendorOptionElem = textSymbolizerElem.firstChildElement( QStringLiteral( "VendorOption" ) );
4854 : 0 : while ( !vendorOptionElem.isNull() && vendorOptionElem.localName() == QLatin1String( "VendorOption" ) )
4855 : : {
4856 : 0 : QString optionName = vendorOptionElem.attribute( QStringLiteral( "name" ) );
4857 : 0 : QString optionValue;
4858 : 0 : if ( vendorOptionElem.firstChild().nodeType() == QDomNode::TextNode )
4859 : : {
4860 : 0 : optionValue = vendorOptionElem.firstChild().nodeValue();
4861 : 0 : }
4862 : : else
4863 : : {
4864 : 0 : if ( vendorOptionElem.firstChild().nodeType() == QDomNode::ElementNode &&
4865 : 0 : vendorOptionElem.firstChild().localName() == QLatin1String( "Literal" ) )
4866 : : {
4867 : 0 : QgsDebugMsg( vendorOptionElem.firstChild().localName() );
4868 : 0 : optionValue = vendorOptionElem.firstChild().firstChild().nodeValue();
4869 : 0 : }
4870 : : else
4871 : : {
4872 : 0 : QgsDebugMsg( QStringLiteral( "unexpected child of %1 named %2" ).arg( vendorOptionElem.localName(), optionName ) );
4873 : : }
4874 : : }
4875 : :
4876 : 0 : if ( !optionName.isEmpty() && !optionValue.isEmpty() )
4877 : : {
4878 : 0 : vendorOptions[ optionName ] = optionValue;
4879 : 0 : }
4880 : :
4881 : 0 : vendorOptionElem = vendorOptionElem.nextSiblingElement();
4882 : 0 : }
4883 : 0 : if ( !vendorOptions.isEmpty() )
4884 : : {
4885 : 0 : for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
4886 : : {
4887 : 0 : if ( it.key() == QLatin1String( "underlineText" ) && it.value() == QLatin1String( "true" ) )
4888 : : {
4889 : 0 : font.setUnderline( true );
4890 : 0 : format.setFont( font );
4891 : 0 : }
4892 : 0 : else if ( it.key() == QLatin1String( "strikethroughText" ) && it.value() == QLatin1String( "true" ) )
4893 : : {
4894 : 0 : font.setStrikeOut( true );
4895 : 0 : format.setFont( font );
4896 : 0 : }
4897 : 0 : else if ( it.key() == QLatin1String( "maxDisplacement" ) )
4898 : : {
4899 : 0 : settings.placement = QgsPalLayerSettings::AroundPoint;
4900 : 0 : }
4901 : 0 : else if ( it.key() == QLatin1String( "followLine" ) && it.value() == QLatin1String( "true" ) )
4902 : : {
4903 : 0 : if ( geometryType() == QgsWkbTypes::PolygonGeometry )
4904 : : {
4905 : 0 : settings.placement = QgsPalLayerSettings::PerimeterCurved;
4906 : 0 : }
4907 : : else
4908 : : {
4909 : 0 : settings.placement = QgsPalLayerSettings::Curved;
4910 : : }
4911 : 0 : }
4912 : 0 : else if ( it.key() == QLatin1String( "maxAngleDelta" ) )
4913 : : {
4914 : : bool ok;
4915 : 0 : double angle = it.value().toDouble( &ok );
4916 : 0 : if ( ok )
4917 : : {
4918 : 0 : settings.maxCurvedCharAngleIn = angle;
4919 : 0 : settings.maxCurvedCharAngleOut = angle;
4920 : 0 : }
4921 : 0 : }
4922 : : // miscellaneous options
4923 : 0 : else if ( it.key() == QLatin1String( "conflictResolution" ) && it.value() == QLatin1String( "false" ) )
4924 : : {
4925 : 0 : settings.displayAll = true;
4926 : 0 : }
4927 : 0 : else if ( it.key() == QLatin1String( "forceLeftToRight" ) && it.value() == QLatin1String( "false" ) )
4928 : : {
4929 : 0 : settings.upsidedownLabels = QgsPalLayerSettings::ShowAll;
4930 : 0 : }
4931 : 0 : else if ( it.key() == QLatin1String( "group" ) && it.value() == QLatin1String( "yes" ) )
4932 : : {
4933 : 0 : settings.lineSettings().setMergeLines( true );
4934 : 0 : }
4935 : 0 : else if ( it.key() == QLatin1String( "labelAllGroup" ) && it.value() == QLatin1String( "true" ) )
4936 : : {
4937 : 0 : settings.lineSettings().setMergeLines( true );
4938 : 0 : }
4939 : 0 : }
4940 : 0 : }
4941 : :
4942 : 0 : format.setBuffer( bufferSettings );
4943 : 0 : settings.setFormat( format );
4944 : 0 : return true;
4945 : 0 : }
4946 : :
4947 : 0 : QgsEditFormConfig QgsVectorLayer::editFormConfig() const
4948 : : {
4949 : 0 : return mEditFormConfig;
4950 : : }
4951 : :
4952 : 0 : void QgsVectorLayer::setEditFormConfig( const QgsEditFormConfig &editFormConfig )
4953 : : {
4954 : 0 : if ( mEditFormConfig == editFormConfig )
4955 : 0 : return;
4956 : :
4957 : 0 : mEditFormConfig = editFormConfig;
4958 : 0 : mEditFormConfig.onRelationsLoaded();
4959 : 0 : emit editFormConfigChanged();
4960 : 0 : }
4961 : :
4962 : 0 : QString QgsVectorLayer::mapTipTemplate() const
4963 : : {
4964 : 0 : return mMapTipTemplate;
4965 : : }
4966 : :
4967 : 0 : void QgsVectorLayer::setMapTipTemplate( const QString &mapTip )
4968 : : {
4969 : 0 : if ( mMapTipTemplate == mapTip )
4970 : 0 : return;
4971 : :
4972 : 0 : mMapTipTemplate = mapTip;
4973 : 0 : emit mapTipTemplateChanged();
4974 : 0 : }
4975 : :
4976 : 0 : QgsAttributeTableConfig QgsVectorLayer::attributeTableConfig() const
4977 : : {
4978 : 0 : QgsAttributeTableConfig config = mAttributeTableConfig;
4979 : :
4980 : 0 : if ( config.isEmpty() )
4981 : 0 : config.update( fields() );
4982 : :
4983 : 0 : return config;
4984 : 0 : }
4985 : :
4986 : 0 : void QgsVectorLayer::setAttributeTableConfig( const QgsAttributeTableConfig &attributeTableConfig )
4987 : : {
4988 : 0 : if ( mAttributeTableConfig != attributeTableConfig )
4989 : : {
4990 : 0 : mAttributeTableConfig = attributeTableConfig;
4991 : 0 : emit configChanged();
4992 : 0 : }
4993 : 0 : }
4994 : :
4995 : 0 : QgsExpressionContext QgsVectorLayer::createExpressionContext() const
4996 : : {
4997 : 0 : return QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( this ) );
4998 : 0 : }
4999 : :
5000 : 0 : QgsExpressionContextScope *QgsVectorLayer::createExpressionContextScope() const
5001 : : {
5002 : 0 : return QgsExpressionContextUtils::layerScope( this );
5003 : : }
5004 : :
5005 : 0 : void QgsVectorLayer::setDiagramLayerSettings( const QgsDiagramLayerSettings &s )
5006 : : {
5007 : 0 : if ( !mDiagramLayerSettings )
5008 : 0 : mDiagramLayerSettings = new QgsDiagramLayerSettings();
5009 : 0 : *mDiagramLayerSettings = s;
5010 : 0 : }
5011 : :
5012 : 0 : QString QgsVectorLayer::htmlMetadata() const
5013 : : {
5014 : 0 : QgsLayerMetadataFormatter htmlFormatter( metadata() );
5015 : 0 : QString myMetadata = QStringLiteral( "<html>\n<body>\n" );
5016 : :
5017 : : // Begin Provider section
5018 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Information from provider" ) + QStringLiteral( "</h1>\n<hr>\n" );
5019 : 0 : myMetadata += QLatin1String( "<table class=\"list-view\">\n" );
5020 : :
5021 : : // name
5022 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
5023 : :
5024 : : // local path
5025 : 0 : QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( mProviderKey, publicSource() );
5026 : 0 : QString path;
5027 : 0 : bool isLocalPath = false;
5028 : 0 : if ( uriComponents.contains( QStringLiteral( "path" ) ) )
5029 : : {
5030 : 0 : path = uriComponents[QStringLiteral( "path" )].toString();
5031 : 0 : if ( QFile::exists( path ) )
5032 : : {
5033 : 0 : isLocalPath = true;
5034 : 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" );
5035 : 0 : }
5036 : 0 : }
5037 : 0 : if ( uriComponents.contains( QStringLiteral( "url" ) ) )
5038 : : {
5039 : 0 : const QString url = uriComponents[QStringLiteral( "url" )].toString();
5040 : 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" );
5041 : 0 : }
5042 : :
5043 : : // data source
5044 : 0 : if ( publicSource() != path || !isLocalPath )
5045 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "</td></tr>\n" );
5046 : :
5047 : : // storage type
5048 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Storage" ) + QStringLiteral( "</td><td>" ) + storageType() + QStringLiteral( "</td></tr>\n" );
5049 : :
5050 : : // comment
5051 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Comment" ) + QStringLiteral( "</td><td>" ) + dataComment() + QStringLiteral( "</td></tr>\n" );
5052 : :
5053 : : // encoding
5054 : 0 : const QgsVectorDataProvider *provider = dataProvider();
5055 : 0 : if ( provider )
5056 : : {
5057 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Encoding" ) + QStringLiteral( "</td><td>" ) + provider->encoding() + QStringLiteral( "</td></tr>\n" );
5058 : 0 : }
5059 : :
5060 : 0 : if ( isSpatial() )
5061 : : {
5062 : : // geom type
5063 : 0 : QgsWkbTypes::GeometryType type = geometryType();
5064 : 0 : if ( type < 0 || type > QgsWkbTypes::NullGeometry )
5065 : : {
5066 : 0 : QgsDebugMsgLevel( QStringLiteral( "Invalid vector type" ), 2 );
5067 : 0 : }
5068 : : else
5069 : : {
5070 : 0 : QString typeString( QStringLiteral( "%1 (%2)" ).arg( QgsWkbTypes::geometryDisplayString( geometryType() ),
5071 : 0 : QgsWkbTypes::displayString( wkbType() ) ) );
5072 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Geometry" ) + QStringLiteral( "</td><td>" ) + typeString + QStringLiteral( "</td></tr>\n" );
5073 : 0 : }
5074 : :
5075 : : // EPSG
5076 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "CRS" ) + QStringLiteral( "</td><td>" );
5077 : 0 : if ( crs().isValid() )
5078 : : {
5079 : 0 : myMetadata += crs().userFriendlyIdentifier( QgsCoordinateReferenceSystem::FullString ) + QStringLiteral( " - " );
5080 : 0 : if ( crs().isGeographic() )
5081 : 0 : myMetadata += tr( "Geographic" );
5082 : : else
5083 : 0 : myMetadata += tr( "Projected" );
5084 : 0 : }
5085 : 0 : myMetadata += QLatin1String( "</td></tr>\n" );
5086 : :
5087 : : // Extent
5088 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
5089 : :
5090 : : // unit
5091 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Unit" ) + QStringLiteral( "</td><td>" ) + QgsUnitTypes::toString( crs().mapUnits() ) + QStringLiteral( "</td></tr>\n" );
5092 : :
5093 : 0 : }
5094 : :
5095 : : // feature count
5096 : 0 : QLocale locale = QLocale();
5097 : 0 : locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
5098 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" )
5099 : 0 : + tr( "Feature count" ) + QStringLiteral( "</td><td>" )
5100 : 0 : + ( featureCount() == -1 ? tr( "unknown" ) : locale.toString( static_cast<qlonglong>( featureCount() ) ) )
5101 : 0 : + QStringLiteral( "</td></tr>\n" );
5102 : :
5103 : : // End Provider section
5104 : 0 : myMetadata += QLatin1String( "</table>\n<br><br>" );
5105 : :
5106 : : // identification section
5107 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Identification" ) + QStringLiteral( "</h1>\n<hr>\n" );
5108 : 0 : myMetadata += htmlFormatter.identificationSectionHtml( );
5109 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
5110 : :
5111 : : // extent section
5112 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Extent" ) + QStringLiteral( "</h1>\n<hr>\n" );
5113 : 0 : myMetadata += htmlFormatter.extentSectionHtml( isSpatial() );
5114 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
5115 : :
5116 : : // Start the Access section
5117 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Access" ) + QStringLiteral( "</h1>\n<hr>\n" );
5118 : 0 : myMetadata += htmlFormatter.accessSectionHtml( );
5119 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
5120 : :
5121 : : // Fields section
5122 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Fields" ) + QStringLiteral( "</h1>\n<hr>\n<table class=\"list-view\">\n" );
5123 : :
5124 : : // primary key
5125 : 0 : QgsAttributeList pkAttrList = primaryKeyAttributes();
5126 : 0 : if ( !pkAttrList.isEmpty() )
5127 : : {
5128 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Primary key attributes" ) + QStringLiteral( "</td><td>" );
5129 : 0 : const auto constPkAttrList = pkAttrList;
5130 : 0 : for ( int idx : constPkAttrList )
5131 : : {
5132 : 0 : myMetadata += fields().at( idx ).name() + ' ';
5133 : : }
5134 : 0 : myMetadata += QLatin1String( "</td></tr>\n" );
5135 : 0 : }
5136 : :
5137 : 0 : const QgsFields myFields = fields();
5138 : :
5139 : : // count fields
5140 : 0 : myMetadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Count" ) + QStringLiteral( "</td><td>" ) + QString::number( myFields.size() ) + QStringLiteral( "</td></tr>\n" );
5141 : :
5142 : 0 : myMetadata += QLatin1String( "</table>\n<br><table width=\"100%\" class=\"tabular-view\">\n" );
5143 : 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" );
5144 : :
5145 : 0 : for ( int i = 0; i < myFields.size(); ++i )
5146 : : {
5147 : 0 : QgsField myField = myFields.at( i );
5148 : 0 : QString rowClass;
5149 : 0 : if ( i % 2 )
5150 : 0 : rowClass = QStringLiteral( "class=\"odd-row\"" );
5151 : 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" );
5152 : 0 : }
5153 : :
5154 : : //close field list
5155 : 0 : myMetadata += QLatin1String( "</table>\n<br><br>" );
5156 : :
5157 : : // Start the contacts section
5158 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Contacts" ) + QStringLiteral( "</h1>\n<hr>\n" );
5159 : 0 : myMetadata += htmlFormatter.contactsSectionHtml( );
5160 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
5161 : :
5162 : : // Start the links section
5163 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "Links" ) + QStringLiteral( "</h1>\n<hr>\n" );
5164 : 0 : myMetadata += htmlFormatter.linksSectionHtml( );
5165 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
5166 : :
5167 : : // Start the history section
5168 : 0 : myMetadata += QStringLiteral( "<h1>" ) + tr( "History" ) + QStringLiteral( "</h1>\n<hr>\n" );
5169 : 0 : myMetadata += htmlFormatter.historySectionHtml( );
5170 : 0 : myMetadata += QLatin1String( "<br><br>\n" );
5171 : :
5172 : 0 : myMetadata += QLatin1String( "\n</body>\n</html>\n" );
5173 : 0 : return myMetadata;
5174 : 0 : }
5175 : :
5176 : 2 : void QgsVectorLayer::invalidateSymbolCountedFlag()
5177 : : {
5178 : 2 : mSymbolFeatureCounted = false;
5179 : 2 : }
5180 : :
5181 : 0 : void QgsVectorLayer::onFeatureCounterCompleted()
5182 : : {
5183 : 0 : onSymbolsCounted();
5184 : 0 : mFeatureCounter = nullptr;
5185 : 0 : }
5186 : :
5187 : 0 : void QgsVectorLayer::onFeatureCounterTerminated()
5188 : : {
5189 : 0 : mFeatureCounter = nullptr;
5190 : 0 : }
5191 : :
5192 : 0 : void QgsVectorLayer::onJoinedFieldsChanged()
5193 : : {
5194 : : // some of the fields of joined layers have changed -> we need to update this layer's fields too
5195 : 0 : updateFields();
5196 : 0 : }
5197 : :
5198 : 0 : void QgsVectorLayer::onFeatureDeleted( QgsFeatureId fid )
5199 : : {
5200 : 0 : if ( mEditCommandActive )
5201 : 0 : mDeletedFids << fid;
5202 : : else
5203 : 0 : emit featuresDeleted( QgsFeatureIds() << fid );
5204 : :
5205 : 0 : emit featureDeleted( fid );
5206 : 0 : }
5207 : :
5208 : 0 : void QgsVectorLayer::onRelationsLoaded()
5209 : : {
5210 : 0 : mEditFormConfig.onRelationsLoaded();
5211 : 0 : }
5212 : :
5213 : 0 : void QgsVectorLayer::onSymbolsCounted()
5214 : : {
5215 : 0 : if ( mFeatureCounter )
5216 : : {
5217 : 0 : mSymbolFeatureCounted = true;
5218 : 0 : mSymbolFeatureCountMap = mFeatureCounter->symbolFeatureCountMap();
5219 : 0 : mSymbolFeatureIdMap = mFeatureCounter->symbolFeatureIdMap();
5220 : 0 : emit symbolFeatureCountMapChanged();
5221 : 0 : }
5222 : 0 : }
5223 : :
5224 : 0 : QList<QgsRelation> QgsVectorLayer::referencingRelations( int idx ) const
5225 : : {
5226 : 0 : return QgsProject::instance()->relationManager()->referencingRelations( this, idx );
5227 : : }
5228 : :
5229 : 0 : QList<QgsWeakRelation> QgsVectorLayer::weakRelations() const
5230 : : {
5231 : 0 : return mWeakRelations;
5232 : : }
5233 : :
5234 : 0 : int QgsVectorLayer::listStylesInDatabase( QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError )
5235 : : {
5236 : 0 : return QgsProviderRegistry::instance()->listStyles( mProviderKey, mDataSource, ids, names, descriptions, msgError );
5237 : 0 : }
5238 : :
5239 : 0 : QString QgsVectorLayer::getStyleFromDatabase( const QString &styleId, QString &msgError )
5240 : : {
5241 : 0 : return QgsProviderRegistry::instance()->getStyleById( mProviderKey, mDataSource, styleId, msgError );
5242 : 0 : }
5243 : :
5244 : 0 : bool QgsVectorLayer::deleteStyleFromDatabase( const QString &styleId, QString &msgError )
5245 : : {
5246 : 0 : return QgsProviderRegistry::instance()->deleteStyleById( mProviderKey, mDataSource, styleId, msgError );
5247 : 0 : }
5248 : :
5249 : :
5250 : 0 : void QgsVectorLayer::saveStyleToDatabase( const QString &name, const QString &description,
5251 : : bool useAsDefault, const QString &uiFileContent, QString &msgError )
5252 : : {
5253 : :
5254 : 0 : QString sldStyle, qmlStyle;
5255 : 0 : QDomDocument qmlDocument, sldDocument;
5256 : 0 : QgsReadWriteContext context;
5257 : 0 : exportNamedStyle( qmlDocument, msgError, context );
5258 : 0 : if ( !msgError.isNull() )
5259 : : {
5260 : 0 : return;
5261 : : }
5262 : 0 : qmlStyle = qmlDocument.toString();
5263 : :
5264 : 0 : this->exportSldStyle( sldDocument, msgError );
5265 : 0 : if ( !msgError.isNull() )
5266 : : {
5267 : 0 : return;
5268 : : }
5269 : 0 : sldStyle = sldDocument.toString();
5270 : :
5271 : 0 : QgsProviderRegistry::instance()->saveStyle( mProviderKey,
5272 : 0 : mDataSource, qmlStyle, sldStyle, name,
5273 : 0 : description, uiFileContent, useAsDefault, msgError );
5274 : 0 : }
5275 : :
5276 : :
5277 : :
5278 : 78 : QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, QgsMapLayer::StyleCategories categories )
5279 : : {
5280 : 78 : return loadNamedStyle( theURI, resultFlag, false, categories );
5281 : : }
5282 : :
5283 : 1 : bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
5284 : : {
5285 : 1 : bool rc = false;
5286 : :
5287 : 1 : QString joinKey = mAuxiliaryLayerKey;
5288 : 1 : if ( !key.isEmpty() )
5289 : 0 : joinKey = key;
5290 : :
5291 : 1 : if ( storage.isValid() && !joinKey.isEmpty() )
5292 : : {
5293 : 0 : QgsAuxiliaryLayer *alayer = nullptr;
5294 : :
5295 : 0 : int idx = fields().lookupField( joinKey );
5296 : :
5297 : 0 : if ( idx >= 0 )
5298 : : {
5299 : 0 : alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
5300 : :
5301 : 0 : if ( alayer )
5302 : : {
5303 : 0 : setAuxiliaryLayer( alayer );
5304 : 0 : rc = true;
5305 : 0 : }
5306 : 0 : }
5307 : 0 : }
5308 : :
5309 : 1 : return rc;
5310 : 1 : }
5311 : :
5312 : 0 : void QgsVectorLayer::setAuxiliaryLayer( QgsAuxiliaryLayer *alayer )
5313 : : {
5314 : 0 : mAuxiliaryLayerKey.clear();
5315 : :
5316 : 0 : if ( mAuxiliaryLayer )
5317 : 0 : removeJoin( mAuxiliaryLayer->id() );
5318 : :
5319 : 0 : if ( alayer )
5320 : : {
5321 : 0 : addJoin( alayer->joinInfo() );
5322 : :
5323 : 0 : if ( !alayer->isEditable() )
5324 : 0 : alayer->startEditing();
5325 : :
5326 : 0 : mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
5327 : 0 : }
5328 : :
5329 : 0 : mAuxiliaryLayer.reset( alayer );
5330 : 0 : if ( mAuxiliaryLayer )
5331 : 0 : mAuxiliaryLayer->setParent( this );
5332 : 0 : updateFields();
5333 : 0 : }
5334 : :
5335 : 0 : const QgsAuxiliaryLayer *QgsVectorLayer::auxiliaryLayer() const
5336 : : {
5337 : 0 : return mAuxiliaryLayer.get();
5338 : : }
5339 : :
5340 : 0 : QgsAuxiliaryLayer *QgsVectorLayer::auxiliaryLayer()
5341 : : {
5342 : 0 : return mAuxiliaryLayer.get();
5343 : : }
5344 : :
5345 : 78 : QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB, QgsMapLayer::StyleCategories categories )
5346 : : {
5347 : 78 : QgsDataSourceUri dsUri( theURI );
5348 : 78 : QString returnMessage;
5349 : 78 : QString qml, errorMsg;
5350 : 78 : if ( !loadFromLocalDB && mDataProvider && mDataProvider->isSaveAndLoadStyleToDatabaseSupported() )
5351 : : {
5352 : 1 : qml = QgsProviderRegistry::instance()->loadStyle( mProviderKey, mDataSource, errorMsg );
5353 : 1 : }
5354 : 78 : if ( !qml.isEmpty() )
5355 : : {
5356 : 0 : QDomDocument myDocument( QStringLiteral( "qgis" ) );
5357 : 0 : myDocument.setContent( qml );
5358 : 0 : resultFlag = importNamedStyle( myDocument, errorMsg );
5359 : 0 : returnMessage = QObject::tr( "Loaded from Provider" );
5360 : 0 : }
5361 : : else
5362 : : {
5363 : 78 : returnMessage = QgsMapLayer::loadNamedStyle( theURI, resultFlag, categories );
5364 : : }
5365 : :
5366 : 78 : if ( resultFlag )
5367 : 0 : emit styleLoaded( categories );
5368 : :
5369 : 78 : return returnMessage;
5370 : 78 : }
5371 : :
5372 : 1 : QSet<QgsMapLayerDependency> QgsVectorLayer::dependencies() const
5373 : : {
5374 : 1 : if ( mDataProvider )
5375 : 1 : return mDataProvider->dependencies() + mDependencies;
5376 : 0 : return mDependencies;
5377 : 1 : }
5378 : :
5379 : 5 : void QgsVectorLayer::emitDataChanged()
5380 : : {
5381 : 5 : if ( mDataChangedFired )
5382 : 0 : return;
5383 : :
5384 : 5 : updateExtents(); // reset cached extent to reflect data changes
5385 : :
5386 : 5 : mDataChangedFired = true;
5387 : 5 : emit dataChanged();
5388 : 5 : mDataChangedFired = false;
5389 : 5 : }
5390 : :
5391 : 0 : void QgsVectorLayer::onAfterCommitChangesDependency()
5392 : : {
5393 : 0 : mDataChangedFired = true;
5394 : 0 : reload();
5395 : 0 : mDataChangedFired = false;
5396 : 0 : }
5397 : :
5398 : 0 : bool QgsVectorLayer::setDependencies( const QSet<QgsMapLayerDependency> &oDeps )
5399 : : {
5400 : 0 : QSet<QgsMapLayerDependency> deps;
5401 : 0 : const auto constODeps = oDeps;
5402 : 0 : for ( const QgsMapLayerDependency &dep : constODeps )
5403 : : {
5404 : 0 : if ( dep.origin() == QgsMapLayerDependency::FromUser )
5405 : 0 : deps << dep;
5406 : : }
5407 : :
5408 : 0 : QSet<QgsMapLayerDependency> toAdd = deps - dependencies();
5409 : :
5410 : : // disconnect layers that are not present in the list of dependencies anymore
5411 : 0 : for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
5412 : : {
5413 : 0 : QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5414 : 0 : if ( !lyr )
5415 : 0 : continue;
5416 : 0 : disconnect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5417 : 0 : disconnect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5418 : 0 : disconnect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5419 : 0 : disconnect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
5420 : 0 : disconnect( lyr, &QgsVectorLayer::repaintRequested, this, &QgsVectorLayer::triggerRepaint );
5421 : 0 : disconnect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
5422 : : }
5423 : :
5424 : : // assign new dependencies
5425 : 0 : if ( mDataProvider )
5426 : 0 : mDependencies = mDataProvider->dependencies() + deps;
5427 : : else
5428 : 0 : mDependencies = deps;
5429 : 0 : emit dependenciesChanged();
5430 : :
5431 : : // connect to new layers
5432 : 0 : for ( const QgsMapLayerDependency &dep : std::as_const( mDependencies ) )
5433 : : {
5434 : 0 : QgsVectorLayer *lyr = static_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( dep.layerId() ) );
5435 : 0 : if ( !lyr )
5436 : 0 : continue;
5437 : 0 : connect( lyr, &QgsVectorLayer::featureAdded, this, &QgsVectorLayer::emitDataChanged );
5438 : 0 : connect( lyr, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayer::emitDataChanged );
5439 : 0 : connect( lyr, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayer::emitDataChanged );
5440 : 0 : connect( lyr, &QgsVectorLayer::dataChanged, this, &QgsVectorLayer::emitDataChanged );
5441 : 0 : connect( lyr, &QgsVectorLayer::repaintRequested, this, &QgsVectorLayer::triggerRepaint );
5442 : 0 : connect( lyr, &QgsVectorLayer::afterCommitChanges, this, &QgsVectorLayer::onAfterCommitChangesDependency );
5443 : : }
5444 : :
5445 : : // if new layers are present, emit a data change
5446 : 0 : if ( ! toAdd.isEmpty() )
5447 : 0 : emitDataChanged();
5448 : :
5449 : : return true;
5450 : 0 : }
5451 : :
5452 : 0 : QgsFieldConstraints::Constraints QgsVectorLayer::fieldConstraints( int fieldIndex ) const
5453 : : {
5454 : 0 : if ( fieldIndex < 0 || fieldIndex >= mFields.count() || !mDataProvider )
5455 : 0 : return QgsFieldConstraints::Constraints();
5456 : :
5457 : 0 : QgsFieldConstraints::Constraints constraints = mFields.at( fieldIndex ).constraints().constraints();
5458 : :
5459 : : // make sure provider constraints are always present!
5460 : 0 : if ( mFields.fieldOrigin( fieldIndex ) == QgsFields::OriginProvider )
5461 : : {
5462 : 0 : constraints |= mDataProvider->fieldConstraints( mFields.fieldOriginIndex( fieldIndex ) );
5463 : 0 : }
5464 : :
5465 : 0 : return constraints;
5466 : 0 : }
5467 : :
5468 : 0 : QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength> QgsVectorLayer::fieldConstraintsAndStrength( int fieldIndex ) const
5469 : : {
5470 : 0 : QMap< QgsFieldConstraints::Constraint, QgsFieldConstraints::ConstraintStrength > m;
5471 : :
5472 : 0 : if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
5473 : 0 : return m;
5474 : :
5475 : 0 : QString name = mFields.at( fieldIndex ).name();
5476 : :
5477 : 0 : QMap< QPair< QString, QgsFieldConstraints::Constraint >, QgsFieldConstraints::ConstraintStrength >::const_iterator conIt = mFieldConstraintStrength.constBegin();
5478 : 0 : for ( ; conIt != mFieldConstraintStrength.constEnd(); ++conIt )
5479 : : {
5480 : 0 : if ( conIt.key().first == name )
5481 : : {
5482 : 0 : m[ conIt.key().second ] = mFieldConstraintStrength.value( conIt.key() );
5483 : 0 : }
5484 : 0 : }
5485 : :
5486 : 0 : return m;
5487 : 0 : }
5488 : :
5489 : 0 : void QgsVectorLayer::setFieldConstraint( int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength )
5490 : : {
5491 : 0 : if ( index < 0 || index >= mFields.count() )
5492 : 0 : return;
5493 : :
5494 : 0 : QString name = mFields.at( index ).name();
5495 : :
5496 : : // add constraint to existing constraints
5497 : 0 : QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
5498 : 0 : constraints |= constraint;
5499 : 0 : mFieldConstraints.insert( name, constraints );
5500 : :
5501 : 0 : mFieldConstraintStrength.insert( qMakePair( name, constraint ), strength );
5502 : :
5503 : 0 : updateFields();
5504 : 0 : }
5505 : :
5506 : 0 : void QgsVectorLayer::removeFieldConstraint( int index, QgsFieldConstraints::Constraint constraint )
5507 : : {
5508 : 0 : if ( index < 0 || index >= mFields.count() )
5509 : 0 : return;
5510 : :
5511 : 0 : QString name = mFields.at( index ).name();
5512 : :
5513 : : // remove constraint from existing constraints
5514 : 0 : QgsFieldConstraints::Constraints constraints = mFieldConstraints.value( name, QgsFieldConstraints::Constraints() );
5515 : 0 : constraints &= ~constraint;
5516 : 0 : mFieldConstraints.insert( name, constraints );
5517 : :
5518 : 0 : mFieldConstraintStrength.remove( qMakePair( name, constraint ) );
5519 : :
5520 : 0 : updateFields();
5521 : 0 : }
5522 : :
5523 : 0 : QString QgsVectorLayer::constraintExpression( int index ) const
5524 : : {
5525 : 0 : if ( index < 0 || index >= mFields.count() )
5526 : 0 : return QString();
5527 : :
5528 : 0 : return mFields.at( index ).constraints().constraintExpression();
5529 : 0 : }
5530 : :
5531 : 0 : QString QgsVectorLayer::constraintDescription( int index ) const
5532 : : {
5533 : 0 : if ( index < 0 || index >= mFields.count() )
5534 : 0 : return QString();
5535 : :
5536 : 0 : return mFields.at( index ).constraints().constraintDescription();
5537 : 0 : }
5538 : :
5539 : 0 : void QgsVectorLayer::setConstraintExpression( int index, const QString &expression, const QString &description )
5540 : : {
5541 : 0 : if ( index < 0 || index >= mFields.count() )
5542 : 0 : return;
5543 : :
5544 : 0 : if ( expression.isEmpty() )
5545 : : {
5546 : 0 : mFieldConstraintExpressions.remove( mFields.at( index ).name() );
5547 : 0 : }
5548 : : else
5549 : : {
5550 : 0 : mFieldConstraintExpressions.insert( mFields.at( index ).name(), qMakePair( expression, description ) );
5551 : : }
5552 : 0 : updateFields();
5553 : 0 : }
5554 : :
5555 : 0 : void QgsVectorLayer::setFieldConfigurationFlags( int index, QgsField::ConfigurationFlags flags )
5556 : : {
5557 : 0 : if ( index < 0 || index >= mFields.count() )
5558 : 0 : return;
5559 : :
5560 : 0 : mFieldConfigurationFlags.insert( mFields.at( index ).name(), flags );
5561 : 0 : updateFields();
5562 : 0 : }
5563 : :
5564 : 0 : void QgsVectorLayer::setFieldConfigurationFlag( int index, QgsField::ConfigurationFlag flag, bool active )
5565 : : {
5566 : 0 : if ( index < 0 || index >= mFields.count() )
5567 : 0 : return;
5568 : 0 : QgsField::ConfigurationFlags flags = mFields.at( index ).configurationFlags();
5569 : 0 : flags.setFlag( flag, active );
5570 : 0 : setFieldConfigurationFlags( index, flags );
5571 : 0 : }
5572 : :
5573 : 0 : QgsField::ConfigurationFlags QgsVectorLayer::fieldConfigurationFlags( int index ) const
5574 : : {
5575 : :
5576 : 0 : if ( index < 0 || index >= mFields.count() )
5577 : 0 : return QgsField::ConfigurationFlag::None;
5578 : :
5579 : 0 : return mFields.at( index ).configurationFlags();
5580 : 0 : }
5581 : :
5582 : 0 : void QgsVectorLayer::setEditorWidgetSetup( int index, const QgsEditorWidgetSetup &setup )
5583 : : {
5584 : 0 : if ( index < 0 || index >= mFields.count() )
5585 : 0 : return;
5586 : :
5587 : 0 : if ( setup.isNull() )
5588 : 0 : mFieldWidgetSetups.remove( mFields.at( index ).name() );
5589 : : else
5590 : 0 : mFieldWidgetSetups.insert( mFields.at( index ).name(), setup );
5591 : 0 : updateFields();
5592 : 0 : }
5593 : :
5594 : 0 : QgsEditorWidgetSetup QgsVectorLayer::editorWidgetSetup( int index ) const
5595 : : {
5596 : :
5597 : 0 : if ( index < 0 || index >= mFields.count() )
5598 : 0 : return QgsEditorWidgetSetup();
5599 : :
5600 : 0 : return mFields.at( index ).editorWidgetSetup();
5601 : 0 : }
5602 : :
5603 : 0 : QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties()
5604 : : {
5605 : 0 : QgsAbstractVectorLayerLabeling *labeling = nullptr;
5606 : 0 : if ( customProperty( QStringLiteral( "labeling" ) ).toString() == QLatin1String( "pal" ) )
5607 : : {
5608 : 0 : if ( customProperty( QStringLiteral( "labeling/enabled" ), QVariant( false ) ).toBool() )
5609 : : {
5610 : : // try to load from custom properties
5611 : 0 : QgsPalLayerSettings settings;
5612 : 0 : settings.readFromLayerCustomProperties( this );
5613 : 0 : labeling = new QgsVectorLayerSimpleLabeling( settings );
5614 : 0 : }
5615 : :
5616 : : // also clear old-style labeling config
5617 : 0 : removeCustomProperty( QStringLiteral( "labeling" ) );
5618 : 0 : const auto constCustomPropertyKeys = customPropertyKeys();
5619 : 0 : for ( const QString &key : constCustomPropertyKeys )
5620 : : {
5621 : 0 : if ( key.startsWith( QLatin1String( "labeling/" ) ) )
5622 : 0 : removeCustomProperty( key );
5623 : : }
5624 : 0 : }
5625 : :
5626 : 0 : return labeling;
5627 : 0 : }
5628 : :
5629 : 0 : bool QgsVectorLayer::allowCommit() const
5630 : : {
5631 : 0 : return mAllowCommit;
5632 : : }
5633 : :
5634 : 0 : void QgsVectorLayer::setAllowCommit( bool allowCommit )
5635 : : {
5636 : 0 : if ( mAllowCommit == allowCommit )
5637 : 0 : return;
5638 : :
5639 : 0 : mAllowCommit = allowCommit;
5640 : 0 : emit allowCommitChanged();
5641 : 0 : }
5642 : :
5643 : 0 : QgsGeometryOptions *QgsVectorLayer::geometryOptions() const
5644 : : {
5645 : 0 : return mGeometryOptions.get();
5646 : : }
5647 : :
5648 : 0 : void QgsVectorLayer::setReadExtentFromXml( bool readExtentFromXml )
5649 : : {
5650 : 0 : mReadExtentFromXml = readExtentFromXml;
5651 : 0 : }
5652 : :
5653 : 0 : bool QgsVectorLayer::readExtentFromXml() const
5654 : : {
5655 : 0 : return mReadExtentFromXml;
5656 : : }
5657 : :
5658 : 0 : void QgsVectorLayer::onDirtyTransaction( const QString &sql, const QString &name )
5659 : : {
5660 : 0 : QgsTransaction *tr = dataProvider()->transaction();
5661 : 0 : if ( tr && mEditBuffer )
5662 : : {
5663 : 0 : qobject_cast<QgsVectorLayerEditPassthrough *>( mEditBuffer )->update( tr, sql, name );
5664 : 0 : }
5665 : 0 : }
5666 : :
5667 : 0 : QList<QgsVectorLayer *> QgsVectorLayer::DeleteContext::handledLayers( bool includeAuxiliaryLayers ) const
5668 : : {
5669 : 0 : QList<QgsVectorLayer *> layers;
5670 : 0 : QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
5671 : 0 : for ( i = mHandledFeatures.begin(); i != mHandledFeatures.end(); ++i )
5672 : : {
5673 : 0 : if ( includeAuxiliaryLayers || !qobject_cast< QgsAuxiliaryLayer * >( i.key() ) )
5674 : 0 : layers.append( i.key() );
5675 : 0 : }
5676 : 0 : return layers;
5677 : 0 : }
5678 : :
5679 : 0 : QgsFeatureIds QgsVectorLayer::DeleteContext::handledFeatures( QgsVectorLayer *layer ) const
5680 : : {
5681 : 0 : return mHandledFeatures[layer];
5682 : : }
|