Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Expression builder: show represented values in preview
Instead of only showing the raw values, show also the represented values in the expression builder in the list values preview.
This helps people to choose from readable values (whereas still the raw values get inserted on double click).
  • Loading branch information
m-kuhn committed May 20, 2019
1 parent 284f5d5 commit c698ba7
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 38 deletions.
92 changes: 59 additions & 33 deletions src/gui/qgsexpressionbuilderwidget.cpp
Expand Up @@ -30,6 +30,8 @@
#include "qgsrelationmanager.h"
#include "qgsrelation.h"
#include "qgsexpressioncontextutils.h"
#include "qgsfieldformatterregistry.h"
#include "qgsfieldformatter.h"

#include <QMenu>
#include <QFile>
Expand Down Expand Up @@ -60,11 +62,11 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
mValueGroupBox->hide();
// highlighter = new QgsExpressionHighlighter( txtExpressionString->document() );

mModel = new QStandardItemModel();
mProxyModel = new QgsExpressionItemSearchProxy();
mModel = qgis::make_unique<QStandardItemModel>();
mProxyModel = qgis::make_unique<QgsExpressionItemSearchProxy>();
mProxyModel->setDynamicSortFilter( true );
mProxyModel->setSourceModel( mModel );
expressionTree->setModel( mProxyModel );
mProxyModel->setSourceModel( mModel.get() );
expressionTree->setModel( mProxyModel.get() );
expressionTree->setSortingEnabled( true );
expressionTree->sortByColumn( 0, Qt::AscendingOrder );

Expand All @@ -86,10 +88,10 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
txtSearchEdit->setShowSearchIcon( true );
txtSearchEdit->setPlaceholderText( tr( "Search…" ) );

mValuesModel = new QStringListModel();
mProxyValues = new QSortFilterProxyModel();
mProxyValues->setSourceModel( mValuesModel );
mValuesListView->setModel( mProxyValues );
mValuesModel = qgis::make_unique<QStandardItemModel>();
mProxyValues = qgis::make_unique<QSortFilterProxyModel>();
mProxyValues->setSourceModel( mValuesModel.get() );
mValuesListView->setModel( mProxyValues.get() );
txtSearchEditValues->setShowSearchIcon( true );
txtSearchEditValues->setPlaceholderText( tr( "Search…" ) );

Expand Down Expand Up @@ -210,11 +212,6 @@ QgsExpressionBuilderWidget::~QgsExpressionBuilderWidget()
settings.setValue( QStringLiteral( "Windows/QgsExpressionBuilderWidget/splitter" ), splitter->saveState() );
settings.setValue( QStringLiteral( "Windows/QgsExpressionBuilderWidget/editorsplitter" ), editorSplit->saveState() );
settings.setValue( QStringLiteral( "Windows/QgsExpressionBuilderWidget/functionsplitter" ), functionsplit->saveState() );

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

void QgsExpressionBuilderWidget::setLayer( QgsVectorLayer *layer )
Expand All @@ -240,15 +237,7 @@ void QgsExpressionBuilderWidget::currentChanged( const QModelIndex &index, const
bool isField = mLayer && item->getItemType() == QgsExpressionItem::Field;
if ( isField )
{
if ( mFieldValues.contains( item->text() ) )
{
const QStringList &values = mFieldValues[item->text()];
mValuesModel->setStringList( values );
}
else
{
mValuesModel->setStringList( QStringList() );
}
loadFieldValues( mFieldValues.value( item->text() ) );
}
mValueGroupBox->setVisible( isField );
mShowHelpButton->setText( isField ? tr( "Show Values" ) : tr( "Show Help" ) );
Expand Down Expand Up @@ -429,10 +418,28 @@ void QgsExpressionBuilderWidget::loadFieldNames( const QgsFields &fields )
QIcon icon = fields.iconForField( i );
registerItem( QStringLiteral( "Fields and Values" ), fieldName, " \"" + fieldName + "\" ", QString(), QgsExpressionItem::Field, false, i, icon );
}
// highlighter->addFields( fieldNames );
// highlighter->addFields( fieldNames );
}

void QgsExpressionBuilderWidget::loadFieldsAndValues( const QMap<QString, QStringList> &fieldValues )
{
mFieldValues.clear();
QgsFields fields;
for ( auto it = fieldValues.constBegin(); it != fieldValues.constEnd(); ++it )
{
fields.append( QgsField( it.key() ) );
const QStringList values = it.value();
QVariantMap map;
for ( const QString &value : values )
{
map.insert( value, value );
}
mFieldValues.insert( it.key(), map );
}
loadFieldNames( fields );
}

void QgsExpressionBuilderWidget::loadFieldsAndValues( const QMap<QString, QVariantMap> &fieldValues )
{
QgsFields fields;
for ( auto it = fieldValues.constBegin(); it != fieldValues.constEnd(); ++it )
Expand All @@ -452,16 +459,19 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int

// TODO We should thread this so that we don't hold the user up if the layer is massive.

int fieldIndex = mLayer->fields().lookupField( fieldName );
const QgsFields fields = mLayer->fields();
int fieldIndex = fields.lookupField( fieldName );

if ( fieldIndex < 0 )
return;

QStringList strValues;
const QgsEditorWidgetSetup setup = fields.at( fieldIndex ).editorWidgetSetup();
const QgsFieldFormatter *formatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );

