QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  const auto constMRowStyles = mRowStyles;
56  for ( const QgsConditionalStyle &style : constMRowStyles )
57  {
58  style.writeXml( rowel, doc, context );
59  }
60 
61  stylesel.appendChild( rowel );
62 
63  QDomElement fieldsel = doc.createElement( QStringLiteral( "fieldstyles" ) );
64  QHash<QString, QgsConditionalStyles>::const_iterator it = mFieldStyles.constBegin();
65  for ( ; it != mFieldStyles.constEnd(); ++it )
66  {
67  QDomElement fieldel = doc.createElement( QStringLiteral( "fieldstyle" ) );
68  fieldel.setAttribute( QStringLiteral( "fieldname" ), it.key() );
69  QgsConditionalStyles styles = it.value();
70  const auto constStyles = styles;
71  for ( const QgsConditionalStyle &style : constStyles )
72  {
73  style.writeXml( fieldel, doc, context );
74  }
75  fieldsel.appendChild( fieldel );
76  }
77 
78  stylesel.appendChild( fieldsel );
79 
80  node.appendChild( stylesel );
81  return true;
82 }
83 
84 bool QgsConditionalLayerStyles::readXml( const QDomNode &node, const QgsReadWriteContext &context )
85 {
86  QDomElement condel = node.firstChildElement( QStringLiteral( "conditionalstyles" ) );
87  mRowStyles.clear();
88  mFieldStyles.clear();
89  QDomElement rowstylesel = condel.firstChildElement( QStringLiteral( "rowstyles" ) );
90  QDomNodeList nodelist = rowstylesel.toElement().elementsByTagName( QStringLiteral( "style" ) );
91  for ( int i = 0; i < nodelist.count(); i++ )
92  {
93  QDomElement styleElm = nodelist.at( i ).toElement();
95  style.readXml( styleElm, context );
96  mRowStyles.append( style );
97  }
98 
99  QDomElement fieldstylesel = condel.firstChildElement( QStringLiteral( "fieldstyles" ) );
100  nodelist = fieldstylesel.toElement().elementsByTagName( QStringLiteral( "fieldstyle" ) );
101  QList<QgsConditionalStyle> styles;
102  for ( int i = 0; i < nodelist.count(); i++ )
103  {
104  styles.clear();
105  QDomElement fieldel = nodelist.at( i ).toElement();
106  QString fieldName = fieldel.attribute( QStringLiteral( "fieldname" ) );
107  QDomNodeList stylenodelist = fieldel.toElement().elementsByTagName( QStringLiteral( "style" ) );
108  styles.reserve( stylenodelist.count() );
109  for ( int i = 0; i < stylenodelist.count(); i++ )
110  {
111  QDomElement styleElm = stylenodelist.at( i ).toElement();
113  style.readXml( styleElm, context );
114  styles.append( style );
115  }
116  mFieldStyles.insert( fieldName, styles );
117  }
118 
119  return true;
120 }
121 
123  : mBackColor( QColor( 0, 0, 0, 0 ) )
124  , mTextColor( QColor( 0, 0, 0, 0 ) )
125 {}
126 
128  : mBackColor( QColor( 0, 0, 0, 0 ) )
129  , mTextColor( QColor( 0, 0, 0, 0 ) )
130 {
131  setRule( rule );
132 }
133 
135  : mValid( other.mValid )
136  , mName( other.mName )
137  , mRule( other.mRule )
138  , mFont( other.mFont )
139  , mBackColor( other.mBackColor )
140  , mTextColor( other.mTextColor )
141  , mIcon( other.mIcon )
142 {
143  if ( other.mSymbol )
144  mSymbol.reset( other.mSymbol->clone() );
145 }
146 
148 {
149  mValid = other.mValid;
150  mRule = other.mRule;
151  mFont = other.mFont;
152  mBackColor = other.mBackColor;
153  mTextColor = other.mTextColor;
154  mIcon = other.mIcon;
155  mName = other.mName;
156  if ( other.mSymbol )
157  {
158  mSymbol.reset( other.mSymbol->clone() );
159  }
160  else
161  {
162  mSymbol.reset();
163  }
164  return ( *this );
165 }
166 
168 {
169  if ( name().isEmpty() )
170  return rule();
171  else
172  return QStringLiteral( "%1 \n%2" ).arg( name(), rule() );
173 }
174 
176 {
177  mValid = true;
178  if ( value )
179  {
180  mSymbol.reset( value->clone() );
181  mIcon = QgsSymbolLayerUtils::symbolPreviewPixmap( mSymbol.get(), QSize( 16, 16 ) );
182  }
183  else
184  {
185  mSymbol.reset();
186  }
187 }
188 
189 bool QgsConditionalStyle::matches( const QVariant &value, QgsExpressionContext &context ) const
190 {
191  QgsExpression exp( mRule );
192  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "value" ), value, true ) );
193  return exp.evaluate( &context ).toBool();
194 }
195 
197 {
198  QPixmap pixmap( 64, 32 );
199  pixmap.fill( Qt::transparent );
200 
201  QPainter painter( &pixmap );
202 
203  if ( validBackgroundColor() )
204  painter.setBrush( mBackColor );
205 
206  QRect rect = QRect( 0, 0, 64, 32 );
207  painter.setPen( Qt::NoPen );
208  painter.drawRect( rect );
209  painter.drawPixmap( 8, 8, icon() );
210 
211  if ( validTextColor() )
212  painter.setPen( mTextColor );
213  else
214  painter.setPen( Qt::black );
215 
216  painter.setRenderHint( QPainter::Antialiasing );
217  painter.setRenderHint( QPainter::HighQualityAntialiasing );
218  painter.setFont( font() );
219  rect = QRect( 32, 0, 32, 32 );
220  painter.drawText( rect, Qt::AlignCenter, QStringLiteral( "abc\n123" ) );
221  painter.end();
222  return pixmap;
223 }
224 
226 {
227  return ( backgroundColor().isValid() && backgroundColor().alpha() != 0 );
228 }
229 
231 {
232  return ( textColor().isValid() && textColor().alpha() != 0 );
233 }
234 
235 QList<QgsConditionalStyle> QgsConditionalStyle::matchingConditionalStyles( const QList<QgsConditionalStyle> &styles, const QVariant &value, QgsExpressionContext &context )
236 {
237  QList<QgsConditionalStyle> matchingstyles;
238  const auto constStyles = styles;
239  for ( const QgsConditionalStyle &style : constStyles )
240  {
241  if ( style.matches( value, context ) )
242  matchingstyles.append( style );
243  }
244  return matchingstyles;
245 }
246 
247 QgsConditionalStyle QgsConditionalStyle::matchingConditionalStyle( const QList<QgsConditionalStyle> &styles, const QVariant &value, QgsExpressionContext &context )
248 {
249  const auto constStyles = styles;
250  for ( const QgsConditionalStyle &style : constStyles )
251  {
252  if ( style.matches( value, context ) )
253  return style;
254  }
255  return QgsConditionalStyle();
256 }
257 
258 QgsConditionalStyle QgsConditionalStyle::compressStyles( const QList<QgsConditionalStyle> &styles )
259 {
260  QgsConditionalStyle style;
261  const auto constStyles = styles;
262  for ( const QgsConditionalStyle &s : constStyles )
263  {
264  style.setFont( s.font() );
265  if ( s.backgroundColor().isValid() && s.backgroundColor().alpha() != 0 )
266  style.setBackgroundColor( s.backgroundColor() );
267  if ( s.textColor().isValid() && s.textColor().alpha() != 0 )
268  style.setTextColor( s.textColor() );
269  if ( s.symbol() )
270  style.setSymbol( s.symbol() );
271  }
272  return style;
273 }
274 
275 bool QgsConditionalStyle::writeXml( QDomNode &node, QDomDocument &doc, const QgsReadWriteContext &context ) const
276 {
277  QDomElement stylesel = doc.createElement( QStringLiteral( "style" ) );
278  stylesel.setAttribute( QStringLiteral( "rule" ), mRule );
279  stylesel.setAttribute( QStringLiteral( "name" ), mName );
280  stylesel.setAttribute( QStringLiteral( "background_color" ), mBackColor.name() );
281  stylesel.setAttribute( QStringLiteral( "background_color_alpha" ), mBackColor.alpha() );
282  stylesel.setAttribute( QStringLiteral( "text_color" ), mTextColor.name() );
283  stylesel.setAttribute( QStringLiteral( "text_color_alpha" ), mTextColor.alpha() );
284  QDomElement labelFontElem = QgsFontUtils::toXmlElement( mFont, doc, QStringLiteral( "font" ) );
285  stylesel.appendChild( labelFontElem );
286  if ( mSymbol )
287  {
288  QDomElement symbolElm = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "icon" ), mSymbol.get(), doc, context );
289  stylesel.appendChild( symbolElm );
290  }
291  node.appendChild( stylesel );
292  return true;
293 }
294 
295 bool QgsConditionalStyle::readXml( const QDomNode &node, const QgsReadWriteContext &context )
296 {
297  QDomElement styleElm = node.toElement();
298  setRule( styleElm.attribute( QStringLiteral( "rule" ) ) );
299  setName( styleElm.attribute( QStringLiteral( "name" ) ) );
300  QColor bColor = QColor( styleElm.attribute( QStringLiteral( "background_color" ) ) );
301  if ( styleElm.hasAttribute( QStringLiteral( "background_color_alpha" ) ) )
302  {
303  bColor.setAlpha( styleElm.attribute( QStringLiteral( "background_color_alpha" ) ).toInt() );
304  }
305  setBackgroundColor( bColor );
306  QColor tColor = QColor( styleElm.attribute( QStringLiteral( "text_color" ) ) );
307  if ( styleElm.hasAttribute( QStringLiteral( "text_color_alpha" ) ) )
308  {
309  tColor.setAlpha( styleElm.attribute( QStringLiteral( "text_color_alpha" ) ).toInt() );
310  }
311  setTextColor( tColor );
312  QgsFontUtils::setFromXmlChildNode( mFont, styleElm, QStringLiteral( "font" ) );
313  QDomElement symbolElm = styleElm.firstChildElement( QStringLiteral( "symbol" ) );
314  if ( !symbolElm.isNull() )
315  {
316  QgsSymbol *symbol = QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( symbolElm, context );
317  setSymbol( symbol );
318  }
319  return true;
320 }
321 
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.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
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
Returns 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
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr)
Returns a pixmap preview for a color ramp.
void setTextColor(const QColor &value)
Set the text color for the style.