Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsvectorlayerutils.cpp
3 : : -----------------------
4 : : Date : October 2016
5 : : Copyright : (C) 2016 by Nyall Dawson
6 : : Email : nyall dot dawson at gmail dot com
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : :
16 : : #include <QRegularExpression>
17 : :
18 : : #include "qgsexpressioncontext.h"
19 : : #include "qgsfeatureiterator.h"
20 : : #include "qgsfeaturerequest.h"
21 : : #include "qgsvectorlayerutils.h"
22 : : #include "qgsvectordataprovider.h"
23 : : #include "qgsproject.h"
24 : : #include "qgsrelationmanager.h"
25 : : #include "qgsfeedback.h"
26 : : #include "qgsvectorlayer.h"
27 : : #include "qgsthreadingutils.h"
28 : : #include "qgsgeometrycollection.h"
29 : : #include "qgsexpressioncontextutils.h"
30 : : #include "qgsmultisurface.h"
31 : : #include "qgsgeometryfactory.h"
32 : : #include "qgscurvepolygon.h"
33 : : #include "qgspolygon.h"
34 : : #include "qgslinestring.h"
35 : : #include "qgsmultipoint.h"
36 : : #include "qgsvectorlayerjoinbuffer.h"
37 : : #include "qgsvectorlayerlabeling.h"
38 : : #include "qgspallabeling.h"
39 : : #include "qgsrenderer.h"
40 : : #include "qgssymbollayer.h"
41 : : #include "qgsstyleentityvisitor.h"
42 : : #include "qgsstyle.h"
43 : : #include "qgsauxiliarystorage.h"
44 : :
45 : :
46 : 0 : QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
47 : : {
48 : 0 : std::unique_ptr<QgsExpression> expression;
49 : 0 : QgsExpressionContext context;
50 : :
51 : 0 : int attrNum = layer->fields().lookupField( fieldOrExpression );
52 : 0 : if ( attrNum == -1 )
53 : : {
54 : : // try to use expression
55 : 0 : expression.reset( new QgsExpression( fieldOrExpression ) );
56 : 0 : context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
57 : :
58 : 0 : if ( expression->hasParserError() || !expression->prepare( &context ) )
59 : : {
60 : 0 : ok = false;
61 : 0 : return QgsFeatureIterator();
62 : : }
63 : 0 : }
64 : :
65 : 0 : QSet<QString> lst;
66 : 0 : if ( !expression )
67 : 0 : lst.insert( fieldOrExpression );
68 : : else
69 : 0 : lst = expression->referencedColumns();
70 : :
71 : 0 : QgsFeatureRequest request = QgsFeatureRequest()
72 : 0 : .setFlags( ( expression && expression->needsGeometry() ) ?
73 : : QgsFeatureRequest::NoFlags :
74 : : QgsFeatureRequest::NoGeometry )
75 : 0 : .setSubsetOfAttributes( lst, layer->fields() );
76 : :
77 : 0 : ok = true;
78 : 0 : if ( !selectedOnly )
79 : : {
80 : 0 : return layer->getFeatures( request );
81 : : }
82 : : else
83 : : {
84 : 0 : return layer->getSelectedFeatures( request );
85 : : }
86 : 0 : }
87 : :
88 : 0 : QList<QVariant> QgsVectorLayerUtils::getValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, QgsFeedback *feedback )
89 : : {
90 : 0 : QList<QVariant> values;
91 : 0 : QgsFeatureIterator fit = getValuesIterator( layer, fieldOrExpression, ok, selectedOnly );
92 : 0 : if ( ok )
93 : : {
94 : 0 : std::unique_ptr<QgsExpression> expression;
95 : 0 : QgsExpressionContext context;
96 : :
97 : 0 : int attrNum = layer->fields().lookupField( fieldOrExpression );
98 : 0 : if ( attrNum == -1 )
99 : : {
100 : : // use expression, already validated in the getValuesIterator() function
101 : 0 : expression.reset( new QgsExpression( fieldOrExpression ) );
102 : 0 : context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
103 : 0 : }
104 : :
105 : 0 : QgsFeature f;
106 : 0 : while ( fit.nextFeature( f ) )
107 : : {
108 : 0 : if ( expression )
109 : : {
110 : 0 : context.setFeature( f );
111 : 0 : QVariant v = expression->evaluate( &context );
112 : 0 : values << v;
113 : 0 : }
114 : : else
115 : : {
116 : 0 : values << f.attribute( attrNum );
117 : : }
118 : 0 : if ( feedback && feedback->isCanceled() )
119 : : {
120 : 0 : ok = false;
121 : 0 : return values;
122 : : }
123 : : }
124 : 0 : }
125 : 0 : return values;
126 : 0 : }
127 : :
128 : 0 : QList<double> QgsVectorLayerUtils::getDoubleValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, int *nullCount, QgsFeedback *feedback )
129 : : {
130 : 0 : QList<double> values;
131 : :
132 : 0 : if ( nullCount )
133 : 0 : *nullCount = 0;
134 : :
135 : 0 : QList<QVariant> variantValues = getValues( layer, fieldOrExpression, ok, selectedOnly, feedback );
136 : 0 : if ( !ok )
137 : 0 : return values;
138 : :
139 : : bool convertOk;
140 : 0 : const auto constVariantValues = variantValues;
141 : 0 : for ( const QVariant &value : constVariantValues )
142 : : {
143 : 0 : double val = value.toDouble( &convertOk );
144 : 0 : if ( convertOk )
145 : 0 : values << val;
146 : 0 : else if ( value.isNull() )
147 : : {
148 : 0 : if ( nullCount )
149 : 0 : *nullCount += 1;
150 : 0 : }
151 : 0 : if ( feedback && feedback->isCanceled() )
152 : : {
153 : 0 : ok = false;
154 : 0 : return values;
155 : : }
156 : : }
157 : 0 : return values;
158 : 0 : }
159 : :
160 : 0 : bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds )
161 : : {
162 : 0 : if ( !layer )
163 : 0 : return false;
164 : :
165 : 0 : QgsFields fields = layer->fields();
166 : :
167 : 0 : if ( fieldIndex < 0 || fieldIndex >= fields.count() )
168 : 0 : return false;
169 : :
170 : : // If it's a joined field search the value in the source layer
171 : 0 : if ( fields.fieldOrigin( fieldIndex ) == QgsFields::FieldOrigin::OriginJoin )
172 : : {
173 : : int srcFieldIndex;
174 : 0 : const QgsVectorLayerJoinInfo *joinInfo { layer->joinBuffer()->joinForFieldIndex( fieldIndex, fields, srcFieldIndex ) };
175 : 0 : if ( ! joinInfo )
176 : : {
177 : 0 : return false;
178 : : }
179 : 0 : fieldIndex = srcFieldIndex;
180 : 0 : layer = joinInfo->joinLayer();
181 : 0 : if ( ! layer )
182 : : {
183 : 0 : return false;
184 : : }
185 : 0 : fields = layer->fields();
186 : 0 : }
187 : :
188 : 0 : QString fieldName = fields.at( fieldIndex ).name();
189 : :
190 : : // build up an optimised feature request
191 : 0 : QgsFeatureRequest request;
192 : 0 : request.setNoAttributes();
193 : 0 : request.setFlags( QgsFeatureRequest::NoGeometry );
194 : :
195 : : // at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
196 : 0 : int limit = ignoreIds.size() + 1;
197 : 0 : request.setLimit( limit );
198 : :
199 : 0 : request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
200 : 0 : QgsExpression::quotedValue( value ) ) );
201 : :
202 : 0 : QgsFeature feat;
203 : 0 : QgsFeatureIterator it = layer->getFeatures( request );
204 : 0 : while ( it.nextFeature( feat ) )
205 : : {
206 : 0 : if ( ignoreIds.contains( feat.id() ) )
207 : 0 : continue;
208 : :
209 : 0 : return true;
210 : : }
211 : :
212 : 0 : return false;
213 : 0 : }
214 : :
215 : 0 : QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed )
216 : : {
217 : 0 : if ( !layer )
218 : 0 : return QVariant();
219 : :
220 : 0 : QgsFields fields = layer->fields();
221 : :
222 : 0 : if ( fieldIndex < 0 || fieldIndex >= fields.count() )
223 : 0 : return QVariant();
224 : :
225 : 0 : QgsField field = fields.at( fieldIndex );
226 : :
227 : 0 : if ( field.isNumeric() )
228 : : {
229 : 0 : QVariant maxVal = layer->maximumValue( fieldIndex );
230 : 0 : QVariant newVar( maxVal.toLongLong() + 1 );
231 : 0 : if ( field.convertCompatible( newVar ) )
232 : 0 : return newVar;
233 : : else
234 : 0 : return QVariant();
235 : 0 : }
236 : : else
237 : : {
238 : 0 : switch ( field.type() )
239 : : {
240 : : case QVariant::String:
241 : : {
242 : 0 : QString base;
243 : 0 : if ( seed.isValid() )
244 : 0 : base = seed.toString();
245 : :
246 : 0 : if ( !base.isEmpty() )
247 : : {
248 : : // strip any existing _1, _2 from the seed
249 : 0 : QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
250 : 0 : QRegularExpressionMatch match = rx.match( base );
251 : 0 : if ( match.hasMatch() )
252 : : {
253 : 0 : base = match.captured( 1 );
254 : 0 : }
255 : 0 : }
256 : : else
257 : : {
258 : : // no base seed - fetch first value from layer
259 : 0 : QgsFeatureRequest req;
260 : 0 : req.setLimit( 1 );
261 : 0 : req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
262 : 0 : req.setFlags( QgsFeatureRequest::NoGeometry );
263 : 0 : QgsFeature f;
264 : 0 : layer->getFeatures( req ).nextFeature( f );
265 : 0 : base = f.attribute( fieldIndex ).toString();
266 : 0 : }
267 : :
268 : : // try variants like base_1, base_2, etc until a new value found
269 : 0 : QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
270 : :
271 : : // might already be unique
272 : 0 : if ( !base.isEmpty() && !vals.contains( base ) )
273 : 0 : return base;
274 : :
275 : 0 : for ( int i = 1; i < 10000; ++i )
276 : : {
277 : 0 : QString testVal = base + '_' + QString::number( i );
278 : 0 : if ( !vals.contains( testVal ) )
279 : 0 : return testVal;
280 : 0 : }
281 : :
282 : : // failed
283 : 0 : return QVariant();
284 : 0 : }
285 : :
286 : : default:
287 : : // todo other types - dates? times?
288 : 0 : break;
289 : : }
290 : : }
291 : :
292 : 0 : return QVariant();
293 : 0 : }
294 : :
295 : 0 : QVariant QgsVectorLayerUtils::createUniqueValueFromCache( const QgsVectorLayer *layer, int fieldIndex, const QSet<QVariant> &existingValues, const QVariant &seed )
296 : : {
297 : 0 : if ( !layer )
298 : 0 : return QVariant();
299 : :
300 : 0 : QgsFields fields = layer->fields();
301 : :
302 : 0 : if ( fieldIndex < 0 || fieldIndex >= fields.count() )
303 : 0 : return QVariant();
304 : :
305 : 0 : QgsField field = fields.at( fieldIndex );
306 : :
307 : 0 : if ( field.isNumeric() )
308 : : {
309 : 0 : QVariant maxVal = existingValues.isEmpty() ? 0 : *std::max_element( existingValues.begin(), existingValues.end(), []( const QVariant & a, const QVariant & b ) { return a.toLongLong() < b.toLongLong(); } );
310 : 0 : QVariant newVar( maxVal.toLongLong() + 1 );
311 : 0 : if ( field.convertCompatible( newVar ) )
312 : 0 : return newVar;
313 : : else
314 : 0 : return QVariant();
315 : 0 : }
316 : : else
317 : : {
318 : 0 : switch ( field.type() )
319 : : {
320 : : case QVariant::String:
321 : : {
322 : 0 : QString base;
323 : 0 : if ( seed.isValid() )
324 : 0 : base = seed.toString();
325 : :
326 : 0 : if ( !base.isEmpty() )
327 : : {
328 : : // strip any existing _1, _2 from the seed
329 : 0 : QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
330 : 0 : QRegularExpressionMatch match = rx.match( base );
331 : 0 : if ( match.hasMatch() )
332 : : {
333 : 0 : base = match.captured( 1 );
334 : 0 : }
335 : 0 : }
336 : : else
337 : : {
338 : : // no base seed - fetch first value from layer
339 : 0 : QgsFeatureRequest req;
340 : 0 : base = existingValues.isEmpty() ? QString() : existingValues.values().first().toString();
341 : 0 : }
342 : :
343 : : // try variants like base_1, base_2, etc until a new value found
344 : 0 : QStringList vals;
345 : 0 : for ( const auto &v : std::as_const( existingValues ) )
346 : : {
347 : 0 : if ( v.toString().startsWith( base ) )
348 : 0 : vals.push_back( v.toString() );
349 : : }
350 : :
351 : : // might already be unique
352 : 0 : if ( !base.isEmpty() && !vals.contains( base ) )
353 : 0 : return base;
354 : :
355 : 0 : for ( int i = 1; i < 10000; ++i )
356 : : {
357 : 0 : QString testVal = base + '_' + QString::number( i );
358 : 0 : if ( !vals.contains( testVal ) )
359 : 0 : return testVal;
360 : 0 : }
361 : :
362 : : // failed
363 : 0 : return QVariant();
364 : 0 : }
365 : :
366 : : default:
367 : : // todo other types - dates? times?
368 : 0 : break;
369 : : }
370 : : }
371 : :
372 : 0 : return QVariant();
373 : :
374 : 0 : }
375 : :
376 : 0 : bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors,
377 : : QgsFieldConstraints::ConstraintStrength strength, QgsFieldConstraints::ConstraintOrigin origin )
378 : : {
379 : 0 : if ( !layer )
380 : 0 : return false;
381 : :
382 : 0 : if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
383 : 0 : return false;
384 : :
385 : 0 : QgsFields fields = layer->fields();
386 : 0 : QgsField field = fields.at( attributeIndex );
387 : 0 : QVariant value = feature.attribute( attributeIndex );
388 : 0 : bool valid = true;
389 : 0 : errors.clear();
390 : :
391 : 0 : QgsFieldConstraints constraints = field.constraints();
392 : :
393 : 0 : if ( constraints.constraints() & QgsFieldConstraints::ConstraintExpression && !constraints.constraintExpression().isEmpty()
394 : 0 : && ( strength == QgsFieldConstraints::ConstraintStrengthNotSet || strength == constraints.constraintStrength( QgsFieldConstraints::ConstraintExpression ) )
395 : 0 : && ( origin == QgsFieldConstraints::ConstraintOriginNotSet || origin == constraints.constraintOrigin( QgsFieldConstraints::ConstraintExpression ) ) )
396 : : {
397 : 0 : QgsExpressionContext context = layer->createExpressionContext();
398 : 0 : context.setFeature( feature );
399 : :
400 : 0 : QgsExpression expr( constraints.constraintExpression() );
401 : :
402 : 0 : valid = expr.evaluate( &context ).toBool();
403 : :
404 : 0 : if ( expr.hasParserError() )
405 : : {
406 : 0 : errors << QObject::tr( "parser error: %1" ).arg( expr.parserErrorString() );
407 : 0 : }
408 : 0 : else if ( expr.hasEvalError() )
409 : : {
410 : 0 : errors << QObject::tr( "evaluation error: %1" ).arg( expr.evalErrorString() );
411 : 0 : }
412 : 0 : else if ( !valid )
413 : : {
414 : 0 : errors << QObject::tr( "%1 check failed" ).arg( constraints.constraintDescription() );
415 : 0 : }
416 : 0 : }
417 : :
418 : 0 : bool notNullConstraintViolated { false };
419 : :
420 : 0 : if ( constraints.constraints() & QgsFieldConstraints::ConstraintNotNull
421 : 0 : && ( strength == QgsFieldConstraints::ConstraintStrengthNotSet || strength == constraints.constraintStrength( QgsFieldConstraints::ConstraintNotNull ) )
422 : 0 : && ( origin == QgsFieldConstraints::ConstraintOriginNotSet || origin == constraints.constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) ) )
423 : : {
424 : 0 : bool exempt = false;
425 : 0 : if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
426 : 0 : && constraints.constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) == QgsFieldConstraints::ConstraintOriginProvider )
427 : : {
428 : 0 : int providerIdx = fields.fieldOriginIndex( attributeIndex );
429 : 0 : exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintNotNull, value );
430 : 0 : }
431 : :
432 : 0 : if ( !exempt )
433 : : {
434 : 0 : valid = valid && !value.isNull();
435 : :
436 : 0 : if ( value.isNull() )
437 : : {
438 : 0 : errors << QObject::tr( "value is NULL" );
439 : 0 : notNullConstraintViolated = true;
440 : 0 : }
441 : 0 : }
442 : 0 : }
443 : :
444 : : // if a NOT NULL constraint is violated we don't need to check for UNIQUE
445 : 0 : if ( ! notNullConstraintViolated )
446 : : {
447 : :
448 : 0 : if ( constraints.constraints() & QgsFieldConstraints::ConstraintUnique
449 : 0 : && ( strength == QgsFieldConstraints::ConstraintStrengthNotSet || strength == constraints.constraintStrength( QgsFieldConstraints::ConstraintUnique ) )
450 : 0 : && ( origin == QgsFieldConstraints::ConstraintOriginNotSet || origin == constraints.constraintOrigin( QgsFieldConstraints::ConstraintUnique ) ) )
451 : : {
452 : 0 : bool exempt = false;
453 : 0 : if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
454 : 0 : && constraints.constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) == QgsFieldConstraints::ConstraintOriginProvider )
455 : : {
456 : 0 : int providerIdx = fields.fieldOriginIndex( attributeIndex );
457 : 0 : exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintUnique, value );
458 : 0 : }
459 : :
460 : 0 : if ( !exempt )
461 : : {
462 : :
463 : 0 : bool alreadyExists = QgsVectorLayerUtils::valueExists( layer, attributeIndex, value, QgsFeatureIds() << feature.id() );
464 : 0 : valid = valid && !alreadyExists;
465 : :
466 : 0 : if ( alreadyExists )
467 : : {
468 : 0 : errors << QObject::tr( "value is not unique" );
469 : 0 : }
470 : 0 : }
471 : 0 : }
472 : 0 : }
473 : :
474 : 0 : return valid;
475 : 0 : }
476 : :
477 : 1 : QgsFeature QgsVectorLayerUtils::createFeature( const QgsVectorLayer *layer, const QgsGeometry &geometry,
478 : : const QgsAttributeMap &attributes, QgsExpressionContext *context )
479 : : {
480 : 1 : QgsFeatureList features { createFeatures( layer, QgsFeaturesDataList() << QgsFeatureData( geometry, attributes ), context ) };
481 : 1 : return features.isEmpty() ? QgsFeature() : features.first();
482 : 1 : }
483 : :
484 : 1 : QgsFeatureList QgsVectorLayerUtils::createFeatures( const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context )
485 : : {
486 : 1 : if ( !layer )
487 : 0 : return QgsFeatureList();
488 : :
489 : 1 : QgsFeatureList result;
490 : 1 : result.reserve( featuresData.length() );
491 : :
492 : 1 : QgsExpressionContext *evalContext = context;
493 : 1 : std::unique_ptr< QgsExpressionContext > tempContext;
494 : 1 : if ( !evalContext )
495 : : {
496 : : // no context passed, so we create a default one
497 : 1 : tempContext.reset( new QgsExpressionContext( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) ) );
498 : 1 : evalContext = tempContext.get();
499 : 1 : }
500 : :
501 : 1 : QgsFields fields = layer->fields();
502 : :
503 : : // Cache unique values
504 : 1 : QMap<int, QSet<QVariant>> uniqueValueCache;
505 : :
506 : 1 : auto checkUniqueValue = [ & ]( const int fieldIdx, const QVariant & value )
507 : : {
508 : 0 : if ( ! uniqueValueCache.contains( fieldIdx ) )
509 : : {
510 : : // If the layer is filtered, get unique values from an unfiltered clone
511 : 0 : if ( ! layer->subsetString().isEmpty() )
512 : : {
513 : 0 : std::unique_ptr<QgsVectorLayer> unfilteredClone { layer->clone( ) };
514 : 0 : unfilteredClone->setSubsetString( QString( ) );
515 : 0 : uniqueValueCache[ fieldIdx ] = unfilteredClone->uniqueValues( fieldIdx );
516 : 0 : }
517 : : else
518 : : {
519 : 0 : uniqueValueCache[ fieldIdx ] = layer->uniqueValues( fieldIdx );
520 : : }
521 : 0 : }
522 : 0 : return uniqueValueCache[ fieldIdx ].contains( value );
523 : 0 : };
524 : :
525 : 2 : for ( const auto &fd : std::as_const( featuresData ) )
526 : : {
527 : :
528 : 1 : QgsFeature newFeature( fields );
529 : 1 : newFeature.setValid( true );
530 : 1 : newFeature.setGeometry( fd.geometry() );
531 : :
532 : : // initialize attributes
533 : 1 : newFeature.initAttributes( fields.count() );
534 : 1 : for ( int idx = 0; idx < fields.count(); ++idx )
535 : : {
536 : 0 : QVariant v;
537 : 0 : bool checkUnique = true;
538 : 0 : const bool hasUniqueConstraint { static_cast<bool>( fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique ) };
539 : :
540 : : // in order of priority:
541 : : // 1. passed attribute value and if field does not have a unique constraint like primary key
542 : 0 : if ( fd.attributes().contains( idx ) )
543 : : {
544 : 0 : v = fd.attributes().value( idx );
545 : 0 : }
546 : :
547 : : // 2. client side default expression
548 : : // note - deliberately not using else if!
549 : 0 : QgsDefaultValue defaultValueDefinition = layer->defaultValueDefinition( idx );
550 : 0 : if ( ( v.isNull() || ( hasUniqueConstraint
551 : 0 : && checkUniqueValue( idx, v ) )
552 : 0 : || defaultValueDefinition.applyOnUpdate() )
553 : 0 : && defaultValueDefinition.isValid() )
554 : : {
555 : : // client side default expression set - takes precedence over all. Why? Well, this is the only default
556 : : // which QGIS users have control over, so we assume that they're deliberately overriding any
557 : : // provider defaults for some good reason and we should respect that
558 : 0 : v = layer->defaultValue( idx, newFeature, evalContext );
559 : 0 : }
560 : :
561 : : // 3. provider side default value clause
562 : : // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
563 : 0 : if ( ( v.isNull() || ( hasUniqueConstraint
564 : 0 : && checkUniqueValue( idx, v ) ) )
565 : 0 : && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
566 : : {
567 : 0 : int providerIndex = fields.fieldOriginIndex( idx );
568 : 0 : QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
569 : 0 : if ( !providerDefault.isEmpty() )
570 : : {
571 : 0 : v = providerDefault;
572 : 0 : checkUnique = false;
573 : 0 : }
574 : 0 : }
575 : :
576 : : // 4. provider side default literal
577 : : // note - deliberately not using else if!
578 : 0 : if ( ( v.isNull() || ( checkUnique
579 : 0 : && hasUniqueConstraint
580 : 0 : && checkUniqueValue( idx, v ) ) )
581 : 0 : && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
582 : : {
583 : 0 : int providerIndex = fields.fieldOriginIndex( idx );
584 : 0 : v = layer->dataProvider()->defaultValue( providerIndex );
585 : 0 : if ( v.isValid() )
586 : : {
587 : : //trust that the provider default has been sensibly set not to violate any constraints
588 : 0 : checkUnique = false;
589 : 0 : }
590 : 0 : }
591 : :
592 : : // 5. passed attribute value
593 : : // note - deliberately not using else if!
594 : 0 : if ( v.isNull() && fd.attributes().contains( idx ) )
595 : : {
596 : 0 : v = fd.attributes().value( idx );
597 : 0 : }
598 : :
599 : : // last of all... check that unique constraints are respected if the value is valid
600 : 0 : if ( v.isValid() )
601 : : {
602 : : // we can't handle not null or expression constraints here, since there's no way to pick a sensible
603 : : // value if the constraint is violated
604 : 0 : if ( checkUnique && hasUniqueConstraint )
605 : : {
606 : 0 : if ( checkUniqueValue( idx, v ) )
607 : : {
608 : : // unique constraint violated
609 : 0 : QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValueFromCache( layer, idx, uniqueValueCache[ idx ], v );
610 : 0 : if ( uniqueValue.isValid() )
611 : 0 : v = uniqueValue;
612 : 0 : }
613 : 0 : }
614 : 0 : if ( hasUniqueConstraint )
615 : : {
616 : 0 : uniqueValueCache[ idx ].insert( v );
617 : 0 : }
618 : 0 : }
619 : 0 : newFeature.setAttribute( idx, v );
620 : 0 : }
621 : 1 : result.append( newFeature );
622 : 1 : }
623 : 1 : return result;
624 : 1 : }
625 : :
626 : 0 : QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext, const int maxDepth, int depth, QList<QgsVectorLayer *> referencedLayersBranch )
627 : : {
628 : 0 : if ( !layer )
629 : 0 : return QgsFeature();
630 : :
631 : 0 : if ( !layer->isEditable() )
632 : 0 : return QgsFeature();
633 : :
634 : : //get context from layer
635 : 0 : QgsExpressionContext context = layer->createExpressionContext();
636 : 0 : context.setFeature( feature );
637 : :
638 : 0 : QgsFeature newFeature = createFeature( layer, feature.geometry(), feature.attributes().toMap(), &context );
639 : 0 : layer->addFeature( newFeature );
640 : :
641 : 0 : const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
642 : :
643 : 0 : const int effectiveMaxDepth = maxDepth > 0 ? maxDepth : 100;
644 : :
645 : 0 : for ( const QgsRelation &relation : relations )
646 : : {
647 : : //check if composition (and not association)
648 : 0 : if ( relation.strength() == QgsRelation::Composition && !referencedLayersBranch.contains( relation.referencedLayer() ) && depth < effectiveMaxDepth )
649 : : {
650 : 0 : depth++;
651 : 0 : referencedLayersBranch << layer;
652 : :
653 : : //get features connected over this relation
654 : 0 : QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
655 : 0 : QgsFeatureIds childFeatureIds;
656 : 0 : QgsFeature childFeature;
657 : 0 : while ( relatedFeaturesIt.nextFeature( childFeature ) )
658 : : {
659 : : //set childlayer editable
660 : 0 : relation.referencingLayer()->startEditing();
661 : : //change the fk of the child to the id of the new parent
662 : 0 : const auto pairs = relation.fieldPairs();
663 : 0 : for ( const QgsRelation::FieldPair &fieldPair : pairs )
664 : : {
665 : 0 : childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
666 : : }
667 : : //call the function for the child
668 : 0 : childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, duplicateFeatureContext, maxDepth, depth, referencedLayersBranch ).id() );
669 : 0 : }
670 : :
671 : : //store for feedback
672 : 0 : duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
673 : 0 : }
674 : : }
675 : :
676 : :
677 : 0 : return newFeature;
678 : 0 : }
679 : :
680 : 0 : std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
681 : : {
682 : 0 : std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
683 : :
684 : 0 : auto getFeatureSource = [ layer, &featureSource, feedback ]
685 : : {
686 : : Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
687 : 0 : QgsVectorLayer *lyr = layer.data();
688 : :
689 : 0 : if ( lyr )
690 : : {
691 : 0 : featureSource.reset( new QgsVectorLayerFeatureSource( lyr ) );
692 : 0 : }
693 : 0 : };
694 : :
695 : 0 : QgsThreadingUtils::runOnMainThread( getFeatureSource, feedback );
696 : :
697 : 0 : return featureSource;
698 : 0 : }
699 : :
700 : 1 : void QgsVectorLayerUtils::matchAttributesToFields( QgsFeature &feature, const QgsFields &fields )
701 : : {
702 : 1 : if ( !feature.fields().isEmpty() )
703 : : {
704 : 0 : QgsAttributes attributes;
705 : 0 : attributes.reserve( fields.size() );
706 : : // feature has a field mapping, so we can match attributes to field names
707 : 0 : for ( const QgsField &field : fields )
708 : : {
709 : 0 : int index = feature.fields().lookupField( field.name() );
710 : 0 : attributes.append( index >= 0 ? feature.attribute( index ) : QVariant( field.type() ) );
711 : : }
712 : 0 : feature.setAttributes( attributes );
713 : 0 : }
714 : : else
715 : : {
716 : : // no field name mapping in feature, just use order
717 : 1 : const int lengthDiff = feature.attributes().count() - fields.count();
718 : 1 : if ( lengthDiff > 0 )
719 : : {
720 : : // truncate extra attributes
721 : 0 : QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
722 : 0 : feature.setAttributes( attributes );
723 : 0 : }
724 : 1 : else if ( lengthDiff < 0 )
725 : : {
726 : : // add missing null attributes
727 : 0 : QgsAttributes attributes = feature.attributes();
728 : 0 : attributes.reserve( fields.count() );
729 : 0 : for ( int i = feature.attributes().count(); i < fields.count(); ++i )
730 : : {
731 : 0 : attributes.append( QVariant( fields.at( i ).type() ) );
732 : 0 : }
733 : 0 : feature.setAttributes( attributes );
734 : 0 : }
735 : : }
736 : 1 : feature.setFields( fields );
737 : 1 : }
738 : :
739 : 1 : QgsFeatureList QgsVectorLayerUtils::makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags )
740 : : {
741 : 1 : QgsWkbTypes::Type inputWkbType( layer->wkbType( ) );
742 : 1 : QgsFeatureList resultFeatures;
743 : 1 : QgsFeature newF( feature );
744 : : // Fix attributes
745 : 1 : QgsVectorLayerUtils::matchAttributesToFields( newF, layer->fields( ) );
746 : :
747 : 1 : if ( sinkFlags & QgsFeatureSink::RegeneratePrimaryKey )
748 : : {
749 : : // drop incoming primary key values, let them be regenerated
750 : 0 : const QgsAttributeList pkIndexes = layer->dataProvider()->pkAttributeIndexes();
751 : 0 : for ( int index : pkIndexes )
752 : : {
753 : 0 : if ( index >= 0 )
754 : 0 : newF.setAttribute( index, QVariant() );
755 : : }
756 : 0 : }
757 : :
758 : : // Does geometry need transformations?
759 : 1 : QgsWkbTypes::GeometryType newFGeomType( QgsWkbTypes::geometryType( newF.geometry().wkbType() ) );
760 : 2 : bool newFHasGeom = newFGeomType !=
761 : 1 : QgsWkbTypes::GeometryType::UnknownGeometry &&
762 : 1 : newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
763 : 2 : bool layerHasGeom = inputWkbType !=
764 : 1 : QgsWkbTypes::Type::NoGeometry &&
765 : 1 : inputWkbType != QgsWkbTypes::Type::Unknown;
766 : : // Drop geometry if layer is geometry-less
767 : 1 : if ( ( newFHasGeom && !layerHasGeom ) || !newFHasGeom )
768 : : {
769 : 0 : QgsFeature _f = QgsFeature( layer->fields() );
770 : 0 : _f.setAttributes( newF.attributes() );
771 : 0 : resultFeatures.append( _f );
772 : 0 : }
773 : : else
774 : : {
775 : : // Geometry need fixing?
776 : 1 : const QVector< QgsGeometry > geometries = newF.geometry().coerceToType( inputWkbType );
777 : :
778 : 1 : if ( geometries.count() != 1 )
779 : : {
780 : 0 : QgsAttributeMap attrMap;
781 : 0 : for ( int j = 0; j < newF.fields().count(); j++ )
782 : : {
783 : 0 : attrMap[j] = newF.attribute( j );
784 : 0 : }
785 : 0 : resultFeatures.reserve( geometries.size() );
786 : 0 : for ( const QgsGeometry &geometry : geometries )
787 : : {
788 : 0 : QgsFeature _f( createFeature( layer, geometry, attrMap ) );
789 : 0 : resultFeatures.append( _f );
790 : 0 : }
791 : 0 : }
792 : : else
793 : : {
794 : 1 : newF.setGeometry( geometries.at( 0 ) );
795 : 1 : resultFeatures.append( newF );
796 : : }
797 : 1 : }
798 : 1 : return resultFeatures;
799 : 1 : }
800 : :
801 : 0 : QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer *layer, QgsFeatureSink::SinkFlags sinkFlags )
802 : : {
803 : 0 : QgsFeatureList resultFeatures;
804 : 0 : for ( const QgsFeature &f : features )
805 : : {
806 : 0 : const QgsFeatureList features( makeFeatureCompatible( f, layer, sinkFlags ) );
807 : 0 : for ( const auto &_f : features )
808 : : {
809 : 0 : resultFeatures.append( _f );
810 : : }
811 : 0 : }
812 : 0 : return resultFeatures;
813 : 0 : }
814 : :
815 : 0 : QList<QgsVectorLayer *> QgsVectorLayerUtils::QgsDuplicateFeatureContext::layers() const
816 : : {
817 : 0 : QList<QgsVectorLayer *> layers;
818 : 0 : QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
819 : 0 : for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
820 : 0 : layers.append( i.key() );
821 : 0 : return layers;
822 : 0 : }
823 : :
824 : 0 : QgsFeatureIds QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicatedFeatures( QgsVectorLayer *layer ) const
825 : : {
826 : 0 : return mDuplicatedFeatures[layer];
827 : : }
828 : :
829 : 0 : void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
830 : : {
831 : 0 : if ( mDuplicatedFeatures.contains( layer ) )
832 : 0 : mDuplicatedFeatures[layer] += ids;
833 : : else
834 : 0 : mDuplicatedFeatures.insert( layer, ids );
835 : 0 : }
836 : : /*
837 : : QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
838 : : {
839 : : return mDuplicatedFeatures;
840 : : }
841 : : */
842 : :
843 : 1 : QgsVectorLayerUtils::QgsFeatureData::QgsFeatureData( const QgsGeometry &geometry, const QgsAttributeMap &attributes ):
844 : 1 : mGeometry( geometry ),
845 : 1 : mAttributes( attributes )
846 : 1 : {}
847 : :
848 : 1 : QgsGeometry QgsVectorLayerUtils::QgsFeatureData::geometry() const
849 : : {
850 : 1 : return mGeometry;
851 : : }
852 : :
853 : 0 : QgsAttributeMap QgsVectorLayerUtils::QgsFeatureData::attributes() const
854 : : {
855 : 0 : return mAttributes;
856 : : }
857 : :
858 : 0 : bool _fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature )
859 : : {
860 : 0 : return layer->isEditable() &&
861 : 0 : !layer->editFormConfig().readOnly( fieldIndex ) &&
862 : : // Provider permissions
863 : 0 : layer->dataProvider() &&
864 : 0 : ( ( layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) ||
865 : 0 : ( layer->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures && ( FID_IS_NULL( feature.id() ) || FID_IS_NEW( feature.id() ) ) ) ) &&
866 : : // Field must not be read only
867 : 0 : !layer->fields().at( fieldIndex ).isReadOnly();
868 : 0 : }
869 : :
870 : 0 : bool QgsVectorLayerUtils::fieldIsReadOnly( const QgsVectorLayer *layer, int fieldIndex )
871 : : {
872 : 0 : if ( layer->fields().fieldOrigin( fieldIndex ) == QgsFields::OriginJoin )
873 : : {
874 : : int srcFieldIndex;
875 : 0 : const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
876 : :
877 : 0 : if ( !info || !info->isEditable() || !info->joinLayer() )
878 : 0 : return true;
879 : :
880 : 0 : return fieldIsReadOnly( info->joinLayer(), srcFieldIndex );
881 : : }
882 : : else
883 : : {
884 : : // any of these properties makes the field read only
885 : 0 : if ( !layer->isEditable() ||
886 : 0 : layer->editFormConfig().readOnly( fieldIndex ) ||
887 : 0 : !layer->dataProvider() ||
888 : 0 : ( !( layer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues )
889 : 0 : && !( layer->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures ) ) ||
890 : 0 : layer->fields().at( fieldIndex ).isReadOnly() )
891 : 0 : return true;
892 : :
893 : 0 : return false;
894 : : }
895 : 0 : }
896 : :
897 : 0 : bool QgsVectorLayerUtils::fieldEditabilityDependsOnFeature( const QgsVectorLayer *layer, int fieldIndex )
898 : : {
899 : : // editability will vary feature-by-feature only for joined fields
900 : 0 : if ( layer->fields().fieldOrigin( fieldIndex ) == QgsFields::OriginJoin )
901 : : {
902 : : int srcFieldIndex;
903 : 0 : const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
904 : :
905 : 0 : if ( !info || !info->isEditable() || info->hasUpsertOnEdit() )
906 : 0 : return false;
907 : :
908 : : // join does not have upsert capabilities, so the ability to edit the joined field will
909 : : // vary feature-by-feature, depending on whether the join target feature already exists
910 : 0 : return true;
911 : : }
912 : : else
913 : : {
914 : 0 : return false;
915 : : }
916 : 0 : }
917 : :
918 : 0 : bool QgsVectorLayerUtils::fieldIsEditable( const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature )
919 : : {
920 : 0 : if ( layer->fields().fieldOrigin( fieldIndex ) == QgsFields::OriginJoin )
921 : : {
922 : : int srcFieldIndex;
923 : 0 : const QgsVectorLayerJoinInfo *info = layer->joinBuffer()->joinForFieldIndex( fieldIndex, layer->fields(), srcFieldIndex );
924 : :
925 : 0 : if ( !info || !info->isEditable() )
926 : 0 : return false;
927 : :
928 : : // check that joined feature exist, else it is not editable
929 : 0 : if ( !info->hasUpsertOnEdit() )
930 : : {
931 : 0 : const QgsFeature joinedFeature = layer->joinBuffer()->joinedFeatureOf( info, feature );
932 : 0 : if ( !joinedFeature.isValid() )
933 : 0 : return false;
934 : 0 : }
935 : :
936 : 0 : return _fieldIsEditable( info->joinLayer(), srcFieldIndex, feature );
937 : : }
938 : : else
939 : 0 : return _fieldIsEditable( layer, fieldIndex, feature );
940 : 0 : }
941 : :
942 : :
943 : 0 : QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> QgsVectorLayerUtils::labelMasks( const QgsVectorLayer *layer )
944 : : {
945 : 0 : class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
946 : : {
947 : : public:
948 : 0 : bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
949 : : {
950 : 0 : if ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule )
951 : : {
952 : 0 : currentRule = node.identifier;
953 : 0 : return true;
954 : : }
955 : 0 : return false;
956 : 0 : }
957 : 0 : bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
958 : : {
959 : 0 : if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
960 : : {
961 : 0 : auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
962 : 0 : if ( labelSettingsEntity->settings().format().mask().enabled() )
963 : : {
964 : 0 : for ( const auto &r : labelSettingsEntity->settings().format().mask().maskedSymbolLayers() )
965 : : {
966 : 0 : masks[currentRule][r.layerId()].insert( r.symbolLayerId() );
967 : : }
968 : 0 : }
969 : 0 : }
970 : 0 : return true;
971 : 0 : }
972 : :
973 : : QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
974 : : // Current label rule, empty string for a simple labeling
975 : : QString currentRule;
976 : : };
977 : :
978 : 0 : if ( ! layer->labeling() )
979 : 0 : return {};
980 : :
981 : 0 : LabelMasksVisitor visitor;
982 : 0 : layer->labeling()->accept( &visitor );
983 : 0 : return std::move( visitor.masks );
984 : 0 : }
985 : :
986 : 0 : QHash<QString, QSet<QgsSymbolLayerId>> QgsVectorLayerUtils::symbolLayerMasks( const QgsVectorLayer *layer )
987 : : {
988 : 0 : if ( ! layer->renderer() )
989 : 0 : return {};
990 : :
991 : 0 : class SymbolLayerVisitor : public QgsStyleEntityVisitorInterface
992 : : {
993 : : public:
994 : 0 : bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
995 : : {
996 : 0 : return ( node.type == QgsStyleEntityVisitorInterface::NodeType::SymbolRule );
997 : : }
998 : :
999 : 0 : void visitSymbol( const QgsSymbol *symbol )
1000 : : {
1001 : 0 : for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
1002 : : {
1003 : 0 : const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
1004 : 0 : for ( const auto &mask : sl->masks() )
1005 : : {
1006 : 0 : masks[mask.layerId()].insert( mask.symbolLayerId() );
1007 : : }
1008 : : // recurse over sub symbols
1009 : 0 : const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol();
1010 : 0 : if ( subSymbol )
1011 : 0 : visitSymbol( subSymbol );
1012 : 0 : }
1013 : 0 : }
1014 : :
1015 : 0 : bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
1016 : : {
1017 : 0 : if ( leaf.entity && leaf.entity->type() == QgsStyle::SymbolEntity )
1018 : : {
1019 : 0 : auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
1020 : 0 : if ( symbolEntity->symbol() )
1021 : 0 : visitSymbol( symbolEntity->symbol() );
1022 : 0 : }
1023 : 0 : return true;
1024 : : }
1025 : : QHash<QString, QSet<QgsSymbolLayerId>> masks;
1026 : : };
1027 : :
1028 : 0 : SymbolLayerVisitor visitor;
1029 : 0 : layer->renderer()->accept( &visitor );
1030 : 0 : return visitor.masks;
1031 : 0 : }
1032 : :
1033 : 0 : QString QgsVectorLayerUtils::getFeatureDisplayString( const QgsVectorLayer *layer, const QgsFeature &feature )
1034 : : {
1035 : 0 : QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
1036 : :
1037 : 0 : QgsExpression exp( layer->displayExpression() );
1038 : 0 : context.setFeature( feature );
1039 : 0 : exp.prepare( &context );
1040 : 0 : QString displayString = exp.evaluate( &context ).toString();
1041 : :
1042 : 0 : return displayString;
1043 : 0 : }
1044 : :
1045 : 0 : bool QgsVectorLayerUtils::impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context, CascadedFeatureFlags flags )
1046 : : {
1047 : 0 : if ( !layer )
1048 : 0 : return false;
1049 : :
1050 : 0 : const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
1051 : 0 : for ( const QgsRelation &relation : relations )
1052 : : {
1053 : 0 : if ( relation.strength() == QgsRelation::Composition )
1054 : : {
1055 : 0 : QgsFeatureIds childFeatureIds;
1056 : :
1057 : 0 : const auto constFids = fids;
1058 : 0 : for ( const QgsFeatureId fid : constFids )
1059 : : {
1060 : : //get features connected over this relation
1061 : 0 : QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( layer->getFeature( fid ) );
1062 : 0 : QgsFeature childFeature;
1063 : 0 : while ( relatedFeaturesIt.nextFeature( childFeature ) )
1064 : : {
1065 : 0 : childFeatureIds.insert( childFeature.id() );
1066 : : }
1067 : 0 : }
1068 : :
1069 : 0 : if ( childFeatureIds.count() > 0 )
1070 : : {
1071 : 0 : if ( context.layers().contains( relation.referencingLayer() ) )
1072 : : {
1073 : 0 : QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( relation.referencingLayer() );
1074 : : // add feature ids
1075 : 0 : handledFeatureIds.unite( childFeatureIds );
1076 : 0 : context.setDuplicatedFeatures( relation.referencingLayer(), handledFeatureIds );
1077 : 0 : }
1078 : : else
1079 : : {
1080 : : // add layer and feature id
1081 : 0 : context.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
1082 : : }
1083 : 0 : }
1084 : 0 : }
1085 : : }
1086 : :
1087 : 0 : if ( layer->joinBuffer()->containsJoins() )
1088 : : {
1089 : 0 : const QgsVectorJoinList joins = layer->joinBuffer()->vectorJoins();
1090 : 0 : for ( const QgsVectorLayerJoinInfo &info : joins )
1091 : : {
1092 : 0 : if ( qobject_cast< QgsAuxiliaryLayer * >( info.joinLayer() ) && flags & IgnoreAuxiliaryLayers )
1093 : 0 : continue;
1094 : :
1095 : 0 : if ( info.isEditable() && info.hasCascadedDelete() )
1096 : : {
1097 : 0 : QgsFeatureIds joinFeatureIds;
1098 : 0 : const auto constFids = fids;
1099 : 0 : for ( const QgsFeatureId &fid : constFids )
1100 : : {
1101 : 0 : const QgsFeature joinFeature = layer->joinBuffer()->joinedFeatureOf( &info, layer->getFeature( fid ) );
1102 : 0 : if ( joinFeature.isValid() )
1103 : 0 : joinFeatureIds.insert( joinFeature.id() );
1104 : 0 : }
1105 : :
1106 : 0 : if ( joinFeatureIds.count() > 0 )
1107 : : {
1108 : 0 : if ( context.layers().contains( info.joinLayer() ) )
1109 : : {
1110 : 0 : QgsFeatureIds handledFeatureIds = context.duplicatedFeatures( info.joinLayer() );
1111 : : // add feature ids
1112 : 0 : handledFeatureIds.unite( joinFeatureIds );
1113 : 0 : context.setDuplicatedFeatures( info.joinLayer(), handledFeatureIds );
1114 : 0 : }
1115 : : else
1116 : : {
1117 : : // add layer and feature id
1118 : 0 : context.setDuplicatedFeatures( info.joinLayer(), joinFeatureIds );
1119 : : }
1120 : 0 : }
1121 : 0 : }
1122 : : }
1123 : 0 : }
1124 : :
1125 : 0 : return !context.layers().isEmpty();
1126 : 0 : }
1127 : :
1128 : 0 : QString QgsVectorLayerUtils::guessFriendlyIdentifierField( const QgsFields &fields )
1129 : : {
1130 : 0 : if ( fields.isEmpty() )
1131 : 0 : return QString();
1132 : :
1133 : : // Check the fields and keep the first one that matches.
1134 : : // We assume that the user has organized the data with the
1135 : : // more "interesting" field names first. As such, name should
1136 : : // be selected before oldname, othername, etc.
1137 : : // This candidates list is a prioritized list of candidates ranked by "interestingness"!
1138 : : // See discussion at https://github.com/qgis/QGIS/pull/30245 - this list must NOT be translated,
1139 : : // but adding hardcoded localized variants of the strings is encouraged.
1140 : 0 : static QStringList sCandidates{ QStringLiteral( "name" ),
1141 : 0 : QStringLiteral( "title" ),
1142 : 0 : QStringLiteral( "heibt" ),
1143 : 0 : QStringLiteral( "desc" ),
1144 : 0 : QStringLiteral( "nom" ),
1145 : 0 : QStringLiteral( "street" ),
1146 : 0 : QStringLiteral( "road" ) };
1147 : :
1148 : : // anti-names
1149 : : // this list of strings indicates parts of field names which make the name "less interesting".
1150 : : // For instance, we'd normally like to default to a field called "name" or "id", but if instead we
1151 : : // find one called "typename" or "typeid", then that's most likely a classification of the feature and not the
1152 : : // best choice to default to
1153 : 0 : static QStringList sAntiCandidates{ QStringLiteral( "type" ),
1154 : 0 : QStringLiteral( "class" ),
1155 : 0 : QStringLiteral( "cat" )
1156 : : };
1157 : :
1158 : 0 : QString bestCandidateName;
1159 : 0 : QString bestCandidateNameWithAntiCandidate;
1160 : :
1161 : 0 : for ( const QString &candidate : sCandidates )
1162 : : {
1163 : 0 : for ( const QgsField &field : fields )
1164 : : {
1165 : 0 : const QString fldName = field.name();
1166 : 0 : if ( fldName.contains( candidate, Qt::CaseInsensitive ) )
1167 : : {
1168 : 0 : bool isAntiCandidate = false;
1169 : 0 : for ( const QString &antiCandidate : sAntiCandidates )
1170 : : {
1171 : 0 : if ( fldName.contains( antiCandidate, Qt::CaseInsensitive ) )
1172 : : {
1173 : 0 : isAntiCandidate = true;
1174 : 0 : break;
1175 : : }
1176 : : }
1177 : :
1178 : 0 : if ( isAntiCandidate )
1179 : : {
1180 : 0 : if ( bestCandidateNameWithAntiCandidate.isEmpty() )
1181 : : {
1182 : 0 : bestCandidateNameWithAntiCandidate = fldName;
1183 : 0 : }
1184 : 0 : }
1185 : : else
1186 : : {
1187 : 0 : bestCandidateName = fldName;
1188 : 0 : break;
1189 : : }
1190 : 0 : }
1191 : 0 : }
1192 : :
1193 : 0 : if ( !bestCandidateName.isEmpty() )
1194 : 0 : break;
1195 : : }
1196 : :
1197 : 0 : const QString candidateName = bestCandidateName.isEmpty() ? bestCandidateNameWithAntiCandidate : bestCandidateName;
1198 : 0 : if ( !candidateName.isEmpty() )
1199 : : {
1200 : 0 : return candidateName;
1201 : : }
1202 : : else
1203 : : {
1204 : : // no good matches found by name, so scan through and look for the first string field
1205 : 0 : for ( const QgsField &field : fields )
1206 : : {
1207 : 0 : if ( field.type() == QVariant::String )
1208 : 0 : return field.name();
1209 : : }
1210 : :
1211 : : // no string fields found - just return first field
1212 : 0 : return fields.at( 0 ).name();
1213 : : }
1214 : 0 : }
|