Skip to content

Commit d493a69

Browse files
committed
[FEATURE] allow filtering for field values in expression widget
1 parent e655c26 commit d493a69

File tree

4 files changed

+107
-139
lines changed

4 files changed

+107
-139
lines changed

python/gui/qgsexpressionbuilderwidget.sip

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ class QgsExpressionBuilderWidget : QWidget
173173
void on_expressionTree_doubleClicked( const QModelIndex &index );
174174
void on_txtExpressionString_textChanged();
175175
void on_txtSearchEdit_textChanged();
176+
void on_txtSearchEditValues_textChanged();
176177
void on_lblPreview_linkActivated( QString link );
177-
void on_mValueListWidget_itemDoubleClicked( QListWidgetItem* item );
178+
void on_mValuesListView_doubleClicked( const QModelIndex &index );
178179
void operatorButtonClicked();
179180
void showContextMenu( const QPoint & );
180181
void loadSampleValues();

src/gui/qgsexpressionbuilderwidget.cpp

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,19 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
5858
connect( btnLoadAll, SIGNAL( pressed() ), this, SLOT( loadAllValues() ) );
5959
connect( btnLoadSample, SIGNAL( pressed() ), this, SLOT( loadSampleValues() ) );
6060

61-
Q_FOREACH ( QPushButton* button, mOperatorsGroupBox->findChildren<QPushButton *>() )
61+
Q_FOREACH( QPushButton* button, mOperatorsGroupBox->findChildren<QPushButton *>() )
6262
{
6363
connect( button, SIGNAL( pressed() ), this, SLOT( operatorButtonClicked() ) );
6464
}
6565

6666
txtSearchEdit->setPlaceholderText( tr( "Search" ) );
6767

68+
mValuesModel = new QStringListModel();
69+
mProxyValues = new QSortFilterProxyModel();
70+
mProxyValues->setSourceModel( mValuesModel );
71+
mValuesListView->setModel( mProxyValues );
72+
txtSearchEditValues->setPlaceholderText( tr( "Search" ) );
73+
6874
QSettings settings;
6975
splitter->restoreState( settings.value( "/windows/QgsExpressionBuilderWidget/splitter" ).toByteArray() );
7076
functionsplit->restoreState( settings.value( "/windows/QgsExpressionBuilderWidget/functionsplitter" ).toByteArray() );
@@ -101,6 +107,8 @@ QgsExpressionBuilderWidget::~QgsExpressionBuilderWidget()
101107

102108
delete mModel;
103109
delete mProxyModel;
110+
delete mValuesModel;
111+
delete mProxyValues;
104112
}
105113

106114
void QgsExpressionBuilderWidget::setLayer( QgsVectorLayer *layer )
@@ -115,25 +123,22 @@ void QgsExpressionBuilderWidget::setLayer( QgsVectorLayer *layer )
115123

