QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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...
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 validTextColor() const
Check if the text color is valid for render.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
QColor textColor() const
The text color set for style.
bool validBackgroundColor() const
Check if the background color is valid for render.
void setRule(const QString &value)
Set the rule for the style.
QFont font() const
The font for the style.
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.
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.
QPixmap icon() const
The icon set for style generated from the set symbol.
Conditional styling for a rule.
bool matches(const QVariant &value, QgsExpressionContext &context) const
Check if the rule matches using the given value and feature.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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.
QString name() const
The name of the 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.
QPixmap renderPreview() const
Render a preview icon of the rule.
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.
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
Returns a deep copy of this symbol.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
QString rule() const
The condition rule set for the style.
bool isValid() const
isValid Check if this rule is valid.
bool writeXml(QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context) const
Write field ui properties specific state from Dom node.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
QgsSymbol * symbol() const
The symbol used to generate the icon 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.
bool writeXml(QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context) const
Write vector conditional style specific state from layer Dom node.
QString displayText() const
The name of the style.
QList< QgsConditionalStyle > QgsConditionalStyles
void setTextColor(const QColor &value)
Set the text color for the style.