[FEATURE] allow filtering for field values in expression widget

This commit is contained in:
Salvatore Larosa 2015-09-24 23:53:43 +02:00
parent e655c2617a
commit d493a69069
4 changed files with 107 additions and 139 deletions

View File

@ -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();

View File

@ -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() );
@ -101,6 +107,8 @@ QgsExpressionBuilderWidget::~QgsExpressionBuilderWidget()
delete mModel;
delete mProxyModel;
delete mValuesModel;
delete mProxyValues;
}
void QgsExpressionBuilderWidget::setLayer( QgsVectorLayer *layer )
@ -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 );
@ -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;
@ -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 ) );
}
@ -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() )
@ -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,
@ -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 );
}
@ -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 ) ),
@ -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();
@ -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 );
@ -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();
}

View File

@ -25,6 +25,7 @@
#include "QStandardItemModel"
#include "QStandardItem"
#include "QSortFilterProxyModel"
#include "QStringListModel"
/** An expression item that can be used in the QgsExpressionBuilderWidget tree.
*/
@ -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.
*/
@ -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();
@ -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;

View File

@ -321,15 +321,12 @@
</layout>
</widget>
<widget class="QFrame" name="moperationListGroup">
<layout class="QGridLayout" name="gridLayout_5">
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QSplitter" name="functionsplit">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="opaqueResize">
<bool>false</bool>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
@ -366,8 +363,8 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<widget class="QWidget" name="">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTextEdit" name="txtHelpText">
<property name="readOnly">
@ -376,116 +373,77 @@
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QFrame" name="mValueGroupBox">
<layout class="QGridLayout" name="gridLayout_7">
<property name="margin">
<number>0</number>
<widget class="QFrame" name="mValueGroupBox">
<layout class="QGridLayout" name="gridLayout_5">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Values</string>
</property>
<property name="spacing">
<number>0</number>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsFilterLineEdit" name="txtSearchEditValues">
<property name="enabled">
<bool>true</bool>
</property>
<item row="1" column="0" colspan="2">
<widget class="QListWidget" name="mValueListWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="viewMode">
<enum>QListView::ListMode</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Values</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="mLoadGroupBox" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="margin">
<number>0</number>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QListView" name="mValuesListView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblLoad">
<property name="text">
<string>Load values</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnLoadAll">
<property name="text">
<string>all unique</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnLoadSample">
<property name="text">
<string>10 samples</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="mLoadGroupBox" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblLoad">
<property name="text">
<string>Load values</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnLoadAll">
<property name="text">
<string>all unique</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnLoadSample">
<property name="text">
<string>10 samples</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>