QGIS API Documentation  2.9.0-Master
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 
48 QgsDataDefined* QgsDataDefined::fromMap( const QgsStringMap &map, const QString &baseName )
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" ) != QString( "0" ) );
63  QString expression = map.value( QString( "%1expression" ).arg( prefix ) );
64  bool useExpression = ( map.value( QString( "%1useexpr" ).arg( prefix ), "1" ) != QString( "0" ) );
65  QString field = map.value( QString( "%1field" ).arg( prefix ), QString() );
66 
67  return new QgsDataDefined( active, useExpression, expression, field );
68 }
69 
70 QgsDataDefined::QgsDataDefined( const QString & string )
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->exprRefColumns.clear();
119 }
120 
122 {
123  return d->expressionString;
124 }
125 
126 void QgsDataDefined::setExpressionString( const QString &expr )
127 {
128  if ( expr == d->expressionString )
129  return;
130 
131  d.detach();
132 
133  d->expressionString = expr;
134  d->expressionPrepared = false;
135  d->exprRefColumns.clear();
136 }
137 
138 QMap<QString, QVariant> QgsDataDefined::expressionParams() const
139 {
140  return d->expressionParams;
141 }
142 
143 void QgsDataDefined::setExpressionParams( QMap<QString, QVariant> params )
144 {
145  d.detach();
146  d->expressionParams = params;
147 }
148 
150 {
151  if ( layer )
152  {
153  return prepareExpression( layer->pendingFields() );
154  }
155  else
156  {
157  //preparing expression without a layer set, so pass empty field list
158  QgsFields empty;
159  return prepareExpression( empty );
160  }
161 }
162 
164 {
165  if ( !d->useExpression || d->expressionString.isEmpty() )
166  {
167  return false;
168  }
169 
170  d.detach();
171  delete d->expression;
172  d->expression = new QgsExpression( d->expressionString );
173  if ( d->expression->hasParserError() )
174  {
175  QgsDebugMsg( "Parser error:" + d->expression->parserErrorString() );
176  return false;
177  }
178 
179  // setup expression parameters
180  QVariant scaleV = d->expressionParams.value( "scale" );
181  if ( scaleV.isValid() )
182  {
183  bool ok;
184  double scale = scaleV.toDouble( &ok );
185  if ( ok )
186  {
187  d->expression->setScale( scale );
188  }
189  }
190 
191  d->expression->prepare( fields );
192  d->exprRefColumns = d->expression->referencedColumns();
193 
194  if ( d->expression->hasEvalError() )
195  {
196  d->expressionPrepared = false;
197  QgsDebugMsg( "Prepare error:" + d->expression->evalErrorString() );
198  return false;
199  }
200 
201  d->expressionPrepared = true;
202 
203  return true;
204 }
205 
207 {
208  return d->expressionPrepared;
209 }
210 
212 {
213  //Ideally there should be a detach here, but that causes issues
214  //as detaching can create a new expression which will be unprepared
215  //TODO - revisit after QgsExpression is made implicitly shared
216  //d.detach();
217  return d->expression;
218 }
219 
221 {
222  if ( layer )
223  {
224  return referencedColumns( layer->pendingFields() );
225  }
226  else
227  {
228  return referencedColumns( );
229  }
230 }
231 
232 QStringList QgsDataDefined::referencedColumns( const QgsFields &fields )
233 {
234  if ( !d->exprRefColumns.isEmpty() )
235  {
236  return d->exprRefColumns;
237  }
238 
239  d.detach();
240  if ( d->useExpression )
241  {
242  if ( !d->expression || !d->expressionPrepared )
243  {
244  prepareExpression( fields );
245  }
246  }
247  else if ( !d->field.isEmpty() )
248  {
249  d->exprRefColumns << d->field;
250  }
251 
252  return d->exprRefColumns;
253 }
254 
255 QString QgsDataDefined::field() const
256 {
257  return d->field;
258 }
259 
260 void QgsDataDefined::setField( const QString &field )
261 {
262  if ( field == d->field )
263  return;
264 
265  d.detach();
266  d->field = field;
267  d->exprRefColumns.clear();
268 }
269 
270 void QgsDataDefined::insertExpressionParam( QString key, QVariant param )
271 {
272  d.detach();
273  d->expressionParams.insert( key, param );
274 }
275 
276 QgsStringMap QgsDataDefined::toMap( const QString &baseName ) const
277 {
278  QgsStringMap map;
279  QString prefix;
280  if ( !baseName.isEmpty() )
281  {
282  prefix.append( QString( "%1_dd_" ).arg( baseName ) );
283  }
284 
285  map.insert( QString( "%1active" ).arg( prefix ), ( d->active ? "1" : "0" ) );
286  map.insert( QString( "%1useexpr" ).arg( prefix ), ( d->useExpression ? "1" : "0" ) );
287  map.insert( QString( "%1expression" ).arg( prefix ), d->expressionString );
288  map.insert( QString( "%1field" ).arg( prefix ), d->field );
289 
290  return map;
291 }
292 
293 QDomElement QgsDataDefined::toXmlElement( QDomDocument &document, const QString& elementName ) const
294 {
295  QDomElement element = document.createElement( elementName );
296  element.setAttribute( "active", d->active ? "true" : "false" );
297  element.setAttribute( "useExpr", d->useExpression ? "true" : "false" );
298  element.setAttribute( "expr", d->expressionString );
299  element.setAttribute( "field", d->field );
300  return element;
301 }
302 
303 bool QgsDataDefined::setFromXmlElement( const QDomElement &element )
304 {
305  if ( element.isNull() )
306  {
307  return false;
308  }
309 
310  d.detach();
311  d->active = element.attribute( "active" ).compare( "true", Qt::CaseInsensitive ) == 0;
312  d->useExpression = element.attribute( "useExpr" ).compare( "true", Qt::CaseInsensitive ) == 0;
313  d->field = element.attribute( "field" );
314  setExpressionString( element.attribute( "expr" ) );
315  return true;
316 }
317 
318 bool QgsDataDefined::operator==( const QgsDataDefined &other ) const
319 {
320  return *( other.d ) == *d;
321 }
322 
323 bool QgsDataDefined::operator!=( const QgsDataDefined &other ) const
324 {
325  return !( *this == other );
326 }
327 
329 {
330  d.detach();
331  d = rhs.d;
332  return *this;
333 }
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:86
void setActive(bool active)
QgsDataDefined & operator=(QgsDataDefined const &rhs)
Assignment operator.
A container class for data source field mapping or expression.
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 field() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual QString dump() const =0
void insertExpressionParam(QString key, QVariant param)
QgsExpression * expression()
Container of fields for a vector layer.
Definition: qgsfield.h:173
QMap< QString, QVariant > expressionParams() const
QString expressionString() const
static QgsDataDefined * fromMap(const QgsStringMap &map, const QString &baseName=QString())
Creates a QgsDataDefined from a decoded QgsStringMap.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:438
void setUseExpression(bool use)
bool setFromXmlElement(const QDomElement &element)
Sets the properties of the data defined container from an XML element.
void setField(const QString &field)
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
QDomElement toXmlElement(QDomDocument &document, const QString &elementName) const
Returns a DOM element containing the properties of the data defined container.
void setExpressionParams(QMap< QString, QVariant > params)
bool operator==(const QgsDataDefined &other) const
bool isField() const
Checks whether an expression consists only of a single field reference.
bool useExpression() const
QgsDataDefined(bool active=false, bool useexpr=false, const QString &expr=QString(), const QString &field=QString())
Construct a new data defined object.
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 hasDefaultValues() const
Returns whether the data defined container is set to all the default values, ie, disabled, with empty expression and no assigned field.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
Represents a vector layer which manages a vector based data sets.
virtual ~QgsDataDefined()
void setExpressionString(const QString &expr)
bool isActive() const
QStringList referencedColumns(QgsVectorLayer *layer)
Returns the columns referenced by the QgsDataDefined.