QGIS API Documentation  2.99.0-Master (0a63d1f)
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 
71 {}
72 
73 QgsDataDefined::QgsDataDefined( const QString & string )
74 {
75  QgsExpression expression( string );
76 
77  bool active = expression.rootNode();
78  bool useExpression = active && ! expression.isField();
79  d = new QgsDataDefinedPrivate( active,
80  useExpression,
81  useExpression ? expression.expression() : QString(),
82  expression.isField() ? expression.rootNode()->dump() : QString() );
83 }
84 
86 {
87  return ( !d->active && !d->useExpression && d->expressionString.isEmpty() && d->field.isEmpty() );
88 }
89 
91 {
92  return d->active;
93 }
94 
95 void QgsDataDefined::setActive( bool active )
96 {
97  if ( active == d->active )
98  return;
99 
100  d.detach();
101  d->active = active;
102 }
103 
105 {
106  return d->useExpression;
107 }
108 
110 {
111  if ( use == d->useExpression )
112  return;
113 
114  d.detach();
115  d->useExpression = use;
116  d->expressionPrepared = false;
117  d->exprRefColumns.clear();
118 }
119 
121 {
122  return d->expressionString;
123 }
124 
125 void QgsDataDefined::setExpressionString( const QString &expr )
126 {
127  if ( expr == d->expressionString )
128  return;
129 
130  d.detach();
131 
132  d->useExpression = true;
133  d->expressionString = expr;
134  d->expressionPrepared = false;
135  d->exprRefColumns.clear();
136 }
137 
139 {
140  return d->useExpression ? d->expressionString : QStringLiteral( "\"%1\"" ).arg( d->field );
141 }
142 
144 {
145  if ( !d->useExpression || d->expressionString.isEmpty() )
146  {
147  return false;
148  }
149 
150  d.detach();
151  delete d->expression;
152  d->expression = new QgsExpression( d->expressionString );
153  if ( d->expression->hasParserError() )
154  {
155  QgsDebugMsg( "Parser error:" + d->expression->parserErrorString() );
156  return false;
157  }
158 
159  d->expression->prepare( &context );
160  d->exprRefColumns = d->expression->referencedColumns();
161 
162  if ( d->expression->hasEvalError() )
163  {
164  d->expressionPrepared = false;
165  QgsDebugMsg( "Prepare error:" + d->expression->evalErrorString() );
166  return false;
167  }
168 
169  d->expressionPrepared = true;
170 
171  return true;
172 }
173 
175 {
176  return d->expressionPrepared;
177 }
178 
180 {
181  //Ideally there should be a detach here, but that causes issues
182  //as detaching can create a new expression which will be unprepared
183  //TODO - revisit after QgsExpression is made implicitly shared
184  //d.detach();
185  return d->expression;
186 }
187 
189 {
190  if ( !d->exprRefColumns.isEmpty() )
191  {
192  return d->exprRefColumns;
193  }
194 
195  d.detach();
196  if ( d->useExpression )
197  {
198  if ( !d->expression || !d->expressionPrepared )
199  {
200  prepareExpression( context );
201  }
202  }
203  else if ( !d->field.isEmpty() )
204  {
205  d->exprRefColumns << d->field;
206  }
207 
208  return d->exprRefColumns;
209 }
210 
211 QString QgsDataDefined::field() const
212 {
213  return d->field;
214 }
215 
216 void QgsDataDefined::setField( const QString &field )
217 {
218  if ( field == d->field )
219  return;
220 
221  d.detach();
222  d->useExpression = false;
223  d->field = field;
224  d->exprRefColumns.clear();
225 }
226 
227 QgsStringMap QgsDataDefined::toMap( const QString &baseName ) const
228 {
229  QgsStringMap map;
230  QString prefix;
231  if ( !baseName.isEmpty() )
232  {
233  prefix.append( QStringLiteral( "%1_dd_" ).arg( baseName ) );
234  }
235 
236  map.insert( QStringLiteral( "%1active" ).arg( prefix ), ( d->active ? "1" : "0" ) );
237  map.insert( QStringLiteral( "%1useexpr" ).arg( prefix ), ( d->useExpression ? "1" : "0" ) );
238  map.insert( QStringLiteral( "%1expression" ).arg( prefix ), d->expressionString );
239  map.insert( QStringLiteral( "%1field" ).arg( prefix ), d->field );
240 
241  return map;
242 }
243 
244 QDomElement QgsDataDefined::toXmlElement( QDomDocument &document, const QString& elementName ) const
245 {
246  QDomElement element = document.createElement( elementName );
247  element.setAttribute( QStringLiteral( "active" ), d->active ? "true" : "false" );
248  element.setAttribute( QStringLiteral( "useExpr" ), d->useExpression ? "true" : "false" );
249  element.setAttribute( QStringLiteral( "expr" ), d->expressionString );
250  element.setAttribute( QStringLiteral( "field" ), d->field );
251  return element;
252 }
253 
254 bool QgsDataDefined::setFromXmlElement( const QDomElement &element )
255 {
256  if ( element.isNull() )
257  {
258  return false;
259  }
260 
261  d.detach();
262  d->active = element.attribute( QStringLiteral( "active" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
263  d->useExpression = element.attribute( QStringLiteral( "useExpr" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
264  d->field = element.attribute( QStringLiteral( "field" ) );
265  d->expressionString = element.attribute( QStringLiteral( "expr" ) );
266  d->expressionPrepared = false;
267  d->exprRefColumns.clear();
268  return true;
269 }
270 
271 bool QgsDataDefined::operator==( const QgsDataDefined &other ) const
272 {
273  return *( other.d ) == *d;
274 }
275 
276 bool QgsDataDefined::operator!=( const QgsDataDefined &other ) const
277 {
278  return !( *this == other );
279 }
280 
282 {
283  d.detach();
284  d = rhs.d;
285  return *this;
286 }
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:36
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:325
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