QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsconditionalstyle.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsconditionalstyle.cpp
3  ---------------------
4  begin : August 2015
5  copyright : (C) 2015 by Nathan Woodrow
6  email : woodrow dot nathan at gmail 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 #include <QPainter>
16 
17 #include "qgsconditionalstyle.h"
18 #include "qgsexpression.h"
19 #include "qgsfontutils.h"
20 #include "qgssymbollayerv2utils.h"
21 #include "qgsmarkersymbollayerv2.h"
22 
24  : mRowStyles( QList<QgsConditionalStyle>() )
25 {}
26 
28 {
29  return mRowStyles;
30 }
31 
33 {
34  mRowStyles = styles;
35 }
36 
38 {
39  mFieldStyles.insert( fieldName, styles );
40 }
41 
43 {
44  if ( mFieldStyles.contains( fieldName ) )
45  {
46  return mFieldStyles[fieldName];
47  }
49 }
50 
52 {
53  QDomElement stylesel = doc.createElement( "conditionalstyles" );
54  QDomElement rowel = doc.createElement( "rowstyles" );
55  Q_FOREACH ( const QgsConditionalStyle& style, mRowStyles )
56  {
57  style.writeXml( rowel, doc );
58  }
59 
60  stylesel.appendChild( rowel );
61 
62  QDomElement fieldsel = doc.createElement( "fieldstyles" );
63  QHash<QString, QgsConditionalStyles>::const_iterator it = mFieldStyles.constBegin();
64  for ( ; it != mFieldStyles.constEnd(); ++it )
65  {
66  QDomElement fieldel = doc.createElement( "fieldstyle" );
67  fieldel.setAttribute( "fieldname", it.key() );
68  QgsConditionalStyles styles = it.value();
69  Q_FOREACH ( const QgsConditionalStyle& style, styles )
70  {
71  style.writeXml( fieldel, doc );
72  }
73  fieldsel.appendChild( fieldel );
74  }
75 
76  stylesel.appendChild( fieldsel );
77 
78  node.appendChild( stylesel );
79  return true;
80 }
81 
83 {
84  QDomElement condel = node.firstChildElement( "conditionalstyles" );
85  mRowStyles.clear();
86  mFieldStyles.clear();
87  QDomElement rowstylesel = condel.firstChildElement( "rowstyles" );
88  QDomNodeList nodelist = rowstylesel.toElement().elementsByTagName( "style" );
89  for ( int i = 0;i < nodelist.count(); i++ )
90  {
91  QDomElement styleElm = nodelist.at( i ).toElement();
93  style.readXml( styleElm );
94  mRowStyles.append( style );
95  }
96 
97  QDomElement fieldstylesel = condel.firstChildElement( "fieldstyles" );
98  nodelist = fieldstylesel.toElement().elementsByTagName( "fieldstyle" );
100  for ( int i = 0;i < nodelist.count(); i++ )
101  {
102  styles.clear();
103  QDomElement fieldel = nodelist.at( i ).toElement();
104  QString fieldName = fieldel.attribute( "fieldname" );
105  QDomNodeList stylenodelist = fieldel.toElement().elementsByTagName( "style" );
106  styles.reserve( stylenodelist.count() );
107  for ( int i = 0;i < stylenodelist.count(); i++ )
108  {
109  QDomElement styleElm = stylenodelist.at( i ).toElement();
111  style.readXml( styleElm );
112  styles.append( style );
113  }
114  mFieldStyles.insert( fieldName, styles );
115  }
116 
117  return true;
118 }
119 
121  : mValid( false )
122  , mSymbol( nullptr )
123  , mBackColor( QColor( 0, 0, 0, 0 ) )
124  , mTextColor( QColor( 0, 0, 0, 0 ) )
125 {}
126 
128  : mValid( false )
129  , mSymbol( nullptr )
130  , mBackColor( QColor( 0, 0, 0, 0 ) )
131  , mTextColor( QColor( 0, 0, 0, 0 ) )
132 {
133  setRule( rule );
134 }
135 
137  : mValid( other.mValid )
138  , mName( other.mName )
139  , mRule( other.mRule )
140  , mFont( other.mFont )
141  , mBackColor( other.mBackColor )
142  , mTextColor( other.mTextColor )
143  , mIcon( other.mIcon )
144 {
145  if ( other.mSymbol.data() )
146  mSymbol.reset( other.mSymbol->clone() );
147 }
148 
150 {
151  mValid = other.mValid;
152  mRule = other.mRule;
153  mFont = other.mFont;
154  mBackColor = other.mBackColor;
155  mTextColor = other.mTextColor;
156  mIcon = other.mIcon;
157  mName = other.mName;
158  if ( other.mSymbol.data() )
159  {
160  mSymbol.reset( other.mSymbol->clone() );
161  }
162  else
163  {
164  mSymbol.reset();
165  }
166  return ( *this );
167 }
168 
170 {
171 }
172 
174 {
175  if ( name().isEmpty() )
176  return rule();
177  else
178  return QString( "%1 \n%2" ).arg( name(), rule() );
179 }
180 
182 {
183  mValid = true;
184  if ( value )
185  {
186  mSymbol.reset( value->clone() );
187  mIcon = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol.data(), QSize( 16, 16 ) );
188  }
189  else
190  {
191  mSymbol.reset();
192  }
193 }
194 
195 bool QgsConditionalStyle::matches( const QVariant& value, QgsExpressionContext& context ) const
196 {
197  QgsExpression exp( mRule );
198  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QString( "value" ), value, true ) );
199  return exp.evaluate( &context ).toBool();
200 }
201 
203 {
204  QPixmap pixmap( 64, 32 );
205  pixmap.fill( Qt::transparent );
206 
207  QPainter painter( &pixmap );
208 
209  if ( validBackgroundColor() )
210  painter.setBrush( mBackColor );
211 
212  QRect rect = QRect( 0, 0, 64, 32 );
213  painter.setPen( Qt::NoPen );
214  painter.drawRect( rect );
215  painter.drawPixmap( 8, 8, icon() );
216 
217  if ( validTextColor() )
218  painter.setPen( mTextColor );
219  else
220  painter.setPen( Qt::black );
221 
222  painter.setRenderHint( QPainter::Antialiasing );
223  painter.setRenderHint( QPainter::HighQualityAntialiasing );
224  painter.setFont( font() );
225  rect = QRect( 32, 0, 32, 32 );
226  painter.drawText( rect, Qt::AlignCenter, "abc\n123" );
227  painter.end();
228  return pixmap;
229 }
230 
232 {
233  return ( backgroundColor().isValid() && backgroundColor().alpha() != 0 );
234 }
235 
237 {
238  return ( textColor().isValid() && textColor().alpha() != 0 );
239 }
240 
242 {
243  QList<QgsConditionalStyle> matchingstyles;
244  Q_FOREACH ( const QgsConditionalStyle& style, styles )
245  {
246  if ( style.matches( value, context ) )
247  matchingstyles.append( style );
248  }
249  return matchingstyles;
250 }
251 
253 {
254  Q_FOREACH ( const QgsConditionalStyle& style, styles )
255  {
256  if ( style.matches( value, context ) )
257  return style;
258  }
259  return QgsConditionalStyle();
260 }
261 
263 {
264  QgsConditionalStyle style;
265  Q_FOREACH ( const QgsConditionalStyle& s, styles )
266  {
267  style.setFont( s.font() );
268  if ( s.backgroundColor().isValid() && s.backgroundColor().alpha() != 0 )
269  style.setBackgroundColor( s.backgroundColor() );
270  if ( s.textColor().isValid() && s.textColor().alpha() != 0 )
271  style.setTextColor( s.textColor() );
272  if ( s.symbol() )
273  style.setSymbol( s.symbol() );
274  }
275  return style;
276 }
277 
279 {
280  QDomElement stylesel = doc.createElement( "style" );
281  stylesel.setAttribute( "rule", mRule );
282  stylesel.setAttribute( "name", mName );
283  stylesel.setAttribute( "background_color", mBackColor.name() );
284  stylesel.setAttribute( "background_color_alpha", mBackColor.alpha() );
285  stylesel.setAttribute( "text_color", mTextColor.name() );
286  stylesel.setAttribute( "text_color_alpha", mTextColor.alpha() );
287  QDomElement labelFontElem = QgsFontUtils::toXmlElement( mFont, doc, "font" );
288  stylesel.appendChild( labelFontElem );
289  if ( ! mSymbol.isNull() )
290  {
291  QDomElement symbolElm = QgsSymbolLayerV2Utils::saveSymbol( "icon", mSymbol.data(), doc );
292  stylesel.appendChild( symbolElm );
293  }
294  node.appendChild( stylesel );
295  return true;
296 }
297 
299 {
300  QDomElement styleElm = node.toElement();
301  setRule( styleElm.attribute( "rule" ) );
302  setName( styleElm.attribute( "name" ) );
303  QColor bColor = QColor( styleElm.attribute( "background_color" ) );
304  if ( styleElm.hasAttribute( "background_color_alpha" ) )
305  {
306  bColor.setAlpha( styleElm.attribute( "background_color_alpha" ).toInt() );
307  }
308  setBackgroundColor( bColor );
309  QColor tColor = QColor( styleElm.attribute( "text_color" ) );
310  if ( styleElm.hasAttribute( "text_color_alpha" ) )
311  {
312  tColor.setAlpha( styleElm.attribute( "text_color_alpha" ).toInt() );
313  }
314  setTextColor( tColor );
315  QgsFontUtils::setFromXmlChildNode( mFont, styleElm, "font" );
316  QDomElement symbolElm = styleElm.firstChildElement( "symbol" );
317  if ( !symbolElm.isNull() )
318  {
319  QgsSymbolV2* symbol = QgsSymbolLayerV2Utils::loadSymbol<QgsMarkerSymbolV2>( symbolElm );
320  setSymbol( symbol );
321  }
322  return true;
323 }
324 
Class for parsing and evaluation of expressions (formerly called "search strings").
void clear()
QString name() const
The name of the style.
QDomNodeList elementsByTagName(const QString &tagname) const
void setName(const QString &value)
Set the name of the style.
Single variable definition for use within a QgsExpressionContextScope.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Write field ui properties specific state from Dom node.
bool end()
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
void setRenderHint(RenderHint hint, bool on)
QDomNode appendChild(const QDomNode &newChild)
void fill(const QColor &color)
QString name() const
QString attribute(const QString &name, const QString &defValue) const
void setRule(const QString &value)
Set the rule for the style.
void reserve(int alloc)
virtual QgsSymbolV2 * clone() const =0
bool matches(const QVariant &value, QgsExpressionContext &context) const
Check if the rule matches using the given value and feature.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName)
Returns the conditional styles set for the field UI properties.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void setAlpha(int alpha)
bool validBackgroundColor() const
Check if the background color is valid for render.
QPixmap icon() const
The icon set for style generated from the set symbol.
const Key & key() const
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
QgsConditionalStyle & operator=(const QgsConditionalStyle &other)
void reset(T *other)
QDomElement toElement() const
void drawRect(const QRectF &rectangle)
QList< QgsConditionalStyle > rowStyles()
void setFont(const QFont &font)
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
int count() const
void append(const T &value)
Conditional styling for a rule.
bool hasAttribute(const QString &name) const
void setPen(const QColor &color)
void setAttribute(const QString &name, const QString &value)
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
int toInt(bool *ok, int base) const
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool isValid() const
isValid Check if this rule is valid.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
const T & value() const
bool writeXml(QDomNode &node, QDomDocument &doc) const
Write vector conditional style specific state from layer Dom node.
void setBrush(const QBrush &brush)
QColor backgroundColor() const
The background color for style.
void drawText(const QPointF &position, const QString &text)
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
int alpha() const
T * data() const
void setBackgroundColor(const QColor &value)
Set the background color for the style.
bool isNull() const
void setFont(const QFont &value)
Set the font for the the style.
bool isNull() const
void setRowStyles(const QList< QgsConditionalStyle > &styles)
Set the conditional styles that apply to full rows of data in the attribute table.
QColor textColor() const
The text color set for style.
QPixmap renderPreview() const
Render a preview icon of the rule.
void setSymbol(QgsSymbolV2 *value)
Set the icon for the style.
static QgsConditionalStyle matchingConditionalStyle(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching style for the value and feature.
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=nullptr)
bool readXml(const QDomNode &node)
Reads vector conditional style specific state from layer Dom node.
bool readXml(const QDomNode &node)
Reads field ui properties specific state from Dom node.
QDomElement firstChildElement(const QString &tagName) const
bool validTextColor() const
Check if the text color is valid for render.
bool toBool() const
QString displayText() const
The name of the style.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
QgsSymbolV2 * symbol() const
The symbol used to generate the icon for the style.
QFont font() const
The font for the style.
QDomElement createElement(const QString &tagName)
void setFieldStyles(const QString &fieldName, const QList< QgsConditionalStyle > &styles)
Set the conditional styles for the field UI properties.
QString rule() const
The condition rule set for the style.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
bool isValid() const
QDomNode at(int index) const
void setTextColor(const QColor &value)
Set the text color for the style.