QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsfieldexpressionwidget.cpp
Go to the documentation of this file.
1 
2 /***************************************************************************
3  qgsfieldexpressionwidget.cpp
4  --------------------------------------
5  Date : 01.04.2014
6  Copyright : (C) 2014 Denis Rouzaud
7  Email : denis.rouzaud@gmail.com
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16 
17 #include <QHBoxLayout>
18 
19 #include "qgsapplication.h"
22 #include "qgsfieldproxymodel.h"
23 #include "qgsdistancearea.h"
24 
26  : QWidget( parent )
27  , mExpressionDialogTitle( tr( "Expression dialog" ) )
28  , mDa( 0 )
29 {
30  QHBoxLayout* layout = new QHBoxLayout( this );
31  layout->setContentsMargins( 0, 0, 0, 0 );
32  mCombo = new QComboBox( this );
33  mCombo->setEditable( true );
34  mCombo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
35  int width = mCombo->minimumSizeHint().width();
36  mCombo->setMinimumWidth( width );
37  mFieldProxyModel = new QgsFieldProxyModel( mCombo );
38  mFieldProxyModel->sourceFieldModel()->setAllowExpression( true );
39  mCombo->setModel( mFieldProxyModel );
40 
41  mButton = new QToolButton( this );
42  mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
43  mButton->setIcon( QgsApplication::getThemeIcon( "/mIconExpression.svg" ) );
44 
45  layout->addWidget( mCombo );
46  layout->addWidget( mButton );
47 
48  // give focus to the combo
49  // hence if the widget is used as a delegate
50  // it will allow pressing on the expression dialog button
51  setFocusProxy( mCombo );
52 
53  connect( mCombo->lineEdit(), SIGNAL( textEdited( QString ) ), this, SLOT( expressionEdited( QString ) ) );
54  connect( mCombo->lineEdit(), SIGNAL( editingFinished() ), this, SLOT( expressionEditingFinished() ) );
55  connect( mCombo, SIGNAL( activated( int ) ), this, SLOT( currentFieldChanged() ) );
56  connect( mButton, SIGNAL( clicked() ), this, SLOT( editExpression() ) );
57  // NW TODO - Fix in 2.6
58 // connect( mCombo->lineEdit(), SIGNAL( returnPressed() ), this, SIGNAL( returnPressed() ) );
59 }
60 
62 {
63  mExpressionDialogTitle = title;
64 }
65 
66 void QgsFieldExpressionWidget::setFilters( QgsFieldProxyModel::Filters filters )
67 {
68  mFieldProxyModel->setFilters( filters );
69 }
70 
72 {
73  QHBoxLayout* layout = dynamic_cast<QHBoxLayout*>( this->layout() );
74  if ( !layout )
75  return;
76 
77  if ( isLeft )
78  {
79  QLayoutItem* item = layout->takeAt( 1 );
80  layout->insertWidget( 0, item->widget() );
81  }
82  else
83  layout->addWidget( mCombo );
84 }
85 
87 {
89 }
90 
92 {
93  return mCombo->currentText();
94 }
95 
97 {
98  QString temp;
99  QgsVectorLayer* vl = layer();
100  return QgsExpression::isValid( currentText(), vl ? vl->pendingFields() : QgsFields(), expressionError ? *expressionError : temp );
101 }
102 
104 {
105  return !mFieldProxyModel->sourceFieldModel()->isField( currentText() );
106 }
107 
108 QString QgsFieldExpressionWidget::currentField( bool *isExpression, bool *isValid ) const
109 {
110  QString text = currentText();
111  if ( isValid )
112  {
113  *isValid = isValidExpression();
114  }
115  if ( isExpression )
116  {
117  *isExpression = this->isExpression();
118  }
119  return text;
120 }
121 
123 {
124  return mFieldProxyModel->sourceFieldModel()->layer();
125 }
126 
128 {
129  QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( layer );
130  if ( vl )
131  {
132  setLayer( vl );
133  }
134 }
135 
137 {
138  mFieldProxyModel->sourceFieldModel()->setLayer( layer );
139 }
140 
142 {
143  if ( fieldName.isEmpty() )
144  return;
145 
146  QModelIndex idx = mFieldProxyModel->sourceFieldModel()->indexFromName( fieldName );
147  if ( !idx.isValid() )
148  {
149  // try to remove quotes and white spaces
150  QString simpleFieldName = fieldName.trimmed();
151  if ( simpleFieldName.startsWith( '"' ) && simpleFieldName.endsWith( '"' ) )
152  {
153  simpleFieldName.remove( 0, 1 ).chop( 1 );
154  idx = mFieldProxyModel->sourceFieldModel()->indexFromName( simpleFieldName );
155  }
156 
157  if ( !idx.isValid() )
158  {
159  // new expression
160  mFieldProxyModel->sourceFieldModel()->setExpression( fieldName );
161  idx = mFieldProxyModel->sourceFieldModel()->indexFromName( fieldName );
162  }
163  }
164  QModelIndex proxyIndex = mFieldProxyModel->mapFromSource( idx );
165  mCombo->setCurrentIndex( proxyIndex.row() );
167 }
168 
170 {
171  QString currentExpression = currentText();
172  QgsVectorLayer* vl = layer();
173 
174  QgsExpressionBuilderDialog dlg( vl, currentExpression );
175  if ( !mDa.isNull() )
176  {
177  dlg.setGeomCalculator( *mDa );
178  }
179  dlg.setWindowTitle( mExpressionDialogTitle );
180 
181  if ( dlg.exec() )
182  {
183  QString newExpression = dlg.expressionText();
184  setField( newExpression );
185  }
186 }
187 
189 {
190  updateLineEditStyle( expression );
191  emit fieldChanged( expression, isValidExpression() );
192 }
193 
195 {
196  QgsDebugMsg( "Editing finished" );
197  const QString expression = mCombo->lineEdit()->text();
198  mFieldProxyModel->sourceFieldModel()->setExpression( expression );
199  QModelIndex idx = mFieldProxyModel->sourceFieldModel()->indexFromName( expression );
200  QModelIndex proxyIndex = mFieldProxyModel->mapFromSource( idx );
201  mCombo->setCurrentIndex( proxyIndex.row() );
203 }
204 
206 {
207  if ( event->type() == QEvent::EnabledChange )
208  {
210  }
211 }
212 
214 {
216 
217  bool isExpression, isValid;
218  QString fieldName = currentField( &isExpression, &isValid );
219 
220  // display tooltip if widget is shorter than expression
221  QFontMetrics metrics( mCombo->lineEdit()->font() );
222  if ( metrics.width( fieldName ) > mCombo->lineEdit()->width() )
223  {
224  mCombo->setToolTip( fieldName );
225  }
226  else
227  {
228  mCombo->setToolTip( "" );
229  }
230 
231  emit fieldChanged( fieldName );
232  emit fieldChanged( fieldName, isValid );
233 }
234 
236 {
238  if ( !isEnabled() )
239  {
240  palette.setColor( QPalette::Text, Qt::gray );
241  }
242  else
243  {
244  bool isExpression, isValid;
245  if ( !expression.isEmpty() )
246  {
247  isExpression = true;
248  isValid = isExpressionValid( expression );
249  }
250  else
251  {
252  currentField( &isExpression, &isValid );
253  }
254  QFont font = mCombo->lineEdit()->font();
255  font.setItalic( isExpression );
256  mCombo->lineEdit()->setFont( font );
257 
258  if ( isExpression && !isValid )
259  {
260  palette.setColor( QPalette::Text, Qt::red );
261  }
262  else
263  {
264  palette.setColor( QPalette::Text, Qt::black );
265  }
266  }
267  mCombo->lineEdit()->setPalette( palette );
268 }
269 
271 {
272  QgsVectorLayer* vl = layer();
273 
274  QgsExpression expression( expressionStr );
275  expression.prepare( vl ? vl->pendingFields() : QgsFields() );
276  return !expression.hasParserError();
277 }
QLayout * layout() const
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:86
Base class for all map layer types.
Definition: qgsmaplayer.h:49
Type type() const
void setContentsMargins(int left, int top, int right, int bottom)
const QPalette & palette() const
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:93
QgsFieldModel * sourceFieldModel()
sourceFieldModel returns the QgsFieldModel used in this QSortFilterProxyModel
int width() const
void setColor(ColorGroup group, ColorRole role, const QColor &color)
void changeEvent(QEvent *event) override
bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
bool isValidExpression(QString *expressionError=0) const
Return true if the current expression is valid.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
virtual QWidget * widget()
void setMinimumWidth(int minw)
bool isExpressionValid(const QString expressionStr)
void setExpression(const QString &expression)
setExpression sets a single expression to be added after the fields at the end of the model ...
int exec()
Container of fields for a vector layer.
Definition: qgsfield.h:173
QString currentText() const
Return the current text that is set in the expression area.
void editExpression()
open the expression dialog to edit the current or add a new expression
void setLayer(QgsVectorLayer *layer)
set the layer used to display the fields and expression
QString & remove(int position, int n)
void setEditable(bool editable)
void chop(int n)
virtual QLayoutItem * takeAt(int index)
static bool isValid(const QString &text, const QgsFields &fields, QString &errorMessage)
void setIcon(const QIcon &icon)
QgsVectorLayer * layer()
returns the currently used layer
Definition: qgsfieldmodel.h:68
bool isField(const QString &expression)
int width() const
bool isValid() const
bool isEnabled() const
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
The QgsFieldProxyModel class provides an easy to use model to display the list of fields of a layer...
virtual QSize minimumSizeHint() const
QgsFieldProxyModel * setFilters(Filters filters)
setFilters set flags that affect how fields are filtered
void setExpressionDialogTitle(QString title)
define the title used in the expression dialog
void setFocusProxy(QWidget *w)
bool isEmpty() const
QString trimmed() const
void setLayer(QgsVectorLayer *layer)
set the layer of whch fields are displayed
int row() const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
void setGeomCalculator(const QgsDistanceArea &da)
Sets geometry calculator used in distance/area calculations.
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
void setAllowExpression(bool allowExpression)
returns the currently used layer
void setGeomCalculator(const QgsDistanceArea &da)
set the geometry calculator used in the expression dialog
void expressionEdited(const QString expression)
when expression is edited by the user in the line edit, it will be checked for validity ...
void setSizePolicy(QSizePolicy)
QgsVectorLayer * layer() const
Returns the currently used layer.
void updateLineEditStyle(const QString expression=QString())
updateLineEditStyle will re-style (color/font) the line edit depending on content and status ...
void setItalic(bool enable)
General purpose distance and area calculator.
QLineEdit * lineEdit() const
void expressionEditingFinished()
when expression has been edited (finished) it will be added to the model
QString currentField(bool *isExpression=0, bool *isValid=0) const
currentField returns the currently selected field or expression if allowed
void setFilters(QgsFieldProxyModel::Filters filters)
setFilters allows fitering according to the type of field
void setModel(QAbstractItemModel *model)
virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const
void setWindowTitle(const QString &)
void setField(const QString &fieldName)
sets the current field or expression in the widget
void setCurrentIndex(int index)
void insertWidget(int index, QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
const QgsFields & pendingFields() const
Returns field list in the to-be-committed state.
void setToolTip(const QString &)
bool isNull() const
QModelIndex indexFromName(const QString &fieldName)
return the index corresponding to a given fieldName
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Represents a vector layer which manages a vector based data sets.
A generic dialog for building expression strings.
QgsFieldExpressionWidget(QWidget *parent=0)
QgsFieldExpressionWidget creates a widget with a combo box to display the fields and expression and a...
void fieldChanged(QString fieldName)
the signal is emitted when the currently selected field changes
#define tr(sourceText)