QGIS API Documentation  2.99.0-Master (6a61179)
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 "qgsfields.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( QStringLiteral( "%1_dd_" ).arg( baseName ) );
54  }
55 
56  if ( !map.contains( QStringLiteral( "%1expression" ).arg( prefix ) ) )
57  {
58  //requires at least the expression value
59  return nullptr;
60  }
61 
62  bool active = ( map.value( QStringLiteral( "%1active" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
63  QString expression = map.value( QStringLiteral( "%1expression" ).arg( prefix ) );
64  bool useExpression = ( map.value( QStringLiteral( "%1useexpr" ).arg( prefix ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
65  QString field = map.value( QStringLiteral( "%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->expressionPrepared = false;
119  d->exprRefColumns.clear();
120 }
121 
123 {
124  return d->expressionString;
125 }
126 
127 void QgsDataDefined::setExpressionString( const QString &expr )
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 : QStringLiteral( "\"%1\"" ).arg( d->field );
143 }
144 
146 {
147  if ( !d->useExpression || d->expressionString.isEmpty() )
148  {
149  return false;
150  }
151 
152  d.detach();
153  delete d->expression;
154  d->expression = new QgsExpression( d->expressionString );
155  if ( d->expression->hasParserError() )
156  {
157  QgsDebugMsg( "Parser error:" + d->expression->parserErrorString() );
158  return false;
159  }
160 
161  d->expression->prepare( &context );
162  d->exprRefColumns = d->expression->referencedColumns();
163 
164  if ( d->expression->hasEvalError() )
165  {
166  d->expressionPrepared = false;
167  QgsDebugMsg( "Prepare error:" + d->expression->evalErrorString() );
168  return false;
169  }
170 
171  d->expressionPrepared = true;
172 
173  return true;
174 }
175 
177 {
178  return d->expressionPrepared;
179 }
180 
182 {
183  //Ideally there should be a detach here, but that causes issues
184  //as detaching can create a new expression which will be unprepared
185  //TODO - revisit after QgsExpression is made implicitly shared
186  //d.detach();
187  return d->expression;
188 }
189 
191 {
192  if ( !d->exprRefColumns.isEmpty() )
193  {
194  return d->exprRefColumns;
195  }
196 
197  d.detach();
198  if ( d->useExpression )
199  {
200  if ( !d->expression || !d->expressionPrepared )
201  {
202  prepareExpression( context );
203  }
204  }
205  else if ( !d->field.isEmpty() )
206  {
207  d->exprRefColumns << d->field;
208  }
209 
210  return d->exprRefColumns;
211 }
212 
213 QString QgsDataDefined::field() const
214 {
215  return d->field;
216 }
217 
218 void QgsDataDefined::setField( const QString &field )
219 {
220  if ( field == d->field )
221  return;
222 
223  d.detach();
224  d->useExpression = false;
225  d->field = field;
226  d->exprRefColumns.clear();
227 }
228 
229 QgsStringMap QgsDataDefined::toMap( const QString &baseName ) const
230 {
231  QgsStringMap map;
232  QString prefix;
233  if ( !baseName.isEmpty() )
234  {
235  prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
236  }
237 
238  map.insert( QStringLiteral( "%1active" ).arg( prefix ), ( d->active ? "1" : "0" ) );
239  map.insert( QStringLiteral( "%1useexpr" ).arg( prefix ), ( d->useExpression ? "1" : "0" ) );
240  map.insert( QStringLiteral( "%1expression" ).arg( prefix ), d->expressionString );
241  map.insert( QStringLiteral( "%1field" ).arg( prefix ), d->field );
242 
243  return map;
244 }
245 
246 QDomElement QgsDataDefined::toXmlElement( QDomDocument &document, const QString& elementName ) const
247 {
248  QDomElement element = document.createElement( elementName );
249  element.setAttribute( QStringLiteral( "active" ), d->active ? "true" : "false" );
250  element.setAttribute( QStringLiteral( "useExpr" ), d->useExpression ? "true" : "false" );
251  element.setAttribute( QStringLiteral( "expr" ), d->expressionString );
252  element.setAttribute( QStringLiteral( "field" ), d->field );
253  return element;
254 }
255 
256 bool QgsDataDefined::setFromXmlElement( const QDomElement &element )
257 {
258  if ( element.isNull() )
259  {
260  return false;
261  }
262 
263  d.detach();
264  d->active = element.attribute( QStringLiteral( "active" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
265  d->useExpression = element.attribute( QStringLiteral( "useExpr" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
266  d->field = element.attribute( QStringLiteral( "field" ) );
267  d->expressionString = element.attribute( QStringLiteral( "expr" ) );
268  d->expressionPrepared = false;
269  d->exprRefColumns.clear();
270  return true;
271 }
272 
273 bool QgsDataDefined::operator==( const QgsDataDefined &other ) const
274 {
275  return *( other.d ) == *d;
276 }
277 
278 bool QgsDataDefined::operator!=( const QgsDataDefined &other ) const
279 {
280  return !( *this == other );
281 }
282 
284 {
285  d.detach();
286  d = rhs.d;
287  return *this;
288 }
Class for parsing and evaluation of expressions (formerly called "search strings").
void setActive(bool active)
QgsDataDefined & operator=(QgsDataDefined const &rhs)
Assignment operator.
A container class for data source field mapping or expression.
bool expressionIsPrepared() const
Returns whether the data defined object&#39;s expression is prepared.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
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()
static QgsDataDefined * fromMap(const QgsStringMap &map, const QString &baseName=QString())
Creates a QgsDataDefined from a decoded QgsStringMap.
QgsStringMap toMap(const QString &baseName=QString()) const
Encodes the QgsDataDefined into a string map.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:328
bool useExpression() const
Returns if the field or the expression part is active.
QSet< QString > referencedColumns(const QgsExpressionContext &context=QgsExpressionContext())
Returns the columns referenced by the QgsDataDefined.
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 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...
QString expression() const
Return the original, unmodified expression string.
QString field() const
Get the field which this QgsDataDefined represents.
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.
bool prepareExpression(const QgsExpressionContext &context=QgsExpressionContext())
Prepares the expression using an expression context.
bool isField() const
Checks whether an expression consists only of a single field reference.
QString expressionOrField() const
Returns an expression which represents a single field if useExpression returns false, otherwise returns the current expression string.
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.
virtual ~QgsDataDefined()
void setExpressionString(const QString &expr)
Sets the expression for this QgsDataDefined.
bool isActive() const