QGIS API Documentation  3.25.0-Master (6b426f5f8a)
qgsexpressionlineedit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpressionlineedit.cpp
3  ------------------------
4  Date : 18.08.2016
5  Copyright : (C) 2016 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15 
16 #include "qgsexpressionlineedit.h"
17 #include "qgsfilterlineedit.h"
18 #include "qgsexpressioncontext.h"
19 #include "qgsapplication.h"
22 #include "qgscodeeditorsql.h"
23 #include "qgsproject.h"
24 #include "qgsvectorlayer.h"
26 
27 #include <QHBoxLayout>
28 #include <QVBoxLayout>
29 #include <QToolButton>
30 
31 
33  : QWidget( parent )
34  , mExpressionDialogTitle( tr( "Expression Dialog" ) )
35 {
36  mButton = new QToolButton();
37  mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
38  mButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ) );
39  connect( mButton, &QAbstractButton::clicked, this, &QgsExpressionLineEdit::editExpression );
40 
41  //sets up layout
42  setMultiLine( false );
43 
44  mExpressionContext = QgsExpressionContext();
45  mExpressionContext << QgsExpressionContextUtils::globalScope()
47 }
48 
50 
52 {
53  mExpressionDialogTitle = title;
54 }
55 
57 {
58  const QString exp = expression();
59 
60  if ( multiLine && !mCodeEditor )
61  {
62  mCodeEditor = new QgsCodeEditorExpression();
63  mCodeEditor->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
64  delete mLineEdit;
65  mLineEdit = nullptr;
66 
67  QHBoxLayout *newLayout = new QHBoxLayout();
68  newLayout->setContentsMargins( 0, 0, 0, 0 );
69  newLayout->addWidget( mCodeEditor );
70 
71  QVBoxLayout *vLayout = new QVBoxLayout();
72  vLayout->addWidget( mButton );
73  vLayout->addStretch();
74  newLayout->addLayout( vLayout );
75 
76  delete layout();
77  setLayout( newLayout );
78 
79  setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
80 
81  setFocusProxy( mCodeEditor );
82  connect( mCodeEditor, &QsciScintilla::textChanged, this, static_cast < void ( QgsExpressionLineEdit::* )() > ( &QgsExpressionLineEdit::expressionEdited ) );
83 
84  setExpression( exp );
85  }
86  else if ( !multiLine && !mLineEdit )
87  {
88  delete mCodeEditor;
89  mCodeEditor = nullptr;
90  mLineEdit = new QgsFilterLineEdit();
91  mLineEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
92 
93  QHBoxLayout *newLayout = new QHBoxLayout();
94  newLayout->setContentsMargins( 0, 0, 0, 0 );
95  newLayout->addWidget( mLineEdit );
96  newLayout->addWidget( mButton );
97 
98  delete layout();
99  setLayout( newLayout );
100 
101  setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
102 
103  setFocusProxy( mLineEdit );
104  connect( mLineEdit, &QLineEdit::textChanged, this, static_cast < void ( QgsExpressionLineEdit::* )( const QString & ) > ( &QgsExpressionLineEdit::expressionEdited ) );
105 
106  setExpression( exp );
107  }
108 }
109 
111 {
112  return mExpectedOutputFormat;
113 }
114 
115 void QgsExpressionLineEdit::setExpectedOutputFormat( const QString &expected )
116 {
117  mExpectedOutputFormat = expected;
118 }
119 
121 {
122  mDa.reset( new QgsDistanceArea( da ) );
123 }
124 
126 {
127  if ( !mExpressionContextGenerator || mExpressionContextGenerator == mLayer )
128  mExpressionContextGenerator = layer;
129  mLayer = layer;
130 }
131 
133 {
134  if ( mLineEdit )
135  return mLineEdit->text();
136  else if ( mCodeEditor )
137  return mCodeEditor->text();
138 
139  return QString();
140 }
141 
142 bool QgsExpressionLineEdit::isValidExpression( QString *expressionError ) const
143 {
144  QString temp;
145  const QgsExpressionContext context = mExpressionContextGenerator ? mExpressionContextGenerator->createExpressionContext() : mExpressionContext;
146  return QgsExpression::checkExpression( expression(), &context, expressionError ? *expressionError : temp );
147 }
148 
150 {
151  mExpressionContextGenerator = generator;
152 }
153 
154 void QgsExpressionLineEdit::setExpression( const QString &newExpression )
155 {
156  if ( mLineEdit )
157  mLineEdit->setText( newExpression );
158  else if ( mCodeEditor )
159  mCodeEditor->setText( newExpression );
160 }
161 
162 void QgsExpressionLineEdit::editExpression()
163 {
164  const QString currentExpression = expression();
165 
166  const QgsExpressionContext context = mExpressionContextGenerator ? mExpressionContextGenerator->createExpressionContext() : mExpressionContext;
167 
168  QgsExpressionBuilderDialog dlg( mLayer, currentExpression, this, QStringLiteral( "generic" ), context );
169  dlg.setExpectedOutputFormat( mExpectedOutputFormat );
170  if ( mDa )
171  {
172  dlg.setGeomCalculator( *mDa );
173  }
174  dlg.setWindowTitle( mExpressionDialogTitle );
175 
176  if ( dlg.exec() )
177  {
178  const QString newExpression = dlg.expressionText();
179  setExpression( newExpression );
180  }
181 }
182 
183 void QgsExpressionLineEdit::expressionEdited()
184 {
185  emit expressionChanged( expression() );
186 }
187 
188 void QgsExpressionLineEdit::expressionEdited( const QString &expression )
189 {
190  updateLineEditStyle( expression );
192 }
193 
195 {
196  if ( event->type() == QEvent::EnabledChange )
197  {
198  updateLineEditStyle( expression() );
199  }
200 }
201 
202 void QgsExpressionLineEdit::updateLineEditStyle( const QString &expression )
203 {
204  if ( !mLineEdit )
205  return;
206 
207  QPalette palette = mLineEdit->palette();
208  if ( !isEnabled() )
209  {
210  palette.setColor( QPalette::Text, Qt::gray );
211  }
212  else
213  {
214  bool isValid = true;
215  if ( !expression.isEmpty() )
216  {
217  isValid = isExpressionValid( expression );
218  }
219  if ( !isValid )
220  {
221  palette.setColor( QPalette::Text, Qt::red );
222  }
223  else
224  {
225  palette.setColor( QPalette::Text, Qt::black );
226  }
227  }
228  mLineEdit->setPalette( palette );
229 }
230 
231 bool QgsExpressionLineEdit::isExpressionValid( const QString &expressionStr )
232 {
233  QgsExpression expression( expressionStr );
234 
235  const QgsExpressionContext context = mExpressionContextGenerator ? mExpressionContextGenerator->createExpressionContext() : mExpressionContext;
236  expression.prepare( &mExpressionContext );
237  return !expression.hasParserError();
238 }
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A QGIS expression editor based on QScintilla2.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
A generic dialog for building expression strings.
Abstract interface for generating an expression context.
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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...
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
QString expression() const
Returns the current expression shown in the widget.
void setMultiLine(bool multiLine)
Sets whether the widget should show a multiline text editor.
void changeEvent(QEvent *event) override
bool isValidExpression(QString *expressionError=nullptr) const
Determines if the current expression is valid.
~QgsExpressionLineEdit() override
void expressionChanged(const QString &expression)
Emitted when the expression is changed.
void registerExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
void setExpectedOutputFormat(const QString &expected)
Set the expected format string, which is shown in the expression builder dialog for the widget.
void setGeomCalculator(const QgsDistanceArea &distanceArea)
Set the geometry calculator used in the expression dialog.
void setExpressionDialogTitle(const QString &title)
Sets the title used in the expression builder dialog.
void setExpression(const QString &expression)
Sets the current expression to show in the widget.
QString expectedOutputFormat() const
Returns the expected format string, which is shown in the expression builder dialog for the widget.
QgsExpressionLineEdit(QWidget *parent=nullptr)
Constructor for QgsExpressionLineEdit.
void setLayer(QgsVectorLayer *layer)
Sets a layer associated with the widget.
Class for parsing and evaluation of expressions (formerly called "search strings").
static bool checkExpression(const QString &text, const QgsExpressionContext *context, QString &errorMessage)
Tests whether a string is a valid expression.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:472
Represents a vector layer which manages a vector based data sets.