QGIS API Documentation  3.2.0-Bonn (bc43194)
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 "qgssymbollayerutils.h"
21 #include "qgsmarkersymbollayer.h"
22 
24  : mRowStyles( QList<QgsConditionalStyle>() )
25 {}
26 
27 QList<QgsConditionalStyle> QgsConditionalLayerStyles::rowStyles()
28 {
29  return mRowStyles;
30 }
31 
32 void QgsConditionalLayerStyles::setRowStyles( const QList<QgsConditionalStyle> &styles )
33 {
34  mRowStyles = styles;
35 }
36 
37 void QgsConditionalLayerStyles::setFieldStyles( const QString &fieldName, const QList<QgsConditionalStyle> &styles )
38 {
39  mFieldStyles.insert( fieldName, styles );
40 }
41 
42 QList<QgsConditionalStyle> QgsConditionalLayerStyles::fieldStyles( const QString &fieldName )
43 {
44  if ( mFieldStyles.contains( fieldName ) )
45  {
46  return mFieldStyles[fieldName];
47  }
48  return QList<QgsConditionalStyle>();
49 }
50 
51 bool QgsConditionalLayerStyles::writeXml( QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context ) const
52 {
53  QDomElement stylesel = doc.createElement( QStringLiteral( "conditionalstyles" ) );
54  QDomElement rowel = doc.createElement( QStringLiteral( "rowstyles" ) );
55  Q_FOREACH ( const QgsConditionalStyle &style, mRowStyles )
56  {
57  style.writeXml( rowel, doc, context );
58  }
59 
60  stylesel.appendChild( rowel );
61 
62  QDomElement fieldsel = doc.createElement( QStringLiteral( "fieldstyles" ) );
63  QHash<QString, QgsConditionalStyles>::const_iterator it = mFieldStyles.constBegin();
64  for ( ; it != mFieldStyles.constEnd(); ++it )
65  {
66  QDomElement fieldel = doc.createElement( QStringLiteral( "fieldstyle" ) );
67  fieldel.setAttribute( QStringLiteral( "fieldname" ), it.key() );
68  QgsConditionalStyles styles = it.value();
69  Q_FOREACH ( const QgsConditionalStyle &style, styles )
70  {
71  style.writeXml( fieldel, doc, context );
72  }
73  fieldsel.appendChild( fieldel );
74  }
75 
76  stylesel.appendChild( fieldsel );
77 
78  node.appendChild( stylesel );
79  return true;
80 }
81 
82 bool QgsConditionalLayerStyles::readXml( const QDomNode &node, const QgsReadWriteContext &context )
83 {
84  QDomElement condel = node.firstChildElement( QStringLiteral( "conditionalstyles" ) );
85  mRowStyles.clear();
86  mFieldStyles.clear();
87  QDomElement rowstylesel = condel.firstChildElement( QStringLiteral( "rowstyles" ) );
88  QDomNodeList nodelist = rowstylesel.toElement().elementsByTagName( QStringLiteral( "style" ) );
89  for ( int i = 0; i < nodelist.count(); i++ )
90  {
91  QDomElement styleElm = nodelist.at( i ).toElement();
93  style.readXml( styleElm, context );
94  mRowStyles.append( style );
95  }
96 
97  QDomElement fieldstylesel = condel.firstChildElement( QStringLiteral( "fieldstyles" ) );
98  nodelist = fieldstylesel.toElement().elementsByTagName( QStringLiteral( "fieldstyle" ) );
99  QList<QgsConditionalStyle> styles;
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( QStringLiteral( "fieldname" ) );
105  QDomNodeList stylenodelist = fieldel.toElement().elementsByTagName( QStringLiteral( "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, context );
112  styles.append( style );
113  }
114  mFieldStyles.insert( fieldName, styles );
115  }
116 
117  return true;
118 }
119 
121  : mBackColor( QColor( 0, 0, 0, 0 ) )
122  , mTextColor( QColor( 0, 0, 0, 0 ) )
123 {}
124 
126  : mBackColor( QColor( 0, 0, 0, 0 ) )
127  , mTextColor( QColor( 0, 0, 0, 0 ) )
128 {
129  setRule( rule );
130 }
131 
133  : mValid( other.mValid )
134  , mName( other.mName )
135  , mRule( other.mRule )
136  , mFont( other.mFont )
137  , mBackColor( other.mBackColor )
138  , mTextColor( other.mTextColor )
139  , mIcon( other.mIcon )
140 {
141  if ( other.mSymbol )
142  mSymbol.reset( other.mSymbol->clone() );
143 }
144 
146 {
147  mValid = other.mValid;
148  mRule = other.mRule;
149  mFont = other.mFont;
150  mBackColor = other.mBackColor;
151  mTextColor = other.mTextColor;
152  mIcon = other.mIcon;
153  mName = other.mName;
154  if ( other.mSymbol )
155  {
156  mSymbol.reset( other.mSymbol->clone() );
157  }
158  else
159  {
160  mSymbol.reset();
161  }
162  return ( *this );
163 }
164 
166 {
167  if ( name().isEmpty() )
168  return rule();
169  else
170  return QStringLiteral( "%1 \n%2" ).arg( name(), rule() );
171 }
172 
174 {
175  mValid = true;
176  if ( value )
177  {
178  mSymbol.reset( value->clone() );
179  mIcon = QgsSymbolLayerUtils::symbolPreviewPixmap( mSymbol.get(), QSize( 16, 16 ) );
180  }
181  else
182  {
183  mSymbol.reset();
184  }
185 }
186 
187 bool QgsConditionalStyle::matches( const QVariant &value, QgsExpressionContext &context ) const
188 {
189  QgsExpression exp( mRule );
190  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "value" ), value, true ) );
191  return exp.evaluate( &context ).toBool();
192 }
193 
195 {
196  QPixmap pixmap( 64, 32 );
197  pixmap.fill( Qt::transparent );
198 
199  QPainter painter( &pixmap );
200 
201  if ( validBackgroundColor() )
202  painter.setBrush( mBackColor );
203 
204  QRect rect = QRect( 0, 0, 64, 32 );
205  painter.setPen( Qt::NoPen );
206  painter.drawRect( rect );
207  painter.drawPixmap( 8, 8, icon() );
208 
209  if ( validTextColor() )
210  painter.setPen( mTextColor );
211  else
212  painter.setPen( Qt::black );
213 
214  painter.setRenderHint( QPainter::Antialiasing );
215  painter.setRenderHint( QPainter::HighQualityAntialiasing );
216  painter.setFont( font() );
217  rect = QRect( 32, 0, 32, 32 );
218  painter.drawText( rect, Qt::AlignCenter, QStringLiteral( "abc\n123" ) );
219  painter.end();
220  return pixmap;
221 }
222 
224 {
225  return ( backgroundColor().isValid() && backgroundColor().alpha() != 0 );
226 }
227 
229 {
230  return ( textColor().isValid() && textColor().alpha() != 0 );
231 }
232 
233 QList<QgsConditionalStyle> QgsConditionalStyle::matchingConditionalStyles( const QList<QgsConditionalStyle> &styles, const QVariant &value, QgsExpressionContext &context )
234 {
235  QList<QgsConditionalStyle> matchingstyles;
236  Q_FOREACH ( const QgsConditionalStyle &style, styles )
237  {
238  if ( style.matches( value, context ) )
239  matchingstyles.append( style );
240  }
241  return matchingstyles;
242 }
243 
244 QgsConditionalStyle QgsConditionalStyle::matchingConditionalStyle( const QList<QgsConditionalStyle> &styles, const QVariant &value, QgsExpressionContext &context )
245 {
246  Q_FOREACH ( const QgsConditionalStyle &style, styles )
247  {
248  if ( style.matches( value, context ) )
249  return style;
250  }
251  return QgsConditionalStyle();
252 }
253 
254 QgsConditionalStyle QgsConditionalStyle::compressStyles( const QList<QgsConditionalStyle> &styles )
255 {
256  QgsConditionalStyle style;
257  Q_FOREACH ( const QgsConditionalStyle &s, styles )
258  {
259  style.setFont( s.font() );
260  if ( s.backgroundColor().isValid() && s.backgroundColor().alpha() != 0 )
261  style.setBackgroundColor( s.backgroundColor() );
262  if ( s.textColor().isValid() && s.textColor().alpha() != 0 )
263  style.setTextColor( s.textColor() );
264  if ( s.symbol() )
265  style.setSymbol( s.symbol() );
266  }
267  return style;
268 }
269 
270 bool QgsConditionalStyle::writeXml( QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context ) const
271 {
272  QDomElement stylesel = doc.createElement( QStringLiteral( "style" ) );
273  stylesel.setAttribute( QStringLiteral( "rule" ), mRule );
274  stylesel.setAttribute( QStringLiteral( "name" ), mName );
275  stylesel.setAttribute( QStringLiteral( "background_color" ), mBackColor.name() );
276  stylesel.setAttribute( QStringLiteral( "background_color_alpha" ), mBackColor.alpha() );
277  stylesel.setAttribute( QStringLiteral( "text_color" ), mTextColor.name() );
278  stylesel.setAttribute( QStringLiteral( "text_color_alpha" ), mTextColor.alpha() );
279  QDomElement labelFontElem = QgsFontUtils::toXmlElement( mFont, doc, QStringLiteral( "font" ) );
280  stylesel.appendChild( labelFontElem );
281  if ( mSymbol )
282  {
283  QDomElement symbolElm = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "icon" ), mSymbol.get(), doc, context );
284  stylesel.appendChild( symbolElm );
285  }
286  node.appendChild( stylesel );
287  return true;
288 }
289 
290 bool QgsConditionalStyle::readXml( const QDomNode &node, const QgsReadWriteContext &context )
291 {
292  QDomElement styleElm = node.toElement();
293  setRule( styleElm.attribute( QStringLiteral( "rule" ) ) );
294  setName( styleElm.attribute( QStringLiteral( "name" ) ) );
295  QColor bColor = QColor( styleElm.attribute( QStringLiteral( "background_color" ) ) );
296  if ( styleElm.hasAttribute( QStringLiteral( "background_color_alpha" ) ) )
297  {
298  bColor.setAlpha( styleElm.attribute( QStringLiteral( "background_color_alpha" ) ).toInt() );
299  }
300  setBackgroundColor( bColor );
301  QColor tColor = QColor( styleElm.attribute( QStringLiteral( "text_color" ) ) );
302  if ( styleElm.hasAttribute( QStringLiteral( "text_color_alpha" ) ) )
303  {
304  tColor.setAlpha( styleElm.attribute( QStringLiteral( "text_color_alpha" ) ).toInt() );
305  }
306  setTextColor( tColor );
307  QgsFontUtils::setFromXmlChildNode( mFont, styleElm, QStringLiteral( "font" ) );
308  QDomElement symbolElm = styleElm.firstChildElement( QStringLiteral( "symbol" ) );
309  if ( !symbolElm.isNull() )
310  {
311  QgsSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElm, context );
312  setSymbol( symbol );
313  }
314  return true;
315 }
316 
Class for parsing and evaluation of expressions (formerly called "search strings").
The class is used as a container of context for various read/write operations on other objects...
QString name() const
The name of the style.
void setName(const QString &value)
Set the name of the style.
Single variable definition for use within a QgsExpressionContextScope.
static QPixmap symbolPreviewPixmap(QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr)
Returns a pixmap preview for a color ramp.
bool writeXml(QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context) const
Write field ui properties specific state from Dom node.
void setRule(const QString &value)
Set the rule for the style.
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.
QVariant evaluate()
Evaluate the feature and return the result.
bool writeXml(QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context) const
Write vector conditional style specific state from layer Dom node.
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.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
QgsConditionalStyle & operator=(const QgsConditionalStyle &other)
QList< QgsConditionalStyle > rowStyles()
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
Conditional styling for a rule.
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.
QColor backgroundColor() const
The background color for style.
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.
bool readXml(const QDomNode &node, const QgsReadWriteContext &context)
Reads field ui properties specific state from Dom node.
void setBackgroundColor(const QColor &value)
Set the background color for the style.
void setFont(const QFont &value)
Set the font for the style.
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.
static QgsConditionalStyle matchingConditionalStyle(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching style for the value and feature.
void setSymbol(QgsSymbol *value)
Set the icon for the style.
virtual QgsSymbol * clone() const =0
Gets a deep copy of this symbol.
bool validTextColor() const
Check if the text color is valid for render.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
QgsSymbol * symbol() const
The symbol used to generate the icon for the style.
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.
QFont font() const
The font for the style.
void setFieldStyles(const QString &fieldName, const QList< QgsConditionalStyle > &styles)
Set the conditional styles for the field UI properties.
bool readXml(const QDomNode &node, const QgsReadWriteContext &context)
Reads vector conditional style specific state from layer Dom node.
QString rule() const
The condition rule set for the style.
QList< QgsConditionalStyle > QgsConditionalStyles
void setTextColor(const QColor &value)
Set the text color for the style.