116124
void QgsExpressionBuilderWidget::currentChanged( const QModelIndex &index, const QModelIndex & )
117125
{
126+
txtSearchEditValues->setText( QString( "" ) );
127+
118128
// Get the item
119129
QModelIndex idx = mProxyModel->mapToSource( index );
120130
QgsExpressionItem* item = dynamic_cast<QgsExpressionItem*>( mModel->itemFromIndex( idx ) );
121131
if ( !item )
122132
return;
123133

124-
mValueListWidget->clear();
125134
if ( item->getItemType() == QgsExpressionItem::Field && mFieldValues.contains( item->text() ) )
126135
{
127136
const QStringList& values = mFieldValues[item->text()];
128-
mValueListWidget->setUpdatesEnabled( false );
129-
mValueListWidget->blockSignals( true );
130-
mValueListWidget->addItems( values );
131-
mValueListWidget->setUpdatesEnabled( true );
132-
mValueListWidget->blockSignals( false );
137+
mValuesModel->setStringList( values );
133138
}
134139

135140
mLoadGroupBox->setVisible( item->getItemType() == QgsExpressionItem::Field && mLayer );
136-
mValueGroupBox->setVisible(( item->getItemType() == QgsExpressionItem::Field && mLayer ) || mValueListWidget->count() > 0 );
141+
mValueGroupBox->setVisible( ( item->getItemType() == QgsExpressionItem::Field && mLayer ) || mValuesListView->model()->rowCount() > 0 );
137142

138143
// Show the help for the current item.
139144
QString help = loadFunctionHelp( item );
@@ -188,7 +193,7 @@ void QgsExpressionBuilderWidget::updateFunctionFileList( QString path )
188193
dir.setNameFilters( QStringList() << "*.py" );
189194
QStringList files = dir.entryList( QDir::Files );
190195
cmbFileNames->clear();
191-
Q_FOREACH ( const QString& name, files )
196+
Q_FOREACH( const QString& name, files )
192197
{
193198
QFileInfo info( mFunctionsPath + QDir::separator() + name );
194199
if ( info.baseName() == "__init__" ) continue;
@@ -292,7 +297,7 @@ void QgsExpressionBuilderWidget::loadFieldNames( const QgsFields& fields )
292297
void QgsExpressionBuilderWidget::loadFieldsAndValues( const QMap<QString, QStringList> &fieldValues )
293298
{
294299
QgsFields fields;
295-
Q_FOREACH ( const QString& fieldName, fieldValues.keys() )
300+
Q_FOREACH( const QString& fieldName, fieldValues.keys() )
296301
{
297302
fields.append( QgsField( fieldName ) );
298303
}
@@ -308,20 +313,16 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString& fieldName, int
308313
return;
309314

310315
// TODO We should thread this so that we don't hold the user up if the layer is massive.
311-
mValueListWidget->clear();
312316

313317
int fieldIndex = mLayer->fieldNameIndex( fieldName );
314318

315319
if ( fieldIndex < 0 )
316320
return;
317321

318-
mValueListWidget->setUpdatesEnabled( false );
319-
mValueListWidget->blockSignals( true );
320-
321322
QList<QVariant> values;
322323
QStringList strValues;
323324
mLayer->uniqueValues( fieldIndex, values, countLimit );
324-
Q_FOREACH ( const QVariant& value, values )
325+
Q_FOREACH( const QVariant& value, values )
325326
{
326327
QString strValue;
327328
if ( value.isNull() )
@@ -330,13 +331,10 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString& fieldName, int
330331
strValue = value.toString();
331332
else
332333
strValue = "'" + value.toString().replace( "'", "''" ) + "'";
333-
mValueListWidget->addItem( strValue );
334334
strValues.append( strValue );
335335
}
336+
mValuesModel->setStringList( strValues );
336337
mFieldValues[fieldName] = strValues;
337-
338-
mValueListWidget->setUpdatesEnabled( true );
339-
mValueListWidget->blockSignals( false );
340338
}
341339

342340
void QgsExpressionBuilderWidget::registerItem( QString group,
@@ -417,7 +415,7 @@ void QgsExpressionBuilderWidget::loadRecent( QString key )
417415
QSettings settings;
418416
QString location = QString( "/expressions/recent/%1" ).arg( key );
419417
QStringList expressions = settings.value( location ).toStringList();
420-
Q_FOREACH ( const QString& expression, expressions )
418+
Q_FOREACH( const QString& expression, expressions )
421419
{
422420
this->registerItem( name, expression, expression, expression );
423421
}
@@ -598,7 +596,7 @@ QString QgsExpressionBuilderWidget::formatPreviewString( const QString& previewS
598596
void QgsExpressionBuilderWidget::loadExpressionContext()
599597
{
600598
QStringList variableNames = mExpressionContext.filteredVariableNames();
601-
Q_FOREACH ( const QString& variable, variableNames )
599+
Q_FOREACH( const QString& variable, variableNames )
602600
{
603601
registerItem( "Variables", variable, " @" + variable + " ",
604602
QgsExpression::variableHelpText( variable, true, mExpressionContext.variable( variable ) ),
@@ -608,7 +606,7 @@ void QgsExpressionBuilderWidget::loadExpressionContext()
608606

609607
// Load the functions from the expression context
610608
QStringList contextFunctions = mExpressionContext.functionNames();
611-
Q_FOREACH ( const QString& functionName, contextFunctions )
609+
Q_FOREACH( const QString& functionName, contextFunctions )
612610
{
613611
QgsExpression::Function* func = mExpressionContext.function( functionName );
614612
QString name = func->name();
@@ -629,6 +627,12 @@ void QgsExpressionBuilderWidget::on_txtSearchEdit_textChanged()
629627
expressionTree->expandAll();
630628
}
631629

630+
void QgsExpressionBuilderWidget::on_txtSearchEditValues_textChanged()
631+
{
632+
mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
633+
mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
634+
}
635+
632636
void QgsExpressionBuilderWidget::on_lblPreview_linkActivated( QString link )
633637
{
634638
Q_UNUSED( link );
@@ -638,10 +642,10 @@ void QgsExpressionBuilderWidget::on_lblPreview_linkActivated( QString link )
638642
mv->exec();
639643
}
640644

641-
void QgsExpressionBuilderWidget::on_mValueListWidget_itemDoubleClicked( QListWidgetItem *item )
645+
void QgsExpressionBuilderWidget::on_mValuesListView_doubleClicked( const QModelIndex &index )
642646
{
643647
// Insert the item text or replace selected text
644-
txtExpressionString->insertText( " " + item->text() + " " );
648+
txtExpressionString->insertText( " " + index.data( Qt::DisplayRole ).toString() + " " );
645649
txtExpressionString->setFocus();
646650
}
647651

src/gui/qgsexpressionbuilderwidget.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "QStandardItemModel"
2626
#include "QStandardItem"
2727
#include "QSortFilterProxyModel"
28+
#include "QStringListModel"
2829

2930
/** An expression item that can be used in the QgsExpressionBuilderWidget tree.
3031
*/
@@ -136,6 +137,7 @@ class QgsExpressionItemSearchProxy : public QSortFilterProxyModel
136137
}
137138
};
138139

140+
139141
/** A reusable widget that can be used to build a expression string.
140142
* See QgsExpressionBuilderDialog for exmaple of usage.
141143
*/
@@ -238,8 +240,9 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
238240
void on_expressionTree_doubleClicked( const QModelIndex &index );
239241
void on_txtExpressionString_textChanged();
240242
void on_txtSearchEdit_textChanged();
243+
void on_txtSearchEditValues_textChanged();
241244
void on_lblPreview_linkActivated( QString link );
242-
void on_mValueListWidget_itemDoubleClicked( QListWidgetItem* item );
245+
void on_mValuesListView_doubleClicked( const QModelIndex &index );
243246
void operatorButtonClicked();
244247
void showContextMenu( const QPoint & );
245248
void loadSampleValues();
@@ -274,6 +277,8 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
274277
QString mFunctionsPath;
275278
QgsVectorLayer *mLayer;
276279
QStandardItemModel *mModel;
280+
QStringListModel *mValuesModel;
281+
QSortFilterProxyModel *mProxyValues;
277282
QgsExpressionItemSearchProxy *mProxyModel;
278283
QMap<QString, QgsExpressionItem*> mExpressionGroups;
279284
QgsFeature mFeature;

0 commit comments

Comments
 (0)