Skip to content

Commit

Permalink
[FEATURE] allow filtering for field values in expression widget
Browse files Browse the repository at this point in the history
  • Loading branch information
slarosa committed Sep 25, 2015
1 parent e655c26 commit d493a69
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 139 deletions.
3 changes: 2 additions & 1 deletion python/gui/qgsexpressionbuilderwidget.sip
Expand Up @@ -173,8 +173,9 @@ class QgsExpressionBuilderWidget : QWidget
void on_expressionTree_doubleClicked( const QModelIndex &index );
void on_txtExpressionString_textChanged();
void on_txtSearchEdit_textChanged();
void on_txtSearchEditValues_textChanged();
void on_lblPreview_linkActivated( QString link );
void on_mValueListWidget_itemDoubleClicked( QListWidgetItem* item );
void on_mValuesListView_doubleClicked( const QModelIndex &index );
void operatorButtonClicked();
void showContextMenu( const QPoint & );
void loadSampleValues();
Expand Down
52 changes: 28 additions & 24 deletions src/gui/qgsexpressionbuilderwidget.cpp
Expand Up @@ -58,13 +58,19 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
connect( btnLoadAll, SIGNAL( pressed() ), this, SLOT( loadAllValues() ) );
connect( btnLoadSample, SIGNAL( pressed() ), this, SLOT( loadSampleValues() ) );

Q_FOREACH ( QPushButton* button, mOperatorsGroupBox->findChildren<QPushButton *>() )
Q_FOREACH( QPushButton* button, mOperatorsGroupBox->findChildren<QPushButton *>() )
{
connect( button, SIGNAL( pressed() ), this, SLOT( operatorButtonClicked() ) );
}

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

mValuesModel = new QStringListModel();
mProxyValues = new QSortFilterProxyModel();
mProxyValues->setSourceModel( mValuesModel );
mValuesListView->setModel( mProxyValues );
txtSearchEditValues->setPlaceholderText( tr( "Search" ) );

QSettings settings;
splitter->restoreState( settings.value( "/windows/QgsExpressionBuilderWidget/splitter" ).toByteArray() );
functionsplit->restoreState( settings.value( "/windows/QgsExpressionBuilderWidget/functionsplitter" ).toByteArray() );
Expand Down Expand Up @@ -101,6 +107,8 @@ QgsExpressionBuilderWidget::~QgsExpressionBuilderWidget()

delete mModel;
delete mProxyModel;
delete mValuesModel;
delete mProxyValues;
}

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

