26 #include <QDomElement>    35   QList<QgsVectorLayer *> lst;
    44 static bool _hasCycleDFS( 
QgsVectorLayer *n, QHash<QgsVectorLayer *, int> &mark )
    46   if ( mark.value( n ) == 1 ) 
    48   if ( mark.value( n ) == 0 ) 
    53       if ( _hasCycleDFS( m, mark ) )
    64   QMutexLocker locker( &mMutex );
    65   mVectorJoins.push_back( joinInfo );
    69   QHash<QgsVectorLayer *, int> markDFS;
    70   if ( mLayer && _hasCycleDFS( mLayer, markDFS ) )
    73     mVectorJoins.pop_back();
    80     cacheJoinLayer( mVectorJoins.last() );
    89     connectJoinedLayer( vl );
   101   QMutexLocker locker( &mMutex );
   103   for ( 
int i = 0; i < mVectorJoins.size(); ++i )
   105     if ( mVectorJoins.at( i ).joinLayerId() == joinLayerId )
   112       mVectorJoins.removeAt( i );
   134     if ( joinFieldIndex < 0 || joinFieldIndex >= cacheLayer->
fields().
count() )
   143     QVector<int> subsetIndices;
   151       if ( !cacheLayerAttrs.contains( joinFieldIndex ) )
   152         cacheLayerAttrs.append( joinFieldIndex );
   161       QString key = attrs.at( joinFieldIndex ).toString();
   165         for ( 
int i = 0; i < subsetIndices.count(); ++i )
   166           subsetAttrs[i] = attrs.at( subsetIndices.at( i ) );
   172         attrs2.remove( joinFieldIndex );  
   183   QVector<int> subsetIndices;
   185   for ( 
int i = 0; i < joinFieldsSubset.count(); ++i )
   187     QString joinedFieldName = joinFieldsSubset.
at( i );
   191       subsetIndices.append( index );
   195       QgsDebugMsg( 
"Join layer subset field not found: " + joinedFieldName );
   199   return subsetIndices;
   206   QList< QgsVectorLayerJoinInfo>::const_iterator joinIt = mVectorJoins.constBegin();
   207   for ( 
int joinIdx = 0; joinIt != mVectorJoins.constEnd(); ++joinIt, ++joinIdx )
   216     QString joinFieldName = joinIt->joinFieldName();
   218     QSet<QString> subset;
   219     if ( joinIt->hasSubset() )
   222       subset = QSet<QString>::fromList( subsetNames );
   225     if ( joinIt->prefix().isNull() )
   227       prefix = joinLayer->
name() + 
'_';
   231       prefix = joinIt->prefix();
   234     for ( 
int idx = 0; idx < joinFields.
count(); ++idx )
   237       if ( joinIt->hasSubset() && !subset.contains( joinFields.
at( idx ).
name() ) )
   242       if ( joinIt->hasSubset() || joinFields.
at( idx ).
name() != joinFieldName )
   254   QMutexLocker locker( &mMutex );
   255   QList< QgsVectorLayerJoinInfo >::iterator joinIt = mVectorJoins.begin();
   256   for ( ; joinIt != mVectorJoins.end(); ++joinIt )
   258     if ( joinIt->isUsingMemoryCache() && joinIt->cacheDirty )
   259       cacheJoinLayer( *joinIt );
   266   QDomElement vectorJoinsElem = document.createElement( QStringLiteral( 
"vectorjoins" ) );
   267   layer_node.appendChild( vectorJoinsElem );
   268   QList< QgsVectorLayerJoinInfo >::const_iterator joinIt = mVectorJoins.constBegin();
   269   for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
   274     QDomElement joinElem = document.createElement( QStringLiteral( 
"join" ) );
   276     joinElem.setAttribute( QStringLiteral( 
"targetFieldName" ), joinIt->targetFieldName() );
   278     joinElem.setAttribute( QStringLiteral( 
"joinLayerId" ), joinIt->joinLayerId() );
   279     joinElem.setAttribute( QStringLiteral( 
"joinFieldName" ), joinIt->joinFieldName() );
   281     joinElem.setAttribute( QStringLiteral( 
"memoryCache" ), joinIt->isUsingMemoryCache() );
   282     joinElem.setAttribute( QStringLiteral( 
"dynamicForm" ), joinIt->isDynamicFormEnabled() );
   283     joinElem.setAttribute( QStringLiteral( 
"editable" ), joinIt->isEditable() );
   284     joinElem.setAttribute( QStringLiteral( 
"upsertOnEdit" ), joinIt->hasUpsertOnEdit() );
   285     joinElem.setAttribute( QStringLiteral( 
"cascadedDelete" ), joinIt->hasCascadedDelete() );
   287     if ( joinIt->hasSubset() )
   289       QDomElement subsetElem = document.createElement( QStringLiteral( 
"joinFieldsSubset" ) );
   292       Q_FOREACH ( 
const QString &fieldName, subsetNames )
   294         QDomElement fieldElem = document.createElement( QStringLiteral( 
"field" ) );
   295         fieldElem.setAttribute( QStringLiteral( 
"name" ), fieldName );
   296         subsetElem.appendChild( fieldElem );
   299       joinElem.appendChild( subsetElem );
   302     if ( !joinIt->prefix().isNull() )
   304       joinElem.setAttribute( QStringLiteral( 
"customPrefix" ), joinIt->prefix() );
   305       joinElem.setAttribute( QStringLiteral( 
"hasCustomPrefix" ), 1 );
   308     vectorJoinsElem.appendChild( joinElem );
   314   mVectorJoins.clear();
   315   QDomElement vectorJoinsElem = layer_node.firstChildElement( QStringLiteral( 
"vectorjoins" ) );
   316   if ( !vectorJoinsElem.isNull() )
   318     QDomNodeList joinList = vectorJoinsElem.elementsByTagName( QStringLiteral( 
"join" ) );
   319     for ( 
int i = 0; i < joinList.size(); ++i )
   321       QDomElement infoElem = joinList.at( i ).toElement();
   323       info.
