34#include "moc_qgsfieldexpressionwidget.cpp"
36using namespace Qt::StringLiterals;
40 , mExpressionDialogTitle( tr(
"Expression Builder" ) )
41 , mDistanceArea( nullptr )
44 QHBoxLayout *layout =
new QHBoxLayout(
this );
45 layout->setContentsMargins( 0, 0, 0, 0 );
47 mCombo =
new QComboBox(
this );
48 mCombo->setEditable(
true );
49 mCombo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
50 const int width = mCombo->minimumSizeHint().width();
51 mCombo->setMinimumWidth( width );
54 mFieldProxyModel->sourceFieldModel()->setAllowExpression(
true );
55 mCombo->setModel( mFieldProxyModel );
57 mButton =
new QToolButton(
this );
58 mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
61 layout->addWidget( mCombo );
62 layout->addWidget( mButton );
68 connect( mFieldProxyModel, &QAbstractItemModel::modelAboutToBeReset,
this, &QgsFieldExpressionWidget::beforeResetModel );
69 connect( mFieldProxyModel, &QAbstractItemModel::modelReset,
this, &QgsFieldExpressionWidget::afterResetModel );
74 mCombo->installEventFilter(
this );
79 mExpressionDialogTitle = title;
84 mFieldProxyModel->setFilters(
filters );
89 mCombo->lineEdit()->setClearButtonEnabled( allowEmpty );
90 mFieldProxyModel->sourceFieldModel()->setAllowEmptyFieldName( allowEmpty );
95 return mFieldProxyModel->sourceFieldModel()->allowEmptyFieldName();
100 QHBoxLayout *layout =
dynamic_cast<QHBoxLayout *
>( this->layout() );
106 QLayoutItem *item = layout->takeAt( 1 );
107 layout->insertWidget( 0, item->widget() );
110 layout->addWidget( mCombo );
115 mDistanceArea = std::shared_ptr<const QgsDistanceArea>(
new QgsDistanceArea( da ) );
120 return mCombo->currentText();
141 return !mFieldProxyModel->sourceFieldModel()->isField(
currentText() );
162 return mFieldProxyModel->sourceFieldModel()->layer();
167 mExpressionContextGenerator = generator;
171 const QString &label,
const QList<QPair<QString, QVariant>> &choices,
const std::function<
QgsExpressionContext(
const QVariant & )> &previewContextGenerator
174 mCustomPreviewLabel = label;
175 mCustomChoices = choices;
176 mPreviewContextGenerator = previewContextGenerator;
183 if ( mFieldProxyModel->sourceFieldModel()->layer() )
191 mFieldProxyModel->sourceFieldModel()->setLayer( vl );
193 if ( mFieldProxyModel->sourceFieldModel()->layer() )
194 connect( mFieldProxyModel->sourceFieldModel()->layer(), &
QgsVectorLayer::updatedFields,
this, &QgsFieldExpressionWidget::reloadLayer, Qt::UniqueConnection );
199 if ( fieldName.isEmpty() )
207 if ( fieldName.size() > mCombo->lineEdit()->maxLength() )
209 mCombo->lineEdit()->setMaxLength( fieldName.size() );
212 QModelIndex idx = mFieldProxyModel->sourceFieldModel()->indexFromName( fieldName );
213 if ( !idx.isValid() )
216 QString simpleFieldName = fieldName.trimmed();
217 if ( simpleFieldName.startsWith(
'"' ) && simpleFieldName.endsWith(
'"' ) )
219 simpleFieldName.remove( 0, 1 ).chop( 1 );
220 idx = mFieldProxyModel->sourceFieldModel()->indexFromName( simpleFieldName );
223 if ( !idx.isValid() )
226 mFieldProxyModel->sourceFieldModel()->setExpression( fieldName );
227 idx = mFieldProxyModel->sourceFieldModel()->indexFromName( fieldName );
230 const QModelIndex proxyIndex = mFieldProxyModel->mapFromSource( idx );
231 mCombo->setCurrentIndex( proxyIndex.row() );
237 mFieldProxyModel->sourceFieldModel()->setFields( fields );
250 const QgsExpressionContext context = mExpressionContextGenerator ? mExpressionContextGenerator->createExpressionContext() : mExpressionContext;
257 dlg.setWindowTitle( mExpressionDialogTitle );
260 if ( !mCustomChoices.isEmpty() )
283 const QString
expression = mCombo->lineEdit()->text();
284 mFieldProxyModel->sourceFieldModel()->setExpression(
expression );
285 const QModelIndex idx = mFieldProxyModel->sourceFieldModel()->indexFromName(
expression );
286 const QModelIndex proxyIndex = mFieldProxyModel->mapFromSource( idx );
287 mCombo->setCurrentIndex( proxyIndex.row() );
293 if ( event->type() == QEvent::EnabledChange )
299void QgsFieldExpressionWidget::reloadLayer()
304void QgsFieldExpressionWidget::beforeResetModel()
307 mBackupExpression = mCombo->currentText();
310void QgsFieldExpressionWidget::afterResetModel()
313 mCombo->lineEdit()->setText( mBackupExpression );
318 if ( watched == mCombo && event->type() == QEvent::KeyPress )
320 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>( event );
321 if ( keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return )
327 return QObject::eventFilter( watched, event );
332 return mAllowEvalErrors;
347 return mButton->isVisibleTo(
this );
355 mButton->setVisible( visible );
367 const QFontMetrics metrics( mCombo->lineEdit()->font() );
368 if ( metrics.boundingRect( fieldName ).width() > mCombo->lineEdit()->width() )
370 mCombo->setToolTip( fieldName );
374 mCombo->setToolTip( QString() );
386 stylesheet = u
"QLineEdit { color: %1; }"_s.arg( QColor( Qt::gray ).name() );
400 QFont font = mCombo->lineEdit()->font();
402 font.setItalic(
false );
403 mCombo->lineEdit()->setFont( font );
407 stylesheet = u
"QLineEdit { color: %1; }"_s.arg( QColor( Qt::red ).name() );
410 mCombo->lineEdit()->setStyleSheet( stylesheet );
422 mExpressionContext.appendScope( scope );
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QFont getMonospaceFont()
Returns the monospaced font to use for code editors.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
A generic dialog for building expression strings.
void setGeomCalculator(const QgsDistanceArea &da)
Sets geometry calculator used in distance/area calculations.
QgsExpressionBuilderWidget * expressionBuilder()
The builder widget that is used by the dialog.
void setAllowEvalErrors(bool allowEvalErrors)
Allow accepting expressions with evaluation errors.
Abstract interface for generating an expression context.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void loadFieldNames(const QgsFields &fields)
This allows loading fields without specifying a layer.
Handles parsing and evaluation of expressions (formerly called "search strings").
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
static bool checkExpression(const QString &text, const QgsExpressionContext *context, QString &errorMessage)
Tests whether a string is a valid expression.
A proxy model to filter the list of fields of a layer.
QgsFieldModel * sourceFieldModel()
Returns the QgsFieldModel used in this QSortFilterProxyModel.
Container of fields for a vector layer.
Base class for all map layer types.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Represents a vector layer which manages a vector based dataset.
QgsExpressionContext createExpressionContext() const final
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void updatedFields()
Emitted whenever the fields available from this layer have been changed.