void QgsExpressionBuilderWidget::currentChanged( const QModelIndex &index, const QModelIndex & )
{
txtSearchEditValues->setText( QString( "" ) );

// Get the item
QModelIndex idx = mProxyModel->mapToSource( index );
QgsExpressionItem* item = dynamic_cast<QgsExpressionItem*>( mModel->itemFromIndex( idx ) );
if ( !item )
return;

mValueListWidget->clear();
if ( item->getItemType() == QgsExpressionItem::Field && mFieldValues.contains( item->text() ) )
{
const QStringList& values = mFieldValues[item->text()];
mValueListWidget->setUpdatesEnabled( false );
mValueListWidget->blockSignals( true );
mValueListWidget->addItems( values );
mValueListWidget->setUpdatesEnabled( true );
mValueListWidget->blockSignals( false );
mValuesModel->setStringList( values );
}

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

// Show the help for the current item.
QString help = loadFunctionHelp( item );
Expand Down Expand Up @@ -188,7 +193,7 @@ void QgsExpressionBuilderWidget::updateFunctionFileList( QString path )
dir.setNameFilters( QStringList() << "*.py" );
QStringList files = dir.entryList( QDir::Files );
cmbFileNames->clear();
Q_FOREACH ( const QString& name, files )
Q_FOREACH( const QString& name, files )
{
QFileInfo info( mFunctionsPath + QDir::separator() + name );
if ( info.baseName() == "__init__" ) continue;
Expand Down Expand Up @@ -292,7 +297,7 @@ void QgsExpressionBuilderWidget::loadFieldNames( const QgsFields& fields )
void QgsExpressionBuilderWidget::loadFieldsAndValues( const QMap<QString, QStringList> &fieldValues )
{
QgsFields fields;
Q_FOREACH ( const QString& fieldName, fieldValues.keys() )
Q_FOREACH( const QString& fieldName, fieldValues.keys() )
{
fields.append( QgsField( fieldName ) );
}
Expand All @@ -308,20 +313,16 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString& fieldName, int
return;

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

int fieldIndex = mLayer->fieldNameIndex( fieldName );

if ( fieldIndex < 0 )
return;

mValueListWidget->setUpdatesEnabled( false );
mValueListWidget->blockSignals( true );

QList<QVariant> values;
QStringList strValues;
mLayer->uniqueValues( fieldIndex, values, countLimit );
Q_FOREACH ( const QVariant& value, values )
Q_FOREACH( const QVariant& value, values )
{
QString strValue;
if ( value.isNull() )
Expand All @@ -330,13 +331,10 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString& fieldName, int
strValue = value.toString();
else
strValue = "'" + value.toString().replace( "'", "''" ) + "'";
mValueListWidget->addItem( strValue );
strValues.append( strValue );
}
mValuesModel->setStringList( strValues );
mFieldValues[fieldName] = strValues;

mValueListWidget->setUpdatesEnabled( true );
mValueListWidget->blockSignals( false );
}

void QgsExpressionBuilderWidget::registerItem( QString group,
Expand Down Expand Up @@ -417,7 +415,7 @@ void QgsExpressionBuilderWidget::loadRecent( QString key )
QSettings settings;
QString location = QString( "/expressions/recent/%1" ).arg( key );
QStringList expressions = settings.value( location ).toStringList();
Q_FOREACH ( const QString& expression, expressions )
Q_FOREACH( const QString& expression, expressions )
{
this->registerItem( name, expression, expression, expression );
}
Expand Down Expand Up @@ -598,7 +596,7 @@ QString QgsExpressionBuilderWidget::formatPreviewString( const QString& previewS
void QgsExpressionBuilderWidget::loadExpressionContext()
{
QStringList variableNames = mExpressionContext.filteredVariableNames();
Q_FOREACH ( const QString& variable, variableNames )
Q_FOREACH( const QString& variable, variableNames )
{
registerItem( "Variables", variable, " @" + variable + " ",
QgsExpression::variableHelpText( variable, true, mExpressionContext.variable( variable ) ),
Expand All @@ -608,7 +606,7 @@ void QgsExpressionBuilderWidget::loadExpressionContext()

// Load the functions from the expression context
QStringList contextFunctions = mExpressionContext.functionNames();
Q_FOREACH ( const QString& functionName, contextFunctions )
Q_FOREACH( const QString& functionName, contextFunctions )
{
QgsExpression::Function* func = mExpressionContext.function( functionName );
QString name = func->name();
Expand All @@ -629,6 +627,12 @@ void QgsExpressionBuilderWidget::on_txtSearchEdit_textChanged()
expressionTree->expandAll();
}

void QgsExpressionBuilderWidget::on_txtSearchEditValues_textChanged()
{
mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
}

void QgsExpressionBuilderWidget::on_lblPreview_linkActivated( QString link )
{
Q_UNUSED( link );
Expand All @@ -638,10 +642,10 @@ void QgsExpressionBuilderWidget::on_lblPreview_linkActivated( QString link )
mv->exec();
}

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

Expand Down
7 changes: 6 additions & 1 deletion src/gui/qgsexpressionbuilderwidget.h
Expand Up @@ -25,6 +25,7 @@
#include "QStandardItemModel"
#include "QStandardItem"
#include "QSortFilterProxyModel"
#include "QStringListModel"

/** An expression item that can be used in the QgsExpressionBuilderWidget tree.
*/
Expand Down Expand Up @@ -136,6 +137,7 @@ class QgsExpressionItemSearchProxy : public QSortFilterProxyModel
}
};


/** A reusable widget that can be used to build a expression string.
* See QgsExpressionBuilderDialog for exmaple of usage.
*/
Expand Down Expand Up @@ -238,8 +240,9 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
void on_expressionTree_doubleClicked( const QModelIndex &index );
void on_txtExpressionString_textChanged();
void on_txtSearchEdit_textChanged();
void on_txtSearchEditValues_textChanged();
void on_lblPreview_linkActivated( QString link );
void on_mValueListWidget_itemDoubleClicked( QListWidgetItem* item );
void on_mValuesListView_doubleClicked( const QModelIndex &index );
void operatorButtonClicked();
void showContextMenu( const QPoint & );
void loadSampleValues();
Expand Down Expand Up @@ -274,6 +277,8 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
QString mFunctionsPath;
QgsVectorLayer *mLayer;
QStandardItemModel *mModel;
QStringListModel *mValuesModel;
QSortFilterProxyModel *mProxyValues;
QgsExpressionItemSearchProxy *mProxyModel;
QMap<QString, QgsExpressionItem*> mExpressionGroups;
QgsFeature mFeature;
Expand Down

0 comments on commit d493a69

Please sign in to comment.