QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 nullptr;
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 
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  d->expressionString = element.attribute( "expr" );
334  d->expressionPrepared = false;
335  d->exprRefColumns.clear();
336  return true;
337 }
338 
339 bool QgsDataDefined::operator==( const QgsDataDefined &other ) const
340 {
341  return *( other.d ) == *d;
342 }
343 
344 bool QgsDataDefined::operator!=( const QgsDataDefined &other ) const
345 {
346  return !( *this == other );
347 }
348 
350 {
351  d.detach();
352  d = rhs.d;
353  return *this;
354 }
Class for parsing and evaluation of expressions (formerly called "search strings").
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
bool expressionIsPrepared() const
Returns whether the data defined object&#39;s expression is prepared.
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
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.
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
QgsExpression * expression()
Container of fields for a vector layer.
Definition: qgsfield.h:252
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:187
QgsStringMap toMap(const QString &baseName=QString()) const
Encodes the QgsDataDefined into a string map.
bool useExpression() const
Returns if the field or the expression part is active.
QgsFields fields() const
Returns the list of fields of this layer.
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
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.
QString expressionString() const
Returns the expression string of this QgsDataDefined.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool isEmpty() const
QString expression() const
Return the original, unmodified expression string.
QString field() const
Get the field which this QgsDataDefined represents.
bool isNull() const
bool operator!=(const QgsDataDefined &other) 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 isField() const
Checks whether an expression consists only of a single field reference.
bool isValid() const
void insertExpressionParam(const QString &key, const QVariant &param)
QString expressionOrField() const
Returns an expression which represents a single field if useExpression returns false, otherwise returns the current expression string.
double toDouble(bool *ok) const
iterator insert(const Key &key, const T &value)
QDomElement createElement(const QString &tagName)
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.
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.
QMap< QString, QVariant > expressionParams() const
const T value(const Key &key) const