setJoinFieldName( infoElem.attribute( QStringLiteral( 
"joinFieldName" ) ) );
   325       info.
setJoinLayerId( infoElem.attribute( QStringLiteral( 
"joinLayerId" ) ) );
   329       info.
setEditable( infoElem.attribute( QStringLiteral( 
"editable" ) ).toInt() );
   330       info.
setUpsertOnEdit( infoElem.attribute( QStringLiteral( 
"upsertOnEdit" ) ).toInt() );
   331       info.
setCascadedDelete( infoElem.attribute( QStringLiteral( 
"cascadedDelete" ) ).toInt() );
   333       QDomElement subsetElem = infoElem.firstChildElement( QStringLiteral( 
"joinFieldsSubset" ) );
   334       if ( !subsetElem.isNull() )
   336         QStringList *fieldNames = 
new QStringList;
   337         QDomNodeList fieldNodes = infoElem.elementsByTagName( QStringLiteral( 
"field" ) );
   338         fieldNames->reserve( fieldNodes.count() );
   339         for ( 
int i = 0; i < fieldNodes.count(); ++i )
   340           *fieldNames << fieldNodes.at( i ).toElement().attribute( QStringLiteral( 
"name" ) );
   344       if ( infoElem.attribute( QStringLiteral( 
"hasCustomPrefix" ) ).toInt() )
   345         info.
setPrefix( infoElem.attribute( QStringLiteral( 
"customPrefix" ) ) );
   356   bool resolved = 
false;
   357   for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
   359     if ( it->joinLayer() )
   362     if ( 
QgsVectorLayer *joinedLayer = qobject_cast<QgsVectorLayer *>( project->
mapLayer( it->joinLayerId() ) ) )
   364       it->setJoinLayer( joinedLayer );
   365       connectJoinedLayer( joinedLayer );
   379   int joinIndex = mVectorJoins.indexOf( *info );
   380   if ( joinIndex == -1 )
   383   for ( 
int i = 0; i < fields.
count(); ++i )
   400   int sourceJoinIndex = originIndex / 1000;
   401   sourceFieldIndex = originIndex % 1000;
   403   if ( sourceJoinIndex < 0 || sourceJoinIndex >= mVectorJoins.count() )
   406   return &( mVectorJoins[sourceJoinIndex] );
   411   QList<const QgsVectorLayerJoinInfo *> infos;
   415     if ( infos.contains( &info ) )
   419       infos.append( &info );
   446   return joinedFeature;
   466   return targetedFeature;
   472   cloned->mVectorJoins = mVectorJoins;
   476 void QgsVectorLayerJoinBuffer::joinedLayerUpdatedFields()
   482   Q_ASSERT( joinedLayer );
   485   for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
   487     if ( joinedLayer == it->joinLayer() )
   489       it->cachedAttributes.clear();
   490       cacheJoinLayer( *it );
   497 void QgsVectorLayerJoinBuffer::joinedLayerModified()
   500   Q_ASSERT( joinedLayer );
   503   for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
   505     if ( joinedLayer == it->joinLayer() )
   507       it->cacheDirty = 
