QGIS API Documentation  3.6.0-Noosa (5873452)
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 {
51  mExpressionDialogTitle = title;
52 }
53 
55 {
56  QString exp = expression();
57 
58  if ( multiLine && !mCodeEditor )
59  {
60  mCodeEditor = new QgsCodeEditorExpression();
61  mCodeEditor->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
62  delete mLineEdit;
63  mLineEdit = nullptr;
64 
65  QHBoxLayout *newLayout = new QHBoxLayout();
66  newLayout->setContentsMargins( 0, 0, 0, 0 );
67  newLayout->addWidget( mCodeEditor );
68 
69  QVBoxLayout *vLayout = new QVBoxLayout();
70  vLayout->addWidget( mButton );
71  vLayout->addStretch();
72  newLayout->addLayout( vLayout );
73 
74  delete layout();
75  setLayout( newLayout );
76 
77  setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
78 
79  setFocusProxy( mCodeEditor );
80  connect( mCodeEditor, &QsciScintilla::textChanged, this, static_cast < void ( QgsExpressionLineEdit::* )() > ( &QgsExpressionLineEdit::expressionEdited ) );
81 
82  setExpression( exp );
83  }
84  else if ( !multiLine && !mLineEdit )
85  {
86  delete mCodeEditor;
87  mCodeEditor = nullptr;
88  mLineEdit = new QgsFilterLineEdit();
89  mLineEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
90 
91  QHBoxLayout *newLayout = new QHBoxLayout();
92  newLayout->setContentsMargins( 0, 0, 0, 0 );
93  newLayout->addWidget( mLineEdit );
94  newLayout->addWidget( mButton );
95 
96  delete layout();
97  setLayout( newLayout );
98 
99  setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
100 
101  setFocusProxy( mLineEdit );
102  connect( mLineEdit, &QLineEdit::textChanged, this, static_cast < void ( QgsExpressionLineEdit::* )( const QString & ) > ( &QgsExpressionLineEdit::expressionEdited ) );
103 
104  setExpression( exp );
105  }
106 }
107 
109 {
110  return mExpectedOutputFormat;
111 }
112 
113 void QgsExpressionLineEdit::setExpectedOutputFormat( const QString &expected )
114 {
115  mExpectedOutputFormat = expected;
116 }
117 
119 {
120  mDa.reset( new QgsDistanceArea( da ) );
121 }
122 
124 {
125  if ( !mExpressionContextGenerator || mExpressionContextGenerator == mLayer )
126  mExpressionContextGenerator = layer;
127  mLayer = layer;
128 }
129 
131 {
132  if ( mLineEdit )
133  return mLineEdit->text();
134  else if ( mCodeEditor )
135  return mCodeEditor->text();
136 
137  return QString();
138 }
139 
140 bool QgsExpressionLineEdit::isValidExpression( QString *expressionError ) const
141 {
142  QString temp;
143  return QgsExpression::checkExpression( expression(), &mExpressionContext, expressionError ? *expressionError : temp );
144 }
145 
147 {
148  mExpressionContextGenerator = generator;
149 }
150 
151 void QgsExpressionLineEdit::setExpression( const QString &newExpression )
152 {
153  if ( mLineEdit )
154  mLineEdit->setText( newExpression );
155  else if ( mCodeEditor )
156  mCodeEditor->setText( newExpression );
157 }
158 
159 void QgsExpressionLineEdit::editExpression()
160 {
161  QString currentExpression = expression();
162 
163  QgsExpressionContext context = mExpressionContextGenerator ? mExpressionContextGenerator->createExpressionContext() : mExpressionContext;
164 
165  QgsExpressionBuilderDialog dlg( mLayer, currentExpression, this, QStringLiteral( "generic" ), context );
166  dlg.setExpectedOutputFormat( mExpectedOutputFormat );
167  if ( mDa )
168  {
169  dlg.setGeomCalculator( *mDa );
170  }
171  dlg.setWindowTitle( mExpressionDialogTitle );
172 
173  if ( dlg.exec() )
174  {
175  QString newExpression = dlg.expressionText();
176  setExpression( newExpression );
177  }
178 }
179 
180 void QgsExpressionLineEdit::expressionEdited()
181 {
182  emit expressionChanged( expression() );
183 }
184 
185 void QgsExpressionLineEdit::expressionEdited( const QString &expression )
186 {
187  updateLineEditStyle( expression );
188  emit expressionChanged( expression );
189 }
190 
192 {
193  if ( event->type() == QEvent::EnabledChange )
194  {
195  updateLineEditStyle( expression() );
196  }
197 }
198 
199 void QgsExpressionLineEdit::updateLineEditStyle( const QString &expression )
200 {
201  if ( !mLineEdit )
202  return;
203 
204  QPalette palette = mLineEdit->palette();
205  if ( !isEnabled() )
206  {
207  palette.setColor( QPalette::Text, Qt::gray );
208  }
209  else
210  {
211  bool isValid = true;
212  if ( !expression.isEmpty() )
213  {
214  isValid = isExpressionValid( expression );
215  }
216  if ( !isValid )
217  {
218  palette.setColor( QPalette::Text, Qt::red );
219  }
220  else
221  {
222  palette.setColor( QPalette::Text, Qt::black );
223  }
224  }
225  mLineEdit->setPalette( palette );
226 }
227 
228 bool QgsExpressionLineEdit::isExpressionValid( const QString &expressionStr )
229 {
230  QgsExpression expression( expressionStr );
231  expression.prepare( &mExpressionContext );
232  return !expression.hasParserError();
233 }
Class for parsing and evaluation of expressions (formerly called "search strings").
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
void setExpectedOutputFormat(const QString &expected)
Set the expected format string, which is shown in the dialog.
A QGIS expression editor based on QScintilla2.
void setMultiLine(bool multiLine)
Sets whether the widget should show a multiline text editor.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static bool checkExpression(const QString &text, const QgsExpressionContext *context, QString &errorMessage)
Tests whether a string is a valid expression.
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
void setExpression(const QString &expression)
Sets the current expression to show in the widget.
QString expression() const
Returns the current expression shown in the widget.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setGeomCalculator(const QgsDistanceArea &da)
Sets geometry calculator used in distance/area calculations.
QLineEdit subclass with built in support for clearing the widget&#39;s value and handling custom null val...
void setGeomCalculator(const QgsDistanceArea &distanceArea)
Set the geometry calculator used in the expression dialog.
Abstract interface for generating an expression context.
void expressionChanged(const QString &expression)
Emitted when the expression is changed.
void changeEvent(QEvent *event) override
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
void setExpressionDialogTitle(const QString &title)
Sets the title used in the expression builder dialog.
void setLayer(QgsVectorLayer *layer)
Sets a layer associated with the widget.
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
void registerExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:430
QString expectedOutputFormat() const
Returns the expected format string, which is shown in the expression builder dialog for the widget...
void setExpectedOutputFormat(const QString &expected)
Set the expected format string, which is shown in the expression builder dialog for the widget...
bool isValidExpression(QString *expressionError=nullptr) const
Determines if the current expression is valid.
QgsExpressionLineEdit(QWidget *parent=nullptr)
Constructor for QgsExpressionLineEdit.
Represents a vector layer which manages a vector based data sets.
A generic dialog for building expression strings.