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();
82 cacheJoinLayer( mVectorJoins.last() );
91 connectJoinedLayer( vl );
103 QMutexLocker locker( &mMutex );
105 for (
int i = 0; i < mVectorJoins.size(); ++i )
107 if ( mVectorJoins.at( i ).joinLayerId() == joinLayerId )
114 mVectorJoins.removeAt( i );
136 if ( joinFieldIndex < 0 || joinFieldIndex >= cacheLayer->
fields().
count() )
145 QVector<int> subsetIndices;
153 if ( !cacheLayerAttrs.contains( joinFieldIndex ) )
154 cacheLayerAttrs.append( joinFieldIndex );
163 QString key = attrs.at( joinFieldIndex ).toString();
167 for (
int i = 0; i < subsetIndices.count(); ++i )
168 subsetAttrs[i] = attrs.at( subsetIndices.at( i ) );
174 attrs2.remove( joinFieldIndex );
185 QVector<int> subsetIndices;
187 for (
int i = 0; i < joinFieldsSubset.count(); ++i )
189 QString joinedFieldName = joinFieldsSubset.
at( i );
193 subsetIndices.append( index );
197 QgsDebugMsg(
"Join layer subset field not found: " + joinedFieldName );
201 return subsetIndices;
208 QList< QgsVectorLayerJoinInfo>::const_iterator joinIt = mVectorJoins.constBegin();
209 for (
int joinIdx = 0; joinIt != mVectorJoins.constEnd(); ++joinIt, ++joinIdx )
218 QString joinFieldName = joinIt->joinFieldName();
220 QSet<QString> subset;
221 if ( joinIt->hasSubset() )
224 subset = qgis::listToSet( subsetNames );
227 if ( joinIt->prefix().isNull() )
229 prefix = joinLayer->
name() +
'_';
233 prefix = joinIt->prefix();
236 for (
int idx = 0; idx < joinFields.
count(); ++idx )
239 if ( joinIt->hasSubset() && !subset.contains( joinFields.
at( idx ).
name() ) )
244 if ( joinIt->hasSubset() || joinFields.
at( idx ).
name() != joinFieldName )
256 QMutexLocker locker( &mMutex );
257 QList< QgsVectorLayerJoinInfo >::iterator joinIt = mVectorJoins.begin();
258 for ( ; joinIt != mVectorJoins.end(); ++joinIt )
260 if ( joinIt->isUsingMemoryCache() && joinIt->cacheDirty )
261 cacheJoinLayer( *joinIt );
268 QDomElement vectorJoinsElem = document.createElement( QStringLiteral(
"vectorjoins" ) );
269 layer_node.appendChild( vectorJoinsElem );
270 QList< QgsVectorLayerJoinInfo >::const_iterator joinIt = mVectorJoins.constBegin();
271 for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
276 QDomElement joinElem = document.createElement( QStringLiteral(
"join" ) );
278 joinElem.setAttribute( QStringLiteral(
"targetFieldName" ), joinIt->targetFieldName() );
280 joinElem.setAttribute( QStringLiteral(
"joinLayerId" ), joinIt->joinLayerId() );
281 joinElem.setAttribute( QStringLiteral(
"joinFieldName" ), joinIt->joinFieldName() );
283 joinElem.setAttribute( QStringLiteral(
"memoryCache" ), joinIt->isUsingMemoryCache() );
284 joinElem.setAttribute( QStringLiteral(
"dynamicForm" ), joinIt->isDynamicFormEnabled() );
285 joinElem.setAttribute( QStringLiteral(
"editable" ), joinIt->isEditable() );
286 joinElem.setAttribute( QStringLiteral(
"upsertOnEdit" ), joinIt->hasUpsertOnEdit() );
287 joinElem.setAttribute( QStringLiteral(
"cascadedDelete" ), joinIt->hasCascadedDelete() );
289 if ( joinIt->hasSubset() )
291 QDomElement subsetElem = document.createElement( QStringLiteral(
"joinFieldsSubset" ) );
294 const auto constSubsetNames = subsetNames;
295 for (
const QString &fieldName : constSubsetNames )
297 QDomElement fieldElem = document.createElement( QStringLiteral(
"field" ) );
298 fieldElem.setAttribute( QStringLiteral(
"name" ), fieldName );
299 subsetElem.appendChild( fieldElem );
302 joinElem.appendChild( subsetElem );
305 if ( !joinIt->prefix().isNull() )
307 joinElem.setAttribute( QStringLiteral(
"customPrefix" ), joinIt->prefix() );
308 joinElem.setAttribute( QStringLiteral(
"hasCustomPrefix" ), 1 );
311 vectorJoinsElem.appendChild( joinElem );
317 mVectorJoins.clear();
318 QDomElement vectorJoinsElem = layer_node.firstChildElement( QStringLiteral(
"vectorjoins" ) );
319 if ( !vectorJoinsElem.isNull() )
321 QDomNodeList joinList = vectorJoinsElem.elementsByTagName( QStringLiteral(
"join" ) );
322 for (
int i = 0; i < joinList.size(); ++i )
324 QDomElement infoElem = joinList.at( i ).toElement();
326 info.
setJoinFieldName( infoElem.attribute( QStringLiteral(
"joinFieldName" ) ) );
328 info.
setJoinLayerId( infoElem.attribute( QStringLiteral(
"joinLayerId" ) ) );
332 info.
setEditable( infoElem.attribute( QStringLiteral(
"editable" ) ).toInt() );
333 info.
setUpsertOnEdit( infoElem.attribute( QStringLiteral(
"upsertOnEdit" ) ).toInt() );
334 info.
setCascadedDelete( infoElem.attribute( QStringLiteral(
"cascadedDelete" ) ).toInt() );
336 QDomElement subsetElem = infoElem.firstChildElement( QStringLiteral(
"joinFieldsSubset" ) );
337 if ( !subsetElem.isNull() )
339 QStringList *fieldNames =
new QStringList;
340 QDomNodeList fieldNodes = infoElem.elementsByTagName( QStringLiteral(
"field" ) );
341 fieldNames->reserve( fieldNodes.count() );
342 for (
int i = 0; i < fieldNodes.count(); ++i )
343 *fieldNames << fieldNodes.at( i ).toElement().attribute( QStringLiteral(
"name" ) );
347 if ( infoElem.attribute( QStringLiteral(
"hasCustomPrefix" ) ).toInt() )
348 info.
setPrefix( infoElem.attribute( QStringLiteral(
"customPrefix" ) ) );
359 bool resolved =
false;
360 for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
362 if ( it->joinLayer() )
365 if (
QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( project->
mapLayer( it->joinLayerId() ) ) )
367 it->setJoinLayer( joinedLayer );
368 connectJoinedLayer( joinedLayer );
382 int joinIndex = mVectorJoins.indexOf( *info );
383 if ( joinIndex == -1 )
386 for (
int i = 0; i < fields.
count(); ++i )
403 int sourceJoinIndex = originIndex / 1000;
404 sourceFieldIndex = originIndex % 1000;
406 if ( sourceJoinIndex < 0 || sourceJoinIndex >= mVectorJoins.count() )
409 return &( mVectorJoins[sourceJoinIndex] );
414 QList<const QgsVectorLayerJoinInfo *> infos;
416 const auto constMVectorJoins = mVectorJoins;
419 if ( infos.contains( &info ) )
422 if ( info.targetFieldName() == field.
name() )
423 infos.append( &info );
450 return joinedFeature;
470 return targetedFeature;
476 cloned->mVectorJoins = mVectorJoins;
480 void QgsVectorLayerJoinBuffer::joinedLayerUpdatedFields()
485 QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( sender() );
486 Q_ASSERT( joinedLayer );
489 for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
491 if ( joinedLayer == it->joinLayer() )
493 it->cachedAttributes.clear();
494 cacheJoinLayer( *it );
501 void QgsVectorLayerJoinBuffer::joinedLayerModified()
503 QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( sender() );
504 Q_ASSERT( joinedLayer );
507 for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
509 if ( joinedLayer == it->joinLayer() )
511 it->cacheDirty =
true;
516 void QgsVectorLayerJoinBuffer::joinedLayerWillBeDeleted()
518 QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( sender() );
519 Q_ASSERT( joinedLayer );
524 void QgsVectorLayerJoinBuffer::connectJoinedLayer(
QgsVectorLayer *vl )
542 if ( joinLayer && joinLayer->
isEditable() && info.isEditable() && info.hasUpsertOnEdit() )
546 const auto constFeatures = features;
547 for (
const QgsFeature &feature : constFeatures )
549 const QgsFeature joinFeature = info.extractJoinedFeature( feature );
553 const QVariant idFieldValue = feature.
attribute( info.targetFieldName() );
566 if ( existingFeature.
isValid() )
568 if ( info.hasSubset() )
571 const auto constSubsetNames = subsetNames;
572 for (
const QString &field : constSubsetNames )
574 QVariant newValue = joinFeature.
attribute( field );
582 for (
const auto &field : joinFields )
584 QVariant newValue = joinFeature.
attribute( field.name() );
585 int fieldIndex = joinLayer->
fields().
indexOf( field.name() );
593 bool notNullFields =
false;
595 for (
const auto &field : joinFields )
597 if ( field.name() == info.joinFieldName() )
600 if ( !joinFeature.
attribute( field.name() ).isNull() )
602 notNullFields =
true;
608 joinFeatures << joinFeature;
651 for (
auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
653 const int field = it.key();
654 const QVariant newValue = it.value();
657 if ( oldValues.contains( field ) )
658 oldValue = oldValues[field];
676 const auto constFids = fids;
682 if ( info.isEditable() && info.hasCascadedDelete() )
686 info.joinLayer()->deleteFeature( joinFeature.
id(), context );