true;
   512 void QgsVectorLayerJoinBuffer::joinedLayerWillBeDeleted()
   515   Q_ASSERT( joinedLayer );
   520 void QgsVectorLayerJoinBuffer::connectJoinedLayer( 
QgsVectorLayer *vl )
   541       Q_FOREACH ( 
const QgsFeature &feature, features )
   560         if ( existingFeature.
isValid() )
   565             Q_FOREACH ( 
const QString &field, subsetNames )
   567               QVariant newValue = joinFeature.
attribute( field );
   575             for ( 
const auto &field : joinFields )
   577               QVariant newValue = joinFeature.
attribute( field.name() );
   578               int fieldIndex = joinLayer->
fields().
indexOf( field.name() );
   586           bool notNullFields = 
false;
   588           for ( 
const auto &field : joinFields )
   593             if ( !joinFeature.
attribute( field.name() ).isNull() )
   595               notNullFields = 
true;
   601             joinFeatures << joinFeature;
   644   for ( 
auto it = newValues.constBegin(); it != newValues.constEnd(); ++it )
   646     const int field = it.key();
   647     const QVariant newValue = it.value();
   650     if ( oldValues.contains( field ) )
   651       oldValue = oldValues[field];
 bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) override
Adds a list of features in joined layers. 
 
const QList< QgsVectorLayerJoinInfo > vectorJoins() const 
 
Wrapper for iterator of features from vector data provider or vector layer. 
 
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
 
QSet< QgsFeatureId > QgsFeatureIds
 
QgsFeature joinedFeatureOf(const QgsVectorLayerJoinInfo *info, const QgsFeature &feature) const 
Returns the joined feature corresponding to the feature. 
 
QString joinLayerId() const 
ID of the joined layer - may be used to resolve reference to the joined layer. 
 
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name. 
 
void createJoinCaches()
Calls cacheJoinLayer() for all vector joins. 
 
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const 
Finds the vector join for a layer field index. 
 
bool isValid() const 
Returns the validity of this feature. 
 
QList< const QgsVectorLayerJoinInfo * > joinsWhereFieldIsId(const QgsField &field) const 
Returns joins where the field of a target layer is considered as an id. 
 
void setEditable(bool enabled)
Sets whether the form of the target layer allows editing joined fields. 
 
bool hasUpsertOnEdit() const 
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
 
bool deleteFeature(QgsFeatureId fid)
Deletes a feature from the layer (but does not commit it). 
 
Class allowing to manage the auxiliary storage for a vector layer. 
 
QList< QgsFeature > QgsFeatureList
 
const QgsVectorJoinList & vectorJoins() const 
 
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
 
QString targetFieldName() const 
Returns name of the field of our layer that will be used for join. 
 
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched. 
 
void readXml(const QDomNode &layer_node)
Reads joins from project file. 
 
void setJoinFieldName(const QString &fieldName)
Sets name of the field of joined layer that will be used for join. 
 
Container of fields for a vector layer. 
 
void setName(const QString &name)
Set the field name. 
 
bool setAttribute(int field, const QVariant &attr)
Set an attribute's value by field index. 
 
void setDynamicFormEnabled(bool enabled)
Sets whether the form has to be dynamically updated with joined fields when a feature is being create...
 
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
 
QgsVectorLayerJoinBuffer(QgsVectorLayer *layer=nullptr)
 
QgsField at(int i) const 
Gets field at particular index (must be in range 0..N-1) 
 
QHash< QString, QgsAttributes > cachedAttributes
Cache for joined attributes to provide fast lookup (size is 0 if no memory caching) ...
 
Manages joined fields for a vector layer. 
 
QgsVectorLayerJoinBuffer * clone() const 
Create a copy of the join buffer. 
 
bool containsJoins() const 
Quick way to test if there is any join at all. 
 
bool isUsingMemoryCache() const 
Returns whether values from the joined layer should be cached in memory to speed up lookups...
 
bool isEditable() const 
Returns whether joined fields may be edited through the form of the target layer. ...
 
bool isEditable() const FINAL
Returns true if the provider is in editing mode. 
 
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changes attribute value in joined layers. 
 
bool deleteFeature(QgsFeatureId fid) const 
Deletes a feature from joined layers. 
 
void setUpsertOnEdit(bool enabled)
Sets whether a feature created on the target layer has to impact the joined layer by creating a new f...
 
QgsFeature getFeature(QgsFeatureId fid) const 
Query the layer for the feature with the given id. 
 
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression. 
 
QgsFields fields() const FINAL
Returns the list of fields of this layer. 
 