QList<QVariant> values = mLayer->uniqueValues( fieldIndex, countLimit ).toList();
std::sort( values.begin(), values.end() );
const auto constValues = values;
for ( const QVariant &value : constValues )

for ( const QVariant &value : qgis::as_const( values ) )
{
QString strValue;
if ( value.isNull() )
Expand All @@ -470,10 +480,15 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
strValue = value.toString();
else
strValue = '\'' + value.toString().replace( '\'', QLatin1String( "''" ) ) + '\'';
strValues.append( strValue );

QString representedValue = formatter->representValue( mLayer, fieldIndex, setup.config(), QVariant(), value );
if ( representedValue != strValue )
representedValue = representedValue + QStringLiteral( " [" ) + strValue + ']';

QStandardItem *item = new QStandardItem( representedValue );
item->setData( strValue );
mValuesModel->appendRow( item );
}
mValuesModel->setStringList( strValues );
mFieldValues[fieldName] = strValues;
}

QString QgsExpressionBuilderWidget::getFunctionHelp( QgsExpressionFunction *function )
Expand All @@ -483,7 +498,7 @@ QString QgsExpressionBuilderWidget::getFunctionHelp( QgsExpressionFunction *func

QString helpContents = QgsExpression::helpText( function->name() );

return "<head><style>" + helpStylesheet() + "</style></head><body>" + helpContents + "</body>";
return QStringLiteral( "<head><style>" ) + helpStylesheet() + QStringLiteral( "</style></head><body>" ) + helpContents + QStringLiteral( "</body>" );

}

Expand Down Expand Up @@ -842,6 +857,17 @@ void QgsExpressionBuilderWidget::setParserError( bool parserError )
emit parserErrorChanged();
}

void QgsExpressionBuilderWidget::loadFieldValues( const QVariantMap &values )
{
mValuesModel->clear();
for ( QVariantMap::ConstIterator it = values.constBegin(); it != values.constEnd(); ++ it )
{
QStandardItem *item = new QStandardItem( it.key() );
item->setData( it.value() );
mValuesModel->appendRow( item );
}
}

bool QgsExpressionBuilderWidget::evalError() const
{
return mEvalError;
Expand All @@ -858,7 +884,7 @@ void QgsExpressionBuilderWidget::setEvalError( bool evalError )

QStandardItemModel *QgsExpressionBuilderWidget::model()
{
return mModel;
return mModel.get();
}

QgsProject *QgsExpressionBuilderWidget::project()
Expand Down Expand Up @@ -1034,7 +1060,7 @@ void QgsExpressionBuilderWidget::lblPreview_linkActivated( const QString &link )
void QgsExpressionBuilderWidget::mValuesListView_doubleClicked( const QModelIndex &index )
{
// Insert the item text or replace selected text
txtExpressionString->insertText( ' ' + index.data( Qt::DisplayRole ).toString() + ' ' );
txtExpressionString->insertText( ' ' + index.data( Qt::UserRole + 1 ).toString() + ' ' );
txtExpressionString->setFocus();
}

Expand Down
17 changes: 12 additions & 5 deletions src/gui/qgsexpressionbuilderwidget.h
Expand Up @@ -431,19 +431,26 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
*/
void setParserError( bool parserError );

void loadFieldValues( const QVariantMap &values );

void loadFieldsAndValues( const QMap<QString, QVariantMap> &fieldValues );

bool mAutoSave = true;
QString mFunctionsPath;
QgsVectorLayer *mLayer = nullptr;
QStandardItemModel *mModel = nullptr;
QStringListModel *mValuesModel = nullptr;
QSortFilterProxyModel *mProxyValues = nullptr;
QgsExpressionItemSearchProxy *mProxyModel = nullptr;
std::unique_ptr<QStandardItemModel> mModel;
// Will hold items with
// * a display string that matches the represented field values
// * custom data in Qt::UserRole + 1 that contains a ready to use expression literal ('quoted string' or NULL or a plain number )
std::unique_ptr<QStandardItemModel> mValuesModel;
std::unique_ptr<QSortFilterProxyModel> mProxyValues;
std::unique_ptr<QgsExpressionItemSearchProxy> mProxyModel;
QMap<QString, QgsExpressionItem *> mExpressionGroups;
QgsExpressionHighlighter *highlighter = nullptr;
bool mExpressionValid = false;
QgsDistanceArea mDa;
QString mRecentKey;
QMap<QString, QStringList> mFieldValues;
QMap<QString, QVariantMap> mFieldValues;
QgsExpressionContext mExpressionContext;
QPointer< QgsProject > mProject;
bool mEvalError = true;
Expand Down

0 comments on commit c698ba7

Please sign in to comment.