QGIS API Documentation  2.12.0-Lyon
qgsdatadefined.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdatadefined.cpp - Data defined container class
3  --------------------------------------
4  Date : 9-May-2013
5  Copyright : (C) 2013 by Larry Shaffer
6  Email : larrys at dakcarto 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 "qgsdatadefined.h"
17 #include "qgsdatadefined_p.h"
18 
19 #include "qgslogger.h"
20 #include "qgsexpression.h"
21 #include "qgsfield.h"
22 #include "qgsvectorlayer.h"
23 
25  bool useexpr,
26  const QString& expr,
27  const QString& field )
28 {
29  d = new QgsDataDefinedPrivate( active, useexpr, expr, field );
30 }
31 
33 {
34  bool active = bool( expression );
35  bool useExpression = expression && ! expression->isField();
36  d = new QgsDataDefinedPrivate( active,
37  useExpression,
38  useExpression ? expression->expression() : QString(),
39  !useExpression ? ( expression ? expression->expression() : QString() ) : QString() );
40 }
41 
43  : d( other.d )
44 {
45 
46 }
47 
49 {
50  QString prefix;
51  if ( !baseName.isEmpty() )
52  {
53  prefix.append( QString( "%1_dd_" ).arg( baseName ) );
54  }
55 
56  if ( !map.contains( QString( "%1expression" ).arg( prefix ) ) )
57  {
58  //requires at least the expression value
59  return 0;
60  }
61 
62  bool active = ( map.value( QString( "%1active" ).arg( prefix ), "1" ) != QLatin1String( "0" ) );
63  QString expression = map.value( QString( "%1expression" ).arg( prefix ) );
64  bool useExpression = ( map.value( QString( "%1useexpr" ).arg( prefix ), "1" ) != QLatin1String( "0" ) );
65  QString field = map.value( QString( "%1field" ).arg( prefix ), QString() );
66 
67  return new QgsDataDefined( active, useExpression, expression, field );
68 }
69 
71 {
72  QgsExpression expression( string );
73 
74  bool active = expression.rootNode();
75  bool useExpression = active && ! expression.isField();
76  d = new QgsDataDefinedPrivate( active,
77  useExpression,
78  useExpression ? expression.expression() : QString(),
79  expression.isField() ? expression.rootNode()->dump() : QString() );
80 }
81 
83 {
84 
85 }
86 
88 {
89  return ( !d->active && !d->useExpression && d->expressionString.isEmpty() && d->field.isEmpty() );
90 }
91 
93 {
94  return d->active;
95 }
96 
97 void QgsDataDefined::setActive( bool active )
98 {
99  if ( active == d->active )
100  return;
101 
102  d.detach();
103  d->active = active;
104 }
105 
107 {
108  return d->useExpression;
109 }
110 
112 {
113  if ( use == d->useExpression )
114  return;
115 
116  d.detach();
117  d->useExpression = use;
118  d->expressionPrepared = false;
119  d->exprRefColumns.clear();
120 }
121 
123 {
124  return d->expressionString;
125 }
126 
128 {
129  if ( expr == d->expressionString )
130  return;
131 
132  d.detach();
133 
134  d->useExpression = true;
135  d->expressionString = expr;
136  d->expressionPrepared = false;
137  d->exprRefColumns.clear();
138 }
139 
141 {
142  return d->useExpression ? d->expressionString : QString( "\"%1\"" ).arg( d->field );
143 }
144 
146 {
147  return d->expressionParams;
148 }
149 
151 {
152  d.detach();
153  d->expressionParams = params;
154 }
155 
157 {
158  if ( layer )
159  {
161  }
162  else
163  {
164  //preparing expression without a layer set, so pass empty context
165  QgsExpressionContext empty;
166  return prepareExpression( empty );
167  }
168 }
169 
171 {
173 }
174 
176 {
177  if ( !d->useExpression || d->expressionString.isEmpty() )
178  {
179  return false;
180  }
181 
182  d.detach();
183  delete d->expression;
184  d->expression = new QgsExpression( d->expressionString );
185  if ( d->expression->hasParserError() )
186  {
187  QgsDebugMsg( "Parser error:" + d->expression->parserErrorString() );
188  return false;
189  }
190 
191  // setup expression parameters
192  QVariant scaleV = d->expressionParams.value( "scale" );
193  if ( scaleV.isValid() )
194  {
195  bool ok;
196  double scale = scaleV.toDouble( &ok );
197  if ( ok )
198  {
199  d->expression->setScale( scale );
200  }
201  }
202 
203  d->expression->prepare( &context );
204  d->exprRefColumns = d->expression->referencedColumns();
205 
206  if ( d->expression->hasEvalError() )
207  {
208  d->expressionPrepared = false;
209  QgsDebugMsg( "Prepare error:" + d->expression->evalErrorString() );
210  return false;
211  }
212 
213  d->expressionPrepared = true;
214 
215  return true;
216 }
217 
219 {
220  return d->expressionPrepared;
221 }
222 
224 {
225  //Ideally there should be a detach here, but that causes issues
226  //as detaching can create a new expression which will be unprepared
227  //TODO - revisit after QgsExpression is made implicitly shared
228  //d.detach();
229  return d->expression;
230 }
231 
233 {
234  if ( layer )
235  {
237  }
238  else
239  {
240  QgsExpressionContext empty;
241  return referencedColumns( empty );
242  }
243 }
244 
246 {
248 }
249 
251 {
252  if ( !d->exprRefColumns.isEmpty() )
253  {
254  return d->exprRefColumns;
255  }
256 
257  d.detach();
258  if ( d->useExpression )
259  {
260  if ( !d->expression || !d->expressionPrepared )
261  {
262  prepareExpression( context );
263  }
264  }
265  else if ( !d->field.isEmpty() )
266  {
267  d->exprRefColumns << d->field;
268  }
269 
270  return d->exprRefColumns;
271 }
272 
274 {
275  return d->field;
276 }
277 
278 void QgsDataDefined::setField( const QString &field )
279 {
280  if ( field == d->field )
281  return;
282 
283  d.detach();
284  d->useExpression = false;
285  d->field = field;
286  d->exprRefColumns.clear();
287 }
288 
290 {
291  d.detach();
292  d->expressionParams.insert( key, param );
293 }
294 
296 {
297  QgsStringMap map;
298  QString prefix;
299  if ( !baseName.isEmpty() )
300  {
301  prefix.append( QString( "%1_dd_" ).arg( baseName ) );
302  }
303 
304  map.insert( QString( "%1active" ).arg( prefix ), ( d->active ? "1" : "0" ) );
305  map.insert( QString( "%1useexpr" ).arg( prefix ), ( d->useExpression ? "1" : "0" ) );
306  map.insert( QString( "%1expression" ).arg( prefix ), d->expressionString );
307  map.insert( QString( "%1field" ).arg( prefix ), d->field );
308 
309  return map;
310 }
311 
312 QDomElement QgsDataDefined::toXmlElement( QDomDocument &document, const QString& elementName ) const
313 {
314  QDomElement element = document.createElement( elementName );
315  element.setAttribute( "active", d->active ? "true" : "false" );
316  element.setAttribute( "useExpr", d->useExpression ? "true" : "false" );
317  element.setAttribute( "expr", d->expressionString );
318  element.setAttribute( "field", d->field );
319  return element;
320 }
321 
323 {
324  if ( element.isNull() )
325  {
326  return false;
327  }
328 
329  d.detach();
330  d->active = element.attribute( "active" ).compare( "true", Qt::CaseInsensitive ) == 0;
331  d->useExpression = element.attribute( "useExpr" ).compare( "true", Qt::CaseInsensitive ) == 0;
332  d->field = element.attribute( "field" );
333  setExpressionString( element.attribute( "expr" ) );
334  return true;
335 }
336 
337 bool QgsDataDefined::operator==( const QgsDataDefined &other ) const
338 {
339  return *( other.d ) == *d;
340 }
341 
342 bool QgsDataDefined::operator!=( const QgsDataDefined &other ) const
343 {
344  return !( *this == other );
345 }
346 
348 {
349  d.detach();
350  d = rhs.d;
351  return *this;
352 }
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:92
void setExpressionParams(const QMap< QString, QVariant > &params)
void setActive(bool active)
QgsDataDefined & operator=(QgsDataDefined const &rhs)
Assignment operator.
QString & append(QChar ch)
A container class for data source field mapping or expression.
bool contains(const Key &key) const
QgsStringMap toMap(const QString &baseName=QString()) const
Encodes the QgsDataDefined into a string map.
bool operator!=(const QgsDataDefined &other) const
const QString expression() const
Alias for dump()
QString attribute(const QString &name, const QString &defValue) const
QString field() const
Get the field which this QgsDataDefined represents.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsFields fields() const
Returns the list of fields of this layer.
static QgsExpressionContext createFeatureBasedContext(const QgsFeature &feature, const QgsFields &fields)
Helper function for creating an expression context which contains just a feature and fields collectio...
virtual QString dump() const =0
Abstract virtual dump method.
QgsExpression * expression()
Container of fields for a vector layer.
Definition: qgsfield.h:177
QMap< QString, QVariant > expressionParams() const
QString expressionString() const
Returns the expression string of this QgsDataDefined.
static QgsDataDefined * fromMap(const QgsStringMap &map, const QString &baseName=QString())
Creates a QgsDataDefined from a decoded QgsStringMap.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:176
QString expressionOrField() const
Returns an expression which represents a single field if useExpression returns false, otherwise returns the current expression string.
void setUseExpression(bool use)
Controls if the field or the expression part is active.
bool setFromXmlElement(const QDomElement &element)
Sets the properties of the data defined container from an XML element.
void setAttribute(const QString &name, const QString &value)
void setField(const QString &field)
Set the field name which this QgsDataDefined represents.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
bool isEmpty() const
QDomElement toXmlElement(QDomDocument &document, const QString &elementName) const
Returns a DOM element containing the properties of the data defined container.
bool operator==(const QgsDataDefined &other) const
bool isField() const
Checks whether an expression consists only of a single field reference.
bool useExpression() const
Returns if the field or the expression part is active.
bool isNull() const
QgsDataDefined(bool active=false, bool useexpr=false, const QString &expr=QString(), const QString &field=QString())
Construct a new data defined object.
Q_DECL_DEPRECATED bool prepareExpression(QgsVectorLayer *layer)
Prepares the expression using a vector layer.
bool expressionIsPrepared() const
Returns whether the data defined object's expression is prepared.
bool isValid() const
void insertExpressionParam(const QString &key, const QVariant &param)
double toDouble(bool *ok) const
iterator insert(const Key &key, const T &value)
bool hasDefaultValues() const
Returns whether the data defined container is set to all the default values, ie, disabled, with empty expression and no assigned field.
QDomElement createElement(const QString &tagName)
Represents a vector layer which manages a vector based data sets.
int compare(const QString &other) const
virtual ~QgsDataDefined()
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void setExpressionString(const QString &expr)
Sets the expression for this QgsDataDefined.
bool isActive() const
Q_DECL_DEPRECATED QStringList referencedColumns(QgsVectorLayer *layer)
Returns the columns referenced by the QgsDataDefined.
const T value(const Key &key) const