QgsFeature extractJoinedFeature(const QgsFeature &feature) const 
Extract the join feature from the target feature for the current join layer information. 
 
QStringList * joinFieldNamesSubset() const 
Gets subset of fields to be used from joined layer. 
 
bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues=QgsAttributeMap())
Changes attributes' values in joined layers. 
 
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched. 
 
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields. 
 
Defines left outer join from our vector layer to some other vector layer. 
 
QMap< int, QVariant > QgsAttributeMap
 
int fieldOriginIndex(int fieldIdx) const 
Gets field's origin index (its meaning is specific to each type of origin) 
 
QString joinFieldName() const 
Returns name of the field of joined layer that will be used for join. 
 
This class wraps a request for features to a vector layer (or directly its vector data provider)...
 
QgsFeature targetedFeatureOf(const QgsVectorLayerJoinInfo *info, const QgsFeature &feature) const 
Returns the targeted feature corresponding to the joined feature. 
 
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join. 
 
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a list of features to the sink. 
 
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
 
QString id() const 
Returns the layer's unique ID, which is used to access this layer from QgsProject. 
 
Reads and writes project states. 
 
int count() const 
Returns number of items. 
 
void setUsingMemoryCache(bool enabled)
Sets whether values from the joined layer should be cached in memory to speed up lookups. 
 
Encapsulate a field in an attribute table or data source. 
 
int lookupField(const QString &fieldName) const 
Looks up field's index from the field name. 
 
int indexOf(const QString &fieldName) const 
Gets the field index from the field name. 
 
bool cacheDirty
True if the cached join attributes need to be updated. 
 
void setTargetFieldName(const QString &fieldName)
Sets name of the field of our layer that will be used for join. 
 
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value)
Create an expression allowing to evaluate if a field is equal to a value. 
 
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer. 
 
int indexFromName(const QString &fieldName) const 
Gets the field index from the field name. 
 
bool hasSubset(bool blacklisted=true) const 
Returns true if blacklisted fields is not empty or if a subset of names has been set. 
 
void setPrefix(const QString &prefix)
Sets prefix of fields from the joined layer. If null, joined layer's name will be used...
 
QVariant attribute(const QString &name) const 
Lookup attribute value from attribute name. 
 
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer. 
 
bool hasCascadedDelete() const 
Returns whether a feature deleted on the target layer has to impact the joined layer by deleting the ...
 
QgsMapLayer * mapLayer(const QString &layerId) const 
Retrieve a pointer to a registered layer by layer ID. 
 
void writeXml(QDomNode &layer_node, QDomDocument &document) const 
Saves mVectorJoins to xml under the layer node. 
 
void updateFields(QgsFields &fields)
Updates field map with joined attributes. 
 
static QVector< int > joinSubsetIndices(QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset)
Returns a vector of indices for use in join based on field names from the layer. 
 
FieldOrigin fieldOrigin(int fieldIdx) const 
Gets field's origin (value from an enumeration) 
 
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request. 
 
bool deleteFeatures(const QgsFeatureIds &fids) const 
Deletes a list of features from joined layers. 
 
void setCascadedDelete(bool enabled)
Sets whether a feature deleted on the target layer has to impact the joined layer by deleting the cor...
 
void joinedFieldsChanged()
Emitted whenever the list of joined fields changes (e.g. 
 
QgsVectorLayer * joinLayer() const 
Returns joined layer (may be null if the reference was set by layer ID and not resolved yet) ...
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request. 
 
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes). 
 
QList< int > QgsAttributeList
 
bool nextFeature(QgsFeature &f)
 
Geometry is not required. It may still be returned if e.g. required for a filter condition. 
 
Represents a vector layer which manages a vector based data sets. 
 
void updatedFields()
Is emitted, whenever the fields available from this layer have been changed. 
 
void layerModified()
This signal is emitted when modifications has been done on layer. 
 
void setJoinFieldNamesSubset(QStringList *fieldNamesSubset)
Set subset of fields to be used from joined layer. 
 
void resolveReferences(QgsProject *project)
Resolves layer IDs of joined layers using given project's available layers. 
 
void setJoinLayerId(const QString &layerId)
Sets ID of the joined layer. It will need to be overwritten by setJoinLayer() to a reference to real ...
 
int joinedFieldsOffset(const QgsVectorLayerJoinInfo *info, const QgsFields &fields)
Find out what is the first index of the join within fields. 
 
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched. 
 
bool isAuxiliaryJoin(const QgsVectorLayerJoinInfo &info) const 
Returns true if the join information is about auxiliary layer, false otherwise.