Skip to content

Commit

Permalink
Merge pull request #4933 from pblottiere/bugfix_chainfilter_218
Browse files Browse the repository at this point in the history
Fixes relation reference widget when chain filter option is activated, fixes #16903 (backport)
  • Loading branch information
Hugo Mercier committed Aug 18, 2017
2 parents a6c461b + b5bdafe commit 899a3cd
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 33 deletions.
130 changes: 97 additions & 33 deletions src/gui/editorwidgets/qgsrelationreferencewidget.cpp
Expand Up @@ -191,10 +191,10 @@ void QgsRelationReferenceWidget::setRelation( const QgsRelation& relation, bool
mReferencedFieldIdx = mReferencedLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).second );
mReferencingFieldIdx = mReferencingLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).first );

QgsAttributeEditorContext context( mEditorContext, relation, QgsAttributeEditorContext::Single, QgsAttributeEditorContext::Embed );

if ( mEmbedForm )
{
QgsAttributeEditorContext context( mEditorContext, relation, QgsAttributeEditorContext::Single, QgsAttributeEditorContext::Embed );
mAttributeEditorFrame->setTitle( mReferencedLayer->name() );
mReferencedAttributeForm = new QgsAttributeForm( relation.referencedLayer(), QgsFeature(), context, this );
mAttributeEditorLayout->addWidget( mReferencedAttributeForm );
Expand Down Expand Up @@ -464,6 +464,10 @@ void QgsRelationReferenceWidget::init()
{
QVariantList uniqueValues;
int idx = mReferencedLayer->fieldNameIndex( fieldName );

if ( idx == -1 )
continue;

QComboBox* cb = new QComboBox();
cb->setProperty( "Field", fieldName );
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
Expand Down Expand Up @@ -785,13 +789,41 @@ void QgsRelationReferenceWidget::filterChanged()
{
QVariant nullValue = QSettings().value( "qgis/nullValue", "NULL" );

QStringList filters;
QMap<QString, QString> filters;
QgsAttributeList attrs;

QComboBox* scb = qobject_cast<QComboBox*>( sender() );

Q_ASSERT( scb );

QgsFeature f;
QgsFeatureIds featureIds;
QString filterExpression;

// comboboxes have to be disabled before building filters
if ( mChainFilters )
disableChainedComboBoxes( scb );

// build filters
Q_FOREACH ( QComboBox *cb, mFilterComboBoxes )
{
if ( cb->currentIndex() != 0 )
{
const QString fieldName = cb->property( "Field" ).toString();

if ( cb->currentText() == nullValue.toString() )
{
filters[fieldName] = QString( "\"%1\" IS NULL" ).arg( fieldName );
}
else
{
filters[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
}
attrs << mReferencedLayer->fieldNameIndex( fieldName );
}
}

bool filtered = false;
if ( mChainFilters )
{
QComboBox* ccb = nullptr;
Expand All @@ -805,13 +837,11 @@ void QgsRelationReferenceWidget::filterChanged()
continue;
}

if ( ccb->currentIndex() == 0 )
{
cb->setCurrentIndex( 0 );
cb->setEnabled( false );
}
else
if ( ccb->currentIndex() != 0 )
{
const QString fieldName = cb->property( "Field" ).toString();
filtered = true;

cb->blockSignals( true );
cb->clear();
cb->addItem( cb->property( "FieldAlias" ).toString() );
Expand All @@ -821,8 +851,30 @@ void QgsRelationReferenceWidget::filterChanged()
QStringList texts;
Q_FOREACH ( const QString& txt, mFilterCache[ccb->property( "Field" ).toString()][ccb->currentText()] )
{
texts << txt;
QMap<QString, QString> filtersAttrs = filters;
filtersAttrs[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, txt );
QStringList vals = filtersAttrs.values();
QString expression = vals.join( QString( " AND " ) );

QgsAttributeList subset = attrs;
subset << mReferencedLayer->fieldNameIndex( fieldName );

QgsFeatureIterator it( mMasterModel->layerCache()->getFeatures( QgsFeatureRequest().setFilterExpression( expression ).setSubsetOfAttributes( subset ) ) );

bool found = false;
while ( it.nextFeature( f ) )
{
if ( !featureIds.contains( f.id() ) )
featureIds << f.id();

found = true;
}

// item is only provided if at least 1 feature exists
if ( found )
texts << txt;
}

texts.sort();
cb->addItems( texts );

Expand All @@ -834,34 +886,21 @@ void QgsRelationReferenceWidget::filterChanged()
}
}

Q_FOREACH ( QComboBox* cb, mFilterComboBoxes )
if ( !mChainFilters || ( mChainFilters && !filtered ) )
{
if ( cb->currentIndex() != 0 )
{
const QString fieldName = cb->property( "Field" ).toString();
QStringList vals = filters.values();
filterExpression = vals.join( QString( " AND " ) );

if ( cb->currentText() == nullValue.toString() )
{
filters << QString( "\"%1\" IS NULL" ).arg( fieldName );
}
else
{
filters << QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
}
attrs << mReferencedLayer->fieldNameIndex( fieldName );
}
}

QString filterExpression = filters.join( " AND " );
QgsFeatureRequest req = QgsFeatureRequest().setSubsetOfAttributes( attrs );
if ( !filterExpression.isEmpty() )
req.setFilterExpression( filterExpression );

QgsFeatureIterator it( mMasterModel->layerCache()->getFeatures( QgsFeatureRequest().setFilterExpression( filterExpression ).setSubsetOfAttributes( attrs ) ) );
QgsFeatureIterator it( mMasterModel->layerCache()->getFeatures( req ) );

QgsFeature f;
QgsFeatureIds featureIds;

while ( it.nextFeature( f ) )
{
featureIds << f.id();
while ( it.nextFeature( f ) )
{
featureIds << f.id();
}
}

mFilterModel->setFilteredFeatures( featureIds );
Expand Down Expand Up @@ -896,3 +935,28 @@ void QgsRelationReferenceWidget::updateAddEntryButton()
mAddEntryButton->setVisible( mAllowAddFeatures );
mAddEntryButton->setEnabled( mReferencedLayer && mReferencedLayer->isEditable() );
}

void QgsRelationReferenceWidget::disableChainedComboBoxes( const QComboBox *scb )
{
QComboBox *ccb = nullptr;
Q_FOREACH ( QComboBox *cb, mFilterComboBoxes )
{
if ( !ccb )
{
if ( cb == scb )
{
ccb = cb;
}

continue;
}

if ( ccb->currentIndex() == 0 )
{
cb->setCurrentIndex( 0 );
cb->setEnabled( false );
}
else
ccb = cb;
}
}
3 changes: 3 additions & 0 deletions src/gui/editorwidgets/qgsrelationreferencewidget.h
Expand Up @@ -162,6 +162,7 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
private:
void highlightFeature( QgsFeature f = QgsFeature(), CanvasExtent canvasExtent = Fixed );
void updateAttributeEditorFrame( const QgsFeature& feature );
void disableChainedComboBoxes( const QComboBox *scb );

// initialized
QgsAttributeEditorContext mEditorContext;
Expand Down Expand Up @@ -218,6 +219,8 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
QVBoxLayout* mAttributeEditorLayout;
QLineEdit* mLineEdit;
QLabel* mInvalidLabel;

friend class TestQgsRelationReferenceWidget;
};

#endif // QGSRELATIONREFERENCEWIDGET_H
2 changes: 2 additions & 0 deletions tests/src/gui/CMakeLists.txt
Expand Up @@ -14,6 +14,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/editorwidgets/core
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/symbology-ng
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/raster
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/attributetable
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/auth
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/composer
Expand Down Expand Up @@ -145,3 +146,4 @@ ADD_QGIS_TEST(sqlcomposerdialog testqgssqlcomposerdialog.cpp)
ADD_QGIS_TEST(filedownloader testqgsfiledownloader.cpp)
ADD_QGIS_TEST(composergui testqgscomposergui.cpp)
ADD_QGIS_TEST(valuerelationwidgetwrapper testqgsvaluerelationwidgetwrapper.cpp)
ADD_QGIS_TEST(relationreferencewidget testqgsrelationreferencewidget.cpp)

0 comments on commit 899a3cd

Please sign in to comment.