QGIS API Documentation  3.2.0-Bonn (bc43194)
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"
25 #include <QHBoxLayout>
26 #include <QVBoxLayout>
27 #include <QToolButton>
28 
29 
31  : QWidget( parent )
32  , mExpressionDialogTitle( tr( "Expression Dialog" ) )
33 {
34  mButton = new QToolButton();
35  mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
36  mButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ) );
37  connect( mButton, &QAbstractButton::clicked, this, &QgsExpressionLineEdit::editExpression );
38 
39  //sets up layout
40  setMultiLine( false );
41 
42  mExpressionContext = QgsExpressionContext();
43  mExpressionContext << QgsExpressionContextUtils::globalScope()
45 }
46 
48 {
49  mExpressionDialogTitle = title;
50 }
51 
53 {
54  QString exp = expression();
55 
56  if ( multiLine && !mCodeEditor )
57  {
58  mCodeEditor = new QgsCodeEditorSQL();
59  mCodeEditor->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
60  delete mLineEdit;
61  mLineEdit = nullptr;
62 
63  QHBoxLayout *newLayout = new QHBoxLayout();
64  newLayout->setContentsMargins( 0, 0, 0, 0 );
65  newLayout->addWidget( mCodeEditor );
66 
67  QVBoxLayout *vLayout = new QVBoxLayout();
68  vLayout->addWidget( mButton );
69  vLayout->addStretch();
70  newLayout->addLayout( vLayout );
71 
72  delete layout();
73  setLayout( newLayout );
74 
75  setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
76 
77  setFocusProxy( mCodeEditor );
78  connect( mCodeEditor, &QsciScintilla::textChanged, this, static_cast < void ( QgsExpressionLineEdit::* )() > ( &QgsExpressionLineEdit::expressionEdited ) );
79 
80  setExpression( exp );
81  }
82  else if ( !multiLine && !mLineEdit )
83  {
84  delete mCodeEditor;
85  mCodeEditor = nullptr;
86  mLineEdit = new QgsFilterLineEdit();
87  mLineEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
88 
89  QHBoxLayout *newLayout = new QHBoxLayout();
90  newLayout->setContentsMargins( 0, 0, 0, 0 );
91  newLayout->addWidget( mLineEdit );
92  newLayout->addWidget( mButton );
93 
94  delete layout();
95  setLayout( newLayout );
96 
97  setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
98 
99  setFocusProxy( mLineEdit );
100  connect( mLineEdit, &QLineEdit::textChanged, this, static_cast < void ( QgsExpressionLineEdit::* )( const QString & ) > ( &QgsExpressionLineEdit::expressionEdited ) );
101 
102  setExpression( exp );
103  }
104 }
105 
107 {
108  mDa.reset( new QgsDistanceArea( da ) );
109 }
110 
112 {
113  if ( !mExpressionContextGenerator || mExpressionContextGenerator == mLayer )
114  mExpressionContextGenerator = layer;
115  mLayer = layer;
116 }
117 
119 {
120  if ( mLineEdit )
121  return mLineEdit->text();
122  else if ( mCodeEditor )
123  return mCodeEditor->text();
124 
125  return QString();
126 }
127 
128 bool QgsExpressionLineEdit::isValidExpression( QString *expressionError ) const
129 {
130  QString temp;
131  return QgsExpression::checkExpression( expression(), &mExpressionContext, expressionError ? *expressionError : temp );
132 }
133 
135 {
136  mExpressionContextGenerator = generator;
137 }
138 
139 void QgsExpressionLineEdit::setExpression( const QString &newExpression )
140 {
141  if ( mLineEdit )
142  mLineEdit->setText( newExpression );
143  else if ( mCodeEditor )
144  mCodeEditor->setText( newExpression );
145 }
146 
147 void QgsExpressionLineEdit::editExpression()
148 {
149  QString currentExpression = expression();
150 
151  QgsExpressionContext context = mExpressionContextGenerator ? mExpressionContextGenerator->createExpressionContext() : mExpressionContext;
152 
153  QgsExpressionBuilderDialog dlg( mLayer, currentExpression, this, QStringLiteral( "generic" ), context );
154  if ( mDa )
155  {
156  dlg.setGeomCalculator( *mDa );
157  }
158  dlg.setWindowTitle( mExpressionDialogTitle );
159 
160  if ( dlg.exec() )
161  {
162  QString newExpression = dlg.expressionText();
163  setExpression( newExpression );
164  }
165 }
166 
167 void QgsExpressionLineEdit::expressionEdited()
168 {
169  emit expressionChanged( expression() );
170 }
171 
172 void QgsExpressionLineEdit::expressionEdited( const QString &expression )
173 {
174  updateLineEditStyle( expression );
175  emit expressionChanged( expression );
176 }
177 
179 {
180  if ( event->type() == QEvent::EnabledChange )
181  {
182  updateLineEditStyle( expression() );
183  }
184 }
185 
186 void QgsExpressionLineEdit::updateLineEditStyle( const QString &expression )
187 {
188  if ( !mLineEdit )
189  return;
190 
191  QPalette palette;
192  if ( !isEnabled() )
193  {
194  palette.setColor( QPalette::Text, Qt::gray );
195  }
196  else
197  {
198  bool isValid = true;
199  if ( !expression.isEmpty() )
200  {
201  isValid = isExpressionValid( expression );
202  }
203  if ( !isValid )
204  {
205  palette.setColor( QPalette::Text, Qt::red );
206  }
207  else
208  {
209  palette.setColor( QPalette::Text, Qt::black );
210  }
211  }
212  mLineEdit->setPalette( palette );
213 }
214 
215 bool QgsExpressionLineEdit::isExpressionValid( const QString &expressionStr )
216 {
217  QgsExpression expression( expressionStr );
218  expression.prepare( &mExpressionContext );
219  return !expression.hasParserError();
220 }
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 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.
A SQL editor based on QScintilla2.
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:391
bool isValidExpression(QString *expressionError=nullptr) const
Returns true 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.