-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3417 from nyalldawson/expression_line_edit
Expression line edit widget
- Loading branch information
Showing
11 changed files
with
556 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/** \ingroup gui | ||
* @class QgsExpressionLineEdit | ||
* @brief The QgsExpressionLineEdit widget includes a line edit for entering expressions | ||
* together with a button to open the expression creation dialog. | ||
* | ||
* This widget is designed for use in contexts where no layer fields are available for | ||
* use in an expression. In contexts where the expression is directly associated with | ||
* a layer and fields can be used, then QgsFieldExpressionWidget is a more appropriate | ||
* choice as it gives users direct access to select fields from a drop down list. | ||
* @note added in QGIS 3.0 | ||
*/ | ||
|
||
class QgsExpressionLineEdit : QWidget | ||
{ | ||
%TypeHeaderCode | ||
#include "qgsexpressionlineedit.h" | ||
%End | ||
|
||
public: | ||
|
||
/** | ||
* Constructor for QgsExpressionLineEdit. | ||
* @param parent parent widget | ||
*/ | ||
explicit QgsExpressionLineEdit( QWidget *parent /TransferThis/ = nullptr ); | ||
/** Sets the title used in the expression builder dialog | ||
* @param title dialog title | ||
* @see expressionDialogTitle() | ||
*/ | ||
void setExpressionDialogTitle( const QString& title ); | ||
|
||
/** Returns the title used for the expression dialog. | ||
* @see setExpressionDialogTitle() | ||
*/ | ||
QString expressionDialogTitle() const; | ||
|
||
/** Sets whether the widget should show a multiline text editor. | ||
* @param multiLine set to true to show multiline editor, or false | ||
* to show single line editor (the default). | ||
*/ | ||
void setMultiLine( bool multiLine ); | ||
|
||
/** Set the geometry calculator used in the expression dialog. | ||
* @param distanceArea calculator | ||
*/ | ||
void setGeomCalculator( const QgsDistanceArea &distanceArea ); | ||
|
||
/** Sets a layer associated with the widget. Required in order to get the fields and values | ||
* from the layer. | ||
* @param layer vector layer | ||
*/ | ||
void setLayer( QgsVectorLayer* layer ); | ||
|
||
/** Returns the current expression shown in the widget. | ||
* @see setExpression() | ||
*/ | ||
QString expression() const; | ||
|
||
/** | ||
* Returns true if the current expression is valid. | ||
* @param expressionError will be set to any generated error message if specified | ||
*/ | ||
bool isValidExpression( QString *expressionError /Out/ = nullptr ) const; | ||
|
||
/** | ||
* Register an expression context generator class that will be used to retrieve | ||
* an expression context for the widget. | ||
* @param generator A QgsExpressionContextGenerator class that will be used to | ||
* create an expression context when required. | ||
*/ | ||
void registerExpressionContextGenerator( const QgsExpressionContextGenerator* generator ); | ||
|
||
signals: | ||
|
||
/** Emitted when the expression is changed. | ||
* @param expression new expression | ||
*/ | ||
void expressionChanged( const QString& expression ); | ||
|
||
public slots: | ||
|
||
/** Sets the current expression to show in the widget. | ||
* @param expression expression string | ||
* @see expression() | ||
*/ | ||
void setExpression( const QString& expression ); | ||
|
||
protected: | ||
void changeEvent( QEvent* event ); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
/*************************************************************************** | ||
qgsexpressionlineedit.cpp | ||
------------------------ | ||
Date : 18.08.2016 | ||
Copyright : (C) 2016 Nyall Dawson | ||
Email : nyall dot dawson at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsexpressionlineedit.h" | ||
#include "qgsfilterlineedit.h" | ||
#include "qgsexpressioncontext.h" | ||
#include "qgsapplication.h" | ||
#include "qgsexpressionbuilderdialog.h" | ||
#include "qgsexpressioncontextgenerator.h" | ||
#include "qgscodeeditorsql.h" | ||
#include <QHBoxLayout> | ||
#include <QVBoxLayout> | ||
#include <QToolButton> | ||
|
||
|
||
QgsExpressionLineEdit::QgsExpressionLineEdit( QWidget *parent ) | ||
: QWidget( parent ) | ||
, mLineEdit( nullptr ) | ||
, mCodeEditor( nullptr ) | ||
, mExpressionDialogTitle( tr( "Expression dialog" ) ) | ||
, mDa( nullptr ) | ||
, mExpressionContextGenerator( nullptr ) | ||
, mLayer( nullptr ) | ||
{ | ||
mButton = new QToolButton(); | ||
mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); | ||
mButton->setIcon( QgsApplication::getThemeIcon( "/mIconExpression.svg" ) ); | ||
connect( mButton, SIGNAL( clicked() ), this, SLOT( editExpression() ) ); | ||
|
||
//sets up layout | ||
setMultiLine( false ); | ||
|
||
mExpressionContext = QgsExpressionContext(); | ||
mExpressionContext << QgsExpressionContextUtils::globalScope() | ||
<< QgsExpressionContextUtils::projectScope(); | ||
} | ||
|
||
void QgsExpressionLineEdit::setExpressionDialogTitle( const QString& title ) | ||
{ | ||
mExpressionDialogTitle = title; | ||
} | ||
|
||
void QgsExpressionLineEdit::setMultiLine( bool multiLine ) | ||
{ | ||
QString exp = expression(); | ||
|
||
if ( multiLine && !mCodeEditor ) | ||
{ | ||
mCodeEditor = new QgsCodeEditorSQL(); | ||
mCodeEditor->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); | ||
delete mLineEdit; | ||
mLineEdit = nullptr; | ||
|
||
QHBoxLayout* newLayout = new QHBoxLayout(); | ||
newLayout->setContentsMargins( 0, 0, 0, 0 ); | ||
newLayout->addWidget( mCodeEditor ); | ||
|
||
QVBoxLayout* vLayout = new QVBoxLayout(); | ||
vLayout->addWidget( mButton ); | ||
vLayout->addStretch(); | ||
newLayout->addLayout( vLayout ); | ||
|
||
delete layout(); | ||
setLayout( newLayout ); | ||
|
||
setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); | ||
|
||
setFocusProxy( mCodeEditor ); | ||
connect( mCodeEditor, SIGNAL( textChanged() ), this, SLOT( expressionEdited() ) ); | ||
|
||
setExpression( exp ); | ||
} | ||
else if ( !multiLine && !mLineEdit ) | ||
{ | ||
delete mCodeEditor; | ||
mCodeEditor = nullptr; | ||
mLineEdit = new QgsFilterLineEdit(); | ||
mLineEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ); | ||
|
||
QHBoxLayout* newLayout = new QHBoxLayout(); | ||
newLayout->setContentsMargins( 0, 0, 0, 0 ); | ||
newLayout->addWidget( mLineEdit ); | ||
newLayout->addWidget( mButton ); | ||
|
||
delete layout(); | ||
setLayout( newLayout ); | ||
|
||
setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ); | ||
|
||
setFocusProxy( mLineEdit ); | ||
connect( mLineEdit, SIGNAL( textChanged( QString ) ), this, SLOT( expressionEdited( QString ) ) ); | ||
|
||
setExpression( exp ); | ||
} | ||
} | ||
|
||
void QgsExpressionLineEdit::setGeomCalculator( const QgsDistanceArea &da ) | ||
{ | ||
mDa.reset( new QgsDistanceArea( da ) ); | ||
} | ||
|
||
void QgsExpressionLineEdit::setLayer( QgsVectorLayer* layer ) | ||
{ | ||
mLayer = layer; | ||
} | ||
|
||
QString QgsExpressionLineEdit::expression() const | ||
{ | ||
if ( mLineEdit ) | ||
return mLineEdit->text(); | ||
else if ( mCodeEditor ) | ||
return mCodeEditor->text(); | ||
|
||
return QString(); | ||
} | ||
|
||
bool QgsExpressionLineEdit::isValidExpression( QString *expressionError ) const | ||
{ | ||
QString temp; | ||
return QgsExpression::isValid( expression(), &mExpressionContext, expressionError ? *expressionError : temp ); | ||
} | ||
|
||
void QgsExpressionLineEdit::registerExpressionContextGenerator( const QgsExpressionContextGenerator* generator ) | ||
{ | ||
mExpressionContextGenerator = generator; | ||
} | ||
|
||
void QgsExpressionLineEdit::setExpression( const QString& newExpression ) | ||
{ | ||
if ( mLineEdit ) | ||
mLineEdit->setText( newExpression ); | ||
else if ( mCodeEditor ) | ||
mCodeEditor->setText( newExpression ); | ||
} | ||
|
||
void QgsExpressionLineEdit::editExpression() | ||
{ | ||
QString currentExpression = expression(); | ||
|
||
QgsExpressionContext context = mExpressionContextGenerator ? mExpressionContextGenerator->createExpressionContext() : mExpressionContext; | ||
|
||
QgsExpressionBuilderDialog dlg( mLayer, currentExpression, this, "generic", context ); | ||
if ( !mDa.isNull() ) | ||
{ | ||
dlg.setGeomCalculator( *mDa ); | ||
} | ||
dlg.setWindowTitle( mExpressionDialogTitle ); | ||
|
||
if ( dlg.exec() ) | ||
{ | ||
QString newExpression = dlg.expressionText(); | ||
setExpression( newExpression ); | ||
} | ||
} | ||
|
||
void QgsExpressionLineEdit::expressionEdited() | ||
{ | ||
emit expressionChanged( expression() ); | ||
} | ||
|
||
void QgsExpressionLineEdit::expressionEdited( const QString& expression ) | ||
{ | ||
updateLineEditStyle( expression ); | ||
emit expressionChanged( expression ); | ||
} | ||
|
||
void QgsExpressionLineEdit::changeEvent( QEvent* event ) | ||
{ | ||
if ( event->type() == QEvent::EnabledChange ) | ||
{ | ||
updateLineEditStyle( expression() ); | ||
} | ||
} | ||
|
||
void QgsExpressionLineEdit::updateLineEditStyle( const QString& expression ) | ||
{ | ||
if ( !mLineEdit ) | ||
return; | ||
|
||
QPalette palette; | ||
if ( !isEnabled() ) | ||
{ | ||
palette.setColor( QPalette::Text, Qt::gray ); | ||
} | ||
else | ||
{ | ||
bool isValid = true; | ||
if ( !expression.isEmpty() ) | ||
{ | ||
isValid = isExpressionValid( expression ); | ||
} | ||
if ( !isValid ) | ||
{ | ||
palette.setColor( QPalette::Text, Qt::red ); | ||
} | ||
else | ||
{ | ||
palette.setColor( QPalette::Text, Qt::black ); | ||
} | ||
} | ||
mLineEdit->setPalette( palette ); | ||
} | ||
|
||
bool QgsExpressionLineEdit::isExpressionValid( const QString& expressionStr ) | ||
{ | ||
QgsExpression expression( expressionStr ); | ||
expression.prepare( &mExpressionContext ); | ||
return !expression.hasParserError(); | ||
} |
Oops, something went wrong.