diff --git a/python/core/qgsvectorlayerjoininfo.sip b/python/core/qgsvectorlayerjoininfo.sip index 9dfab650625..d11753549af 100644 --- a/python/core/qgsvectorlayerjoininfo.sip +++ b/python/core/qgsvectorlayerjoininfo.sip @@ -166,6 +166,23 @@ Returns whether values from the joined layer should be cached in memory to speed :rtype: QgsFeature %End + void setJoinFieldNamesBlackList( const QStringList &blackList ); + + QStringList joinFieldNamesBlackList() const; +%Docstring + :rtype: list of str +%End + + bool hasSubset( bool blacklisted = true ) const; +%Docstring + :rtype: bool +%End + + static QStringList joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted = true ); +%Docstring + :rtype: list of str +%End + bool operator==( const QgsVectorLayerJoinInfo &other ) const; void setJoinFieldNamesSubset( QStringList *fieldNamesSubset /Transfer/ ); @@ -194,6 +211,7 @@ Returns whether values from the joined layer should be cached in memory to speed + }; diff --git a/src/core/qgsauxiliarystorage.cpp b/src/core/qgsauxiliarystorage.cpp index 5c5b5333ad5..0645dfc3cb9 100644 --- a/src/core/qgsauxiliarystorage.cpp +++ b/src/core/qgsauxiliarystorage.cpp @@ -168,6 +168,7 @@ QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &fil mJoinInfo.setEditable( true ); mJoinInfo.setUpsertOnEdit( true ); mJoinInfo.setCascadedDelete( true ); + mJoinInfo.setJoinFieldNamesBlackList( QStringList() << "rowid" ); // introduced by ogr provider } QgsVectorLayer *QgsAuxiliaryLayer::toSpatialLayer() const diff --git a/src/core/qgsvectorlayerfeatureiterator.cpp b/src/core/qgsvectorlayerfeatureiterator.cpp index a9c73cdf7ef..f27f19678c7 100644 --- a/src/core/qgsvectorlayerfeatureiterator.cpp +++ b/src/core/qgsvectorlayerfeatureiterator.cpp @@ -944,10 +944,12 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg // maybe user requested just a subset of layer's attributes // so we do not have to cache everything - bool hasSubset = joinInfo->joinFieldNamesSubset(); QVector subsetIndices; - if ( hasSubset ) - subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, *joinInfo->joinFieldNamesSubset() ); + if ( joinInfo->hasSubset() ) + { + const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo ); + subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames ); + } // select (no geometry) QgsFeatureRequest request; @@ -963,7 +965,7 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg { int index = indexOffset; QgsAttributes attr = fet.attributes(); - if ( hasSubset ) + if ( joinInfo->hasSubset() ) { for ( int i = 0; i < subsetIndices.count(); ++i ) f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) ); diff --git a/src/core/qgsvectorlayerjoinbuffer.cpp b/src/core/qgsvectorlayerjoinbuffer.cpp index 2caab0521f0..2255df373d0 100644 --- a/src/core/qgsvectorlayerjoinbuffer.cpp +++ b/src/core/qgsvectorlayerjoinbuffer.cpp @@ -137,11 +137,11 @@ void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorLayerJoinInfo &joinInfo request.setFlags( QgsFeatureRequest::NoGeometry ); // maybe user requested just a subset of layer's attributes // so we do not have to cache everything - bool hasSubset = joinInfo.joinFieldNamesSubset(); QVector subsetIndices; - if ( hasSubset ) + if ( joinInfo.hasSubset() ) { - subsetIndices = joinSubsetIndices( cacheLayer, *joinInfo.joinFieldNamesSubset() ); + const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( joinInfo ); + subsetIndices = joinSubsetIndices( cacheLayer, subsetNames ); // we need just subset of attributes - but make sure to include join field name QgsAttributeList cacheLayerAttrs = subsetIndices.toList(); @@ -156,7 +156,7 @@ void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorLayerJoinInfo &joinInfo { QgsAttributes attrs = f.attributes(); QString key = attrs.at( joinFieldIndex ).toString(); - if ( hasSubset ) + if ( joinInfo.hasSubset() ) { QgsAttributes subsetAttrs( subsetIndices.count() ); for ( int i = 0; i < subsetIndices.count(); ++i ) @@ -213,11 +213,10 @@ void QgsVectorLayerJoinBuffer::updateFields( QgsFields &fields ) QString joinFieldName = joinIt->joinFieldName(); QSet subset; - bool hasSubset = false; - if ( joinIt->joinFieldNamesSubset() ) + if ( joinIt->hasSubset() ) { - hasSubset = true; - subset = QSet::fromList( *joinIt->joinFieldNamesSubset() ); + const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinIt ); + subset = QSet::fromList( subsetNames ); } if ( joinIt->prefix().isNull() ) @@ -232,12 +231,12 @@ void QgsVectorLayerJoinBuffer::updateFields( QgsFields &fields ) for ( int idx = 0; idx < joinFields.count(); ++idx ) { // if using just a subset of fields, filter some of them out - if ( hasSubset && !subset.contains( joinFields.at( idx ).name() ) ) + if ( joinIt->hasSubset() && !subset.contains( joinFields.at( idx ).name() ) ) continue; //skip the join field to avoid double field names (fields often have the same name) // when using subset of field, use all the selected fields - if ( hasSubset || joinFields.at( idx ).name() != joinFieldName ) + if ( joinIt->hasSubset() || joinFields.at( idx ).name() != joinFieldName ) { QgsField f = joinFields.at( idx ); f.setName( prefix + f.name() ); @@ -279,10 +278,12 @@ void QgsVectorLayerJoinBuffer::writeXml( QDomNode &layer_node, QDomDocument &doc joinElem.setAttribute( QStringLiteral( "upsertOnEdit" ), joinIt->hasUpsertOnEdit() ); joinElem.setAttribute( QStringLiteral( "cascadedDelete" ), joinIt->hasCascadedDelete() ); - if ( joinIt->joinFieldNamesSubset() ) + if ( joinIt->hasSubset() ) { QDomElement subsetElem = document.createElement( QStringLiteral( "joinFieldsSubset" ) ); - Q_FOREACH ( const QString &fieldName, *joinIt->joinFieldNamesSubset() ) + const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinIt ); + + Q_FOREACH ( const QString &fieldName, subsetNames ) { QDomElement fieldElem = document.createElement( QStringLiteral( "field" ) ); fieldElem.setAttribute( QStringLiteral( "name" ), fieldName ); @@ -552,10 +553,10 @@ bool QgsVectorLayerJoinBuffer::addFeatures( QgsFeatureList &features, QgsFeature if ( existingFeature.isValid() ) { - const QStringList *subsetFields = info.joinFieldNamesSubset(); - if ( subsetFields ) + if ( info.hasSubset() ) { - Q_FOREACH ( const QString &field, *subsetFields ) + const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( info ); + Q_FOREACH ( const QString &field, subsetNames ) { QVariant newValue = joinFeature.attribute( field ); int fieldIndex = joinLayer->fields().indexOf( field ); diff --git a/src/core/qgsvectorlayerjoininfo.cpp b/src/core/qgsvectorlayerjoininfo.cpp index f2556331ef3..c5dffdef4a0 100644 --- a/src/core/qgsvectorlayerjoininfo.cpp +++ b/src/core/qgsvectorlayerjoininfo.cpp @@ -68,3 +68,50 @@ QgsFeature QgsVectorLayerJoinInfo::extractJoinedFeature( const QgsFeature &featu return joinFeature; } + +QStringList QgsVectorLayerJoinInfo::joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted ) +{ + QStringList fieldNames; + + if ( blacklisted && !info.joinFieldNamesBlackList().isEmpty() ) + { + QStringList *lst = info.joinFieldNamesSubset(); + if ( lst ) + { + Q_FOREACH ( const QString &s, *lst ) + { + if ( !info.joinFieldNamesBlackList().contains( s ) ) + fieldNames.append( s ); + } + } + else + { + Q_FOREACH ( const QgsField &f, info.joinLayer()->fields() ) + { + if ( !info.joinFieldNamesBlackList().contains( f.name() ) + && f.name() != info.joinFieldName() ) + fieldNames.append( f.name() ); + } + } + } + else + { + QStringList *lst = info.joinFieldNamesSubset(); + if ( lst ) + { + fieldNames = *lst; + } + } + + return fieldNames; +} + +bool QgsVectorLayerJoinInfo::hasSubset( bool blacklisted ) const +{ + bool subset = joinFieldNamesSubset(); + + if ( blacklisted ) + subset |= !joinFieldNamesBlackList().isEmpty(); + + return subset; +} diff --git a/src/core/qgsvectorlayerjoininfo.h b/src/core/qgsvectorlayerjoininfo.h index e2f2d03e8e1..63577dd0ff4 100644 --- a/src/core/qgsvectorlayerjoininfo.h +++ b/src/core/qgsvectorlayerjoininfo.h @@ -141,6 +141,14 @@ class CORE_EXPORT QgsVectorLayerJoinInfo */ QgsFeature extractJoinedFeature( const QgsFeature &feature ) const; + void setJoinFieldNamesBlackList( const QStringList &blackList ) { mBlackList = blackList; } + + QStringList joinFieldNamesBlackList() const { return mBlackList; } + + bool hasSubset( bool blacklisted = true ) const; + + static QStringList joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted = true ); + bool operator==( const QgsVectorLayerJoinInfo &other ) const { return mTargetFieldName == other.mTargetFieldName && @@ -197,6 +205,8 @@ class CORE_EXPORT QgsVectorLayerJoinInfo bool mCascadedDelete = false; + QStringList mBlackList; + //! Cache for joined attributes to provide fast lookup (size is 0 if no memory caching) QHash< QString, QgsAttributes> cachedAttributes; diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index e0fe6ecde31..48866ef0647 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -1996,10 +1996,11 @@ void QgsAttributeForm::updateJoinedFields( const QgsEditorWidgetWrapper &eww ) mJoinedFeatures[info] = joinFeature; - QStringList *subsetFields = info->joinFieldNamesSubset(); - if ( subsetFields ) + if ( info->hasSubset() ) { - Q_FOREACH ( const QString &field, *subsetFields ) + const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *info ); + + Q_FOREACH ( const QString &field, subsetNames ) { QString prefixedName = info->prefixedFieldName( field ); QVariant val;