QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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" ) != 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 
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 
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 
139 {
140  return d->expressionParams;
141 }
142 
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 
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 
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 
271 {
272  d.detach();
273  d->expressionParams.insert( key, param );
274 }
275 
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 
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.
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
#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.
void setUseExpression(bool use)
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)
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.
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
bool isNull() 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 isValid() const
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.
const QgsFields & pendingFields() const
Returns field list in the to-be-committed state.
QDomElement createElement(const QString &tagName)
Represents a vector layer which manages a vector based data sets.
int compare(const QString &other) const
virtual ~QgsDataDefined()
void setExpressionString(const QString &expr)
bool isActive() const
QStringList referencedColumns(QgsVectorLayer *layer)
Returns the columns referenced by the QgsDataDefined.
const T value(const Key &key) const