Skip to content

Commit 899a3cd

Browse files
author
Hugo Mercier
authored
Merge pull request #4933 from pblottiere/bugfix_chainfilter_218
Fixes relation reference widget when chain filter option is activated, fixes #16903 (backport)
2 parents a6c461b + b5bdafe commit 899a3cd

File tree

4 files changed

+285
-33
lines changed

4 files changed

+285
-33
lines changed

src/gui/editorwidgets/qgsrelationreferencewidget.cpp

+97-33
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,10 @@ void QgsRelationReferenceWidget::setRelation( const QgsRelation& relation, bool
191191
mReferencedFieldIdx = mReferencedLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).second );
192192
mReferencingFieldIdx = mReferencingLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).first );
193193

194-
QgsAttributeEditorContext context( mEditorContext, relation, QgsAttributeEditorContext::Single, QgsAttributeEditorContext::Embed );
195194

196195
if ( mEmbedForm )
197196
{
197+
QgsAttributeEditorContext context( mEditorContext, relation, QgsAttributeEditorContext::Single, QgsAttributeEditorContext::Embed );
198198
mAttributeEditorFrame->setTitle( mReferencedLayer->name() );
199199
mReferencedAttributeForm = new QgsAttributeForm( relation.referencedLayer(), QgsFeature(), context, this );
200200
mAttributeEditorLayout->addWidget( mReferencedAttributeForm );
@@ -464,6 +464,10 @@ void QgsRelationReferenceWidget::init()
464464
{
465465
QVariantList uniqueValues;
466466
int idx = mReferencedLayer->fieldNameIndex( fieldName );
467+
468+
if ( idx == -1 )
469+
continue;
470+
467471
QComboBox* cb = new QComboBox();
468472
cb->setProperty( "Field", fieldName );
469473
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
@@ -785,13 +789,41 @@ void QgsRelationReferenceWidget::filterChanged()
785789
{
786790
QVariant nullValue = QSettings().value( "qgis/nullValue", "NULL" );
787791

788-
QStringList filters;
792+
QMap<QString, QString> filters;
789793
QgsAttributeList attrs;
790794

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

793797
Q_ASSERT( scb );
794798

799+
QgsFeature f;
800+
QgsFeatureIds featureIds;
801+
QString filterExpression;
802+
803+
// comboboxes have to be disabled before building filters
804+
if ( mChainFilters )
805+
disableChainedComboBoxes( scb );
806+
807+
// build filters
808+
Q_FOREACH ( QComboBox *cb, mFilterComboBoxes )
809+
{
810+
if ( cb->currentIndex() != 0 )
811+
{
812+
const QString fieldName = cb->property( "Field" ).toString();
813+
814+
if ( cb->currentText() == nullValue.toString() )
815+
{
816+
filters[fieldName] = QString( "\"%1\" IS NULL" ).arg( fieldName );
817+
}
818+
else
819+
{
820+
filters[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
821+
}
822+
attrs << mReferencedLayer->fieldNameIndex( fieldName );
823+
}
824+
}
825+
826+
bool filtered = false;
795827
if ( mChainFilters )
796828
{
797829
QComboBox* ccb = nullptr;
@@ -805,13 +837,11 @@ void QgsRelationReferenceWidget::filterChanged()
805837
continue;
806838
}
807839

808-
if ( ccb->currentIndex() == 0 )
809-
{
810-
cb->setCurrentIndex( 0 );
811-
cb->setEnabled( false );
812-
}
813-
else
840+
if ( ccb->currentIndex() != 0 )
814841
{
842+
const QString fieldName = cb->property( "Field" ).toString();
843+
filtered = true;
844+
815845
cb->blockSignals( true );
816846
cb->clear();
817847
cb->addItem( cb->property( "FieldAlias" ).toString() );
@@ -821,8 +851,30 @@ void QgsRelationReferenceWidget::filterChanged()
821851
QStringList texts;
822852
Q_FOREACH ( const QString& txt, mFilterCache[ccb->property( "Field" ).toString()][ccb->currentText()] )
823853
{
824-
texts << txt;
854+
QMap<QString, QString> filtersAttrs = filters;
855+
filtersAttrs[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, txt );
856+
QStringList vals = filtersAttrs.values();
857+
QString expression = vals.join( QString( " AND " ) );
858+
859+
QgsAttributeList subset = attrs;
860+
subset << mReferencedLayer->fieldNameIndex( fieldName );
861+
862+
QgsFeatureIterator it( mMasterModel->layerCache()->getFeatures( QgsFeatureRequest().setFilterExpression( expression ).setSubsetOfAttributes( subset ) ) );
863+
864+
bool found = false;
865+
while ( it.nextFeature( f ) )
866+
{
867+
if ( !featureIds.contains( f.id() ) )
868+
featureIds << f.id();
869+
870+
found = true;
871+
}
872+
873+
// item is only provided if at least 1 feature exists
874+
if ( found )
875+
texts << txt;
825876
}
877+
826878
texts.sort();
827879
cb->addItems( texts );
828880

@@ -834,34 +886,21 @@ void QgsRelationReferenceWidget::filterChanged()
834886
}
835887
}
836888

837-
Q_FOREACH ( QComboBox* cb, mFilterComboBoxes )
889+
if ( !mChainFilters || ( mChainFilters && !filtered ) )
838890
{
839-
if ( cb->currentIndex() != 0 )
840-
{
841-
const QString fieldName = cb->property( "Field" ).toString();
891+
QStringList vals = filters.values();
892+
filterExpression = vals.join( QString( " AND " ) );
842893

843-
if ( cb->currentText() == nullValue.toString() )
844-
{
845-
filters << QString( "\"%1\" IS NULL" ).arg( fieldName );
846-
}
847-
else
848-
{
849-
filters << QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
850-
}
851-
attrs << mReferencedLayer->fieldNameIndex( fieldName );
852-
}
853-
}
854-
855-
QString filterExpression = filters.join( " AND " );
894+
QgsFeatureRequest req = QgsFeatureRequest().setSubsetOfAttributes( attrs );
895+
if ( !filterExpression.isEmpty() )
896+
req.setFilterExpression( filterExpression );
856897

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

859-
QgsFeature f;
860-
QgsFeatureIds featureIds;
861-
862-
while ( it.nextFeature( f ) )
863-
{
864-
featureIds << f.id();
900+
while ( it.nextFeature( f ) )
901+
{
902+
featureIds << f.id();
903+
}
865904
}
866905

867906
mFilterModel->setFilteredFeatures( featureIds );
@@ -896,3 +935,28 @@ void QgsRelationReferenceWidget::updateAddEntryButton()
896935
mAddEntryButton->setVisible( mAllowAddFeatures );
897936
mAddEntryButton->setEnabled( mReferencedLayer && mReferencedLayer->isEditable() );
898937
}
938+
939+
void QgsRelationReferenceWidget::disableChainedComboBoxes( const QComboBox *scb )
940+
{
941+
QComboBox *ccb = nullptr;
942+
Q_FOREACH ( QComboBox *cb, mFilterComboBoxes )
943+
{
944+
if ( !ccb )
945+
{
946+
if ( cb == scb )
947+
{
948+
ccb = cb;
949+
}
950+
951+
continue;
952+
}
953+
954+
if ( ccb->currentIndex() == 0 )
955+
{
956+
cb->setCurrentIndex( 0 );
957+
cb->setEnabled( false );
958+
}
959+
else
960+
ccb = cb;
961+
}
962+
}

src/gui/editorwidgets/qgsrelationreferencewidget.h

+3
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
162162
private:
163163
void highlightFeature( QgsFeature f = QgsFeature(), CanvasExtent canvasExtent = Fixed );
164164
void updateAttributeEditorFrame( const QgsFeature& feature );
165+
void disableChainedComboBoxes( const QComboBox *scb );
165166

166167
// initialized
167168
QgsAttributeEditorContext mEditorContext;
@@ -218,6 +219,8 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
218219
QVBoxLayout* mAttributeEditorLayout;
219220
QLineEdit* mLineEdit;
220221
QLabel* mInvalidLabel;
222+
223+
friend class TestQgsRelationReferenceWidget;
221224
};
222225

223226
#endif // QGSRELATIONREFERENCEWIDGET_H

tests/src/gui/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
1414
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/editorwidgets/core
1515
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/symbology-ng
1616
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/raster
17+
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/attributetable
1718
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core
1819
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/auth
1920
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/composer
@@ -145,3 +146,4 @@ ADD_QGIS_TEST(sqlcomposerdialog testqgssqlcomposerdialog.cpp)
145146
ADD_QGIS_TEST(filedownloader testqgsfiledownloader.cpp)
146147
ADD_QGIS_TEST(composergui testqgscomposergui.cpp)
147148
ADD_QGIS_TEST(valuerelationwidgetwrapper testqgsvaluerelationwidgetwrapper.cpp)
149+
ADD_QGIS_TEST(relationreferencewidget testqgsrelationreferencewidget.cpp)

0 commit comments

Comments
 (0)