Skip to content
Permalink
Browse files

Fix #10912 (joined attributes are not correctly propagated in nested …

…joins)

This commit makes QgsVectorLayerJoinBuffer listen to changes in fields
of joined vector layers in order to update the cache and inform parent layer
  • Loading branch information
wonder-sk committed Sep 9, 2014
1 parent 1df01c0 commit 071a5ec0c528f886bc7875c43c9e2260191a432c
@@ -193,6 +193,11 @@ class QgsFields
//! Utility function to return a list of QgsField instances
QList<QgsField> toList() const;

//! @note added in 2.6
bool operator==( const QgsFields& other ) const;
//! @note added in 2.6
bool operator!=( const QgsFields& other ) const;

/* SIP_PYOBJECT __getitem__(int key);
%MethodCode
if (a0 = sipConvertFromSequenceIndex(a0, sipCpp->count()) < 0)
@@ -1,4 +1,4 @@
class QgsVectorLayerJoinBuffer
class QgsVectorLayerJoinBuffer : QObject
{
%TypeHeaderCode
#include <qgsvectorlayerjoinbuffer.h>
@@ -39,4 +39,12 @@ class QgsVectorLayerJoinBuffer
@param sourceFieldIndex Output: field's index in source layer */
const QgsVectorJoinInfo* joinForFieldIndex( int index, const QgsFields& fields, int& sourceFieldIndex /Out/ ) const;

//! Create a copy of the join buffer
//! @note added in 2.6
QgsVectorLayerJoinBuffer* clone() const /Factory/;

signals:
//! Emitted whenever the list of joined fields changes (e.g. added join or joined layer's fields change)
//! @note added in 2.6
void joinedFieldsChanged();
};
@@ -369,6 +369,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsnetworkaccessmanager.h
qgsvectordataprovider.h
qgsvectorlayercache.h
qgsvectorlayerjoinbuffer.h
qgsgeometryvalidator.h

composer/qgsaddremoveitemcommand.h
@@ -178,6 +178,11 @@ class CORE_EXPORT QgsFields
Field(): origin( OriginUnknown ), originIndex( -1 ) {}
Field( const QgsField& f, FieldOrigin o, int oi ): field( f ), origin( o ), originIndex( oi ) {}

//! @note added in 2.6
bool operator==( const Field& other ) const { return field == other.field && origin == other.origin && originIndex == other.originIndex; }
//! @note added in 2.6
bool operator!=( const Field& other ) const { return !( *this == other ); }

QgsField field; //!< field
FieldOrigin origin; //!< origin of the field
int originIndex; //!< index specific to the origin
@@ -238,6 +243,11 @@ class CORE_EXPORT QgsFields
//! Utility function to return a list of QgsField instances
QList<QgsField> toList() const;

//! @note added in 2.6
bool operator==( const QgsFields& other ) const { return mFields == other.mFields; }
//! @note added in 2.6
bool operator!=( const QgsFields& other ) const { return ! ( *this == other ); }

protected:
//! internal storage of the container
QVector<Field> mFields;
@@ -1304,6 +1304,7 @@ bool QgsVectorLayer::readXml( const QDomNode& layer_node )
if ( !mJoinBuffer )
{
mJoinBuffer = new QgsVectorLayerJoinBuffer();
connect( mJoinBuffer, SIGNAL( joinedFieldsChanged() ), this, SLOT( onJoinedFieldsChanged() ) );
}
mJoinBuffer->readXml( layer_node );

@@ -1366,6 +1367,7 @@ bool QgsVectorLayer::setDataProvider( QString const & provider )
mWkbType = mDataProvider->geometryType();

mJoinBuffer = new QgsVectorLayerJoinBuffer();
connect( mJoinBuffer, SIGNAL( joinedFieldsChanged() ), this, SLOT( onJoinedFieldsChanged() ) );
mExpressionFieldBuffer = new QgsExpressionFieldBuffer();
updateFields();

@@ -2782,6 +2784,8 @@ void QgsVectorLayer::updateFields()
if ( !mDataProvider )
return;

QgsFields oldFields = mUpdatedFields;

mUpdatedFields = mDataProvider->fields();

// added / removed fields
@@ -2795,7 +2799,8 @@ void QgsVectorLayer::updateFields()
if ( mExpressionFieldBuffer )
mExpressionFieldBuffer->updateFields( mUpdatedFields );

emit updatedFields();
if ( oldFields != mUpdatedFields )
emit updatedFields();
}


@@ -3563,6 +3568,12 @@ void QgsVectorLayer::onRelationsLoaded()
}
}

void QgsVectorLayer::onJoinedFieldsChanged()
{
// some of the fields of joined layers have changed -> we need to update this layer's fields too
updateFields();
}

QgsVectorLayer::ValueRelationData QgsVectorLayer::valueRelation( int idx )
{
if ( editorWidgetV2( idx ) == "ValueRelation" )
@@ -1641,6 +1641,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer

private slots:
void onRelationsLoaded();
void onJoinedFieldsChanged();

protected:
/** Set the extent */
@@ -27,7 +27,7 @@ QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( QgsVectorLayer *layer
{
mProviderFeatureSource = layer->dataProvider()->featureSource();
mFields = layer->pendingFields();
mJoinBuffer = new QgsVectorLayerJoinBuffer( *layer->mJoinBuffer );
mJoinBuffer = layer->mJoinBuffer->clone();
mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );

mCanBeSimplified = layer->hasGeometryType() && layer->geometryType() != QGis::Point;
@@ -39,8 +39,18 @@ void QgsVectorLayerJoinBuffer::addJoin( const QgsVectorJoinInfo& joinInfo )
{
cacheJoinLayer( mVectorJoins.last() );
}

// Wait for notifications about changed fields in joined layer to propagate them.
// During project load the joined layers possibly do not exist yet so the connection will not be created,
// but then QgsProject makes sure to call createJoinCaches() which will do the connection.
// Unique connection makes sure we do not respond to one layer's update more times (in case of multiple join)
if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo.joinLayerId ) ) )
connect( vl, SIGNAL( updatedFields() ), this, SLOT( joinedLayerUpdatedFields() ), Qt::UniqueConnection );

emit joinedFieldsChanged();
}


void QgsVectorLayerJoinBuffer::removeJoin( const QString& joinLayerId )
{
for ( int i = 0; i < mVectorJoins.size(); ++i )
@@ -50,6 +60,11 @@ void QgsVectorLayerJoinBuffer::removeJoin( const QString& joinLayerId )
mVectorJoins.removeAt( i );
}
}

if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinLayerId ) ) )
disconnect( vl, SIGNAL( updatedFields() ), this, SLOT( joinedLayerUpdatedFields() ) );

emit joinedFieldsChanged();
}

void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorJoinInfo& joinInfo )
@@ -121,6 +136,10 @@ void QgsVectorLayerJoinBuffer::createJoinCaches()
for ( ; joinIt != mVectorJoins.end(); ++joinIt )
{
cacheJoinLayer( *joinIt );

// make sure we are connected to the joined layer
if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinIt->joinLayerId ) ) )
connect( vl, SIGNAL( updatedFields() ), this, SLOT( joinedLayerUpdatedFields() ), Qt::UniqueConnection );
}
}

@@ -188,3 +207,28 @@ const QgsVectorJoinInfo* QgsVectorLayerJoinBuffer::joinForFieldIndex( int index,

return &( mVectorJoins[sourceJoinIndex] );
}

QgsVectorLayerJoinBuffer* QgsVectorLayerJoinBuffer::clone() const
{
QgsVectorLayerJoinBuffer* cloned = new QgsVectorLayerJoinBuffer;
cloned->mVectorJoins = mVectorJoins;
return cloned;
}

void QgsVectorLayerJoinBuffer::joinedLayerUpdatedFields()
{
QgsVectorLayer* joinedLayer = qobject_cast<QgsVectorLayer*>( sender() );
Q_ASSERT( joinedLayer );

// recache the joined layer
for ( QgsVectorJoinList::iterator it = mVectorJoins.begin(); it != mVectorJoins.end(); ++it )
{
if ( joinedLayer->id() == it->joinLayerId )
{
it->cachedAttributes.clear();
cacheJoinLayer( *it );
}
}

emit joinedFieldsChanged();
}
@@ -25,11 +25,13 @@
#include <QString>


typedef QList< QgsVectorJoinInfo > QgsVectorJoinList;


/**Manages joined fields for a vector layer*/
class CORE_EXPORT QgsVectorLayerJoinBuffer
class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject
{
Q_OBJECT
public:
QgsVectorLayerJoinBuffer();
~QgsVectorLayerJoinBuffer();
@@ -58,18 +60,30 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer
/**Quick way to test if there is any join at all*/
bool containsJoins() const { return !mVectorJoins.isEmpty(); }

const QList< QgsVectorJoinInfo >& vectorJoins() const { return mVectorJoins; }
const QgsVectorJoinList& vectorJoins() const { return mVectorJoins; }

/**Finds the vector join for a layer field index.
@param index this layers attribute index
@param fields fields of the vector layer (including joined fields)
@param sourceFieldIndex Output: field's index in source layer */
const QgsVectorJoinInfo* joinForFieldIndex( int index, const QgsFields& fields, int& sourceFieldIndex ) const;

//! Create a copy of the join buffer
//! @note added in 2.6
QgsVectorLayerJoinBuffer* clone() const;

signals:
//! Emitted whenever the list of joined fields changes (e.g. added join or joined layer's fields change)
//! @note added in 2.6
void joinedFieldsChanged();

private slots:
void joinedLayerUpdatedFields();

private:

/**Joined vector layers*/
QList< QgsVectorJoinInfo > mVectorJoins;
QgsVectorJoinList mVectorJoins;

/**Caches attributes of join layer in memory if QgsVectorJoinInfo.memoryCache is true (and the cache is not already there)*/
void cacheJoinLayer( QgsVectorJoinInfo& joinInfo );
@@ -133,3 +133,4 @@ ADD_QGIS_TEST(colorschemeregistry testqgscolorschemeregistry.cpp)
ADD_QGIS_TEST(colorscheme testqgscolorscheme.cpp)
ADD_QGIS_TEST(networkcontentfetcher testqgsnetworkcontentfetcher.cpp )
ADD_QGIS_TEST(legendrenderertest testqgslegendrenderer.cpp )
ADD_QGIS_TEST(vectorlayerjoinbuffer testqgsvectorlayerjoinbuffer.cpp )

0 comments on commit 071a5ec

Please sign in to comment.
You can’t perform that action at this time.