26 #include <QDomElement>
35 QList<QgsVectorLayer *> lst;
45 static bool _hasCycleDFS(
QgsVectorLayer *n, QHash<QgsVectorLayer *, int> &mark )
47 if ( mark.value( n ) == 1 )
49 if ( mark.value( n ) == 0 )
52 const auto outEdges { _outEdges( n ) };
55 if ( _hasCycleDFS( m, mark ) )
66 QMutexLocker locker( &mMutex );
67 mVectorJoins.push_back( joinInfo );
71 QHash<QgsVectorLayer *, int> markDFS;
72 if ( mLayer && _hasCycleDFS( mLayer, markDFS ) )
75 mVectorJoins.pop_back();
85 connectJoinedLayer( vl );
95 cacheJoinLayer( mVectorJoins.last() );
108 QMutexLocker locker( &mMutex );
109 for (
int i = 0; i < mVectorJoins.size(); ++i )
111 if ( mVectorJoins.at( i ).joinLayerId() == joinLayerId )
118 mVectorJoins.removeAt( i );
141 if ( joinFieldIndex < 0 || joinFieldIndex >= cacheLayer->
fields().
count() )
150 QVector<int> subsetIndices;
158 if ( !cacheLayerAttrs.contains( joinFieldIndex ) )
159 cacheLayerAttrs.append( joinFieldIndex );
168 QString key = attrs.at( joinFieldIndex ).toString();
172 for (
int i = 0; i < subsetIndices.count(); ++i )
173 subsetAttrs[i] = attrs.at( subsetIndices.at( i ) );
179 for (
int i = 0; i < attrs.size(); i++ )
181 if ( i == joinFieldIndex )
184 QString joinInfoPrefix = joinInfo.
prefix();
185 if ( joinInfoPrefix.isNull() )
186 joinInfoPrefix = QString(
"%1_" ).arg( cacheLayer->
name() );
189 const QString joinFieldName = joinInfoPrefix + cacheLayer->
fields().
names().at( i );
197 attributesCache.append( attrs.at( i ) );
214 QVector<int> subsetIndices;
215 for (
int i = 0; i < joinFieldsSubset.count(); ++i )
217 QString joinedFieldName = joinFieldsSubset.at( i );
218 int index = joinLayerFields.
lookupField( joinedFieldName );
221 subsetIndices.append( index );
225 QgsDebugMsg(
"Join layer subset field not found: " + joinedFieldName );
229 return subsetIndices;
236 QList< QgsVectorLayerJoinInfo>::const_iterator joinIt = mVectorJoins.constBegin();
237 for (
int joinIdx = 0; joinIt != mVectorJoins.constEnd(); ++joinIt, ++joinIdx )
246 QString joinFieldName = joinIt->joinFieldName();
248 QSet<QString> subset;
249 if ( joinIt->hasSubset() )
252 subset = qgis::listToSet( subsetNames );
255 if ( joinIt->prefix().isNull() )
257 prefix = joinLayer->
name() +
'_';
261 prefix = joinIt->prefix();
264 for (
int idx = 0; idx < joinFields.
count(); ++idx )
267 if ( joinIt->hasSubset() && !subset.contains( joinFields.
at( idx ).
name() ) )
272 if ( joinIt->hasSubset() || joinFields.
at( idx ).
name() != joinFieldName )
284 QMutexLocker locker( &mMutex );
285 QList< QgsVectorLayerJoinInfo >::iterator joinIt = mVectorJoins.begin();
286 for ( ; joinIt != mVectorJoins.end(); ++joinIt )
288 if ( joinIt->isUsingMemoryCache() && joinIt->cacheDirty )
289 cacheJoinLayer( *joinIt );
296 QDomElement vectorJoinsElem = document.createElement( QStringLiteral(
"vectorjoins" ) );
297 layer_node.appendChild( vectorJoinsElem );
298 QList< QgsVectorLayerJoinInfo >::const_iterator joinIt = mVectorJoins.constBegin();
299 for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
304 QDomElement joinElem = document.createElement( QStringLiteral(
"join" ) );
306 joinElem.setAttribute( QStringLiteral(
"targetFieldName" ), joinIt->targetFieldName() );
308 joinElem.setAttribute( QStringLiteral(
"joinLayerId" ), joinIt->joinLayerId() );
309 joinElem.setAttribute( QStringLiteral(
"joinFieldName" ), joinIt->joinFieldName() );
311 joinElem.setAttribute( QStringLiteral(
"memoryCache" ), joinIt->isUsingMemoryCache() );
312 joinElem.setAttribute( QStringLiteral(
"dynamicForm" ), joinIt->isDynamicFormEnabled() );
313 joinElem.setAttribute( QStringLiteral(
"editable" ), joinIt->isEditable() );
314 joinElem.setAttribute( QStringLiteral(
"upsertOnEdit" ), joinIt->hasUpsertOnEdit() );
315 joinElem.setAttribute( QStringLiteral(
"cascadedDelete" ), joinIt->hasCascadedDelete() );
317 if ( joinIt->hasSubset() )
319 QDomElement subsetElem = document.createElement( QStringLiteral(
"joinFieldsSubset" ) );
322 const auto constSubsetNames = subsetNames;
323 for (
const QString &fieldName : constSubsetNames )
325 QDomElement fieldElem = document.createElement( QStringLiteral(
"field" ) );
326 fieldElem.setAttribute( QStringLiteral(
"name" ), fieldName );
327 subsetElem.appendChild( fieldElem );
330 joinElem.appendChild( subsetElem );
333 if ( !joinIt->prefix().isNull() )
335 joinElem.setAttribute( QStringLiteral(
"customPrefix" ), joinIt->prefix() );
336 joinElem.setAttribute( QStringLiteral(
"hasCustomPrefix" ), 1 );
339 vectorJoinsElem.appendChild( joinElem );
345 mVectorJoins.clear();
346 QDomElement vectorJoinsElem = layer_node.firstChildElement( QStringLiteral(
"vectorjoins" ) );
347 if ( !vectorJoinsElem.isNull() )
349 QDomNodeList joinList = vectorJoinsElem.elementsByTagName( QStringLiteral(
"join" ) );
350 for (
int i = 0; i < joinList.size(); ++i )
352 QDomElement infoElem = joinList.at( i ).toElement();
354 info.
setJoinFieldName( infoElem.attribute( QStringLiteral(
"joinFieldName" ) ) );
356 info.
setJoinLayerId( infoElem.attribute( QStringLiteral(
"joinLayerId" ) ) );
360 info.
setEditable( infoElem.attribute( QStringLiteral(
"editable" ) ).toInt() );
361 info.
setUpsertOnEdit( infoElem.attribute( QStringLiteral(
"upsertOnEdit" ) ).toInt() );
362 info.
setCascadedDelete( infoElem.attribute( QStringLiteral(
"cascadedDelete" ) ).toInt() );
364 QDomElement subsetElem = infoElem.firstChildElement( QStringLiteral(
"joinFieldsSubset" ) );
365 if ( !subsetElem.isNull() )
367 QStringList *fieldNames =
new QStringList;
368 QDomNodeList fieldNodes = infoElem.elementsByTagName( QStringLiteral(
"field" ) );
369 fieldNames->reserve( fieldNodes.count() );
370 for (
int i = 0; i < fieldNodes.count(); ++i )
371 *fieldNames << fieldNodes.at( i ).toElement().attribute( QStringLiteral(
"name" ) );
375 if ( infoElem.attribute( QStringLiteral(
"hasCustomPrefix" ) ).toInt() )
376 info.
setPrefix( infoElem.attribute( QStringLiteral(
"customPrefix" ) ) );
387 bool resolved =
false;
388 for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
390 if ( it->joinLayer() )
393 if (
QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( project->
mapLayer( it->joinLayerId() ) ) )
395 it->setJoinLayer( joinedLayer );
396 connectJoinedLayer( joinedLayer );
410 int joinIndex = mVectorJoins.indexOf( *info );
411 if ( joinIndex == -1 )
414 for (
int i = 0; i < fields.
count(); ++i )
431 int sourceJoinIndex = originIndex / 1000;
432 sourceFieldIndex = originIndex % 1000;
434 if ( sourceJoinIndex < 0 || sourceJoinIndex >= mVectorJoins.count() )
437 return &( mVectorJoins[sourceJoinIndex] );
442 QList<const QgsVectorLayerJoinInfo *> infos;
444 const auto constMVectorJoins = mVectorJoins;
447 if ( infos.contains( &info ) )
450 if ( info.targetFieldName() ==
field.
name() )
451 infos.append( &info );
478 return joinedFeature;
498 return targetedFeature;
504 cloned->mVectorJoins = mVectorJoins;
508 void QgsVectorLayerJoinBuffer::joinedLayerUpdatedFields()
513 QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( sender() );
514 Q_ASSERT( joinedLayer );
517 for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
519 if ( joinedLayer == it->joinLayer() )
521 it->cachedAttributes.clear();
522 cacheJoinLayer( *it );
529 void QgsVectorLayerJoinBuffer::joinedLayerModified()
531 QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( sender() );
532 Q_ASSERT( joinedLayer );
535 for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
537 if ( joinedLayer == it->joinLayer() )
539 it->cacheDirty =
true;
544 void QgsVectorLayerJoinBuffer::joinedLayerWillBeDeleted()
546 QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( sender() );
547 Q_ASSERT( joinedLayer );
552 void QgsVectorLayerJoinBuffer::connectJoinedLayer(
QgsVectorLayer *vl )
570 if ( joinLayer && joinLayer->
isEditable() && info.isEditable() && info.hasUpsertOnEdit() )
574 for (
const QgsFeature &feature : std::as_const( features ) )
576 const QgsFeature joinFeature = info.extractJoinedFeature( feature );
580 const QVariant idFieldValue = feature.
attribute( info.targetFieldName() );
593 if ( existingFeature.
isValid() )
595 if ( info.hasSubset() )
598 const auto constSubsetNames = subsetNames;
599 for (
const QString &
field : constSubsetNames )
609 for (
const auto &
field : joinFields )
620 bool notNullFields =
false;
622 for (
const auto &
field : joinFields )
624 if (
field.
name() == info.joinFieldName() )
629 notNullFields =
true;
635 joinFeatures << joinFeature;
678 for (
auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
680 const int field = it.key();
681 const QVariant newValue = it.value();
684 if ( oldValues.contains(
field ) )
685 oldValue = oldValues[
field];
703 const auto constFids = fids;
709 if ( info.isEditable() && info.hasCascadedDelete() )
713 info.joinLayer()->deleteFeature( joinFeature.
id(), context );