QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgssinglesymbolrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglesymbolrenderer.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk 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 
17 
18 #include "qgssymbol.h"
19 #include "qgssymbollayerutils.h"
20 
22 #include "qgslogger.h"
23 #include "qgsfeature.h"
24 #include "qgsvectorlayer.h"
25 #include "qgssymbollayer.h"
26 #include "qgsogcutils.h"
29 #include "qgspainteffect.h"
30 #include "qgspainteffectregistry.h"
31 #include "qgsproperty.h"
32 #include "qgsstyleentityvisitor.h"
33 
34 #include <QDomDocument>
35 #include <QDomElement>
36 
38  : QgsFeatureRenderer( QStringLiteral( "singleSymbol" ) )
39  , mSymbol( symbol )
40 {
41  Q_ASSERT( symbol );
42 }
43 
45 {
46  return mSymbol.get();
47 }
48 
50 {
51  Q_UNUSED( context )
52  Q_UNUSED( feature )
53  return mSymbol.get();
54 }
55 
57 {
58  QgsFeatureRenderer::startRender( context, fields );
59 
60  if ( !mSymbol )
61  return;
62 
63  mSymbol->startRender( context, fields );
64 }
65 
67 {
69 
70  if ( !mSymbol )
71  return;
72 
73  mSymbol->stopRender( context );
74 }
75 
76 QSet<QString> QgsSingleSymbolRenderer::usedAttributes( const QgsRenderContext &context ) const
77 {
78  QSet<QString> attributes;
79  if ( mSymbol )
80  attributes.unite( mSymbol->usedAttributes( context ) );
81  return attributes;
82 }
83 
85 {
86  if ( mSymbol )
87  {
88  QgsStyleSymbolEntity entity( mSymbol.get() );
89  return visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) );
90  }
91  return true;
92 }
93 
95 {
96  return mSymbol.get();
97 }
98 
100 {
101  Q_ASSERT( s );
102  mSymbol.reset( s );
103 }
104 
106 {
107  return mSymbol ? QStringLiteral( "SINGLE: %1" ).arg( mSymbol->dump() ) : QString();
108 }
109 
111 {
115  copyRendererData( r );
116  return r;
117 }
118 
119 void QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
120 {
121  QgsStringMap newProps = props;
122 
123  QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
124  element.appendChild( ruleElem );
125 
126  QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
127  nameElem.appendChild( doc.createTextNode( QStringLiteral( "Single symbol" ) ) );
128  ruleElem.appendChild( nameElem );
129 
130  QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, newProps );
131 
132  if ( mSymbol ) mSymbol->toSld( doc, ruleElem, newProps );
133 }
134 
136 {
137  Q_UNUSED( context )
138  QgsSymbolList lst;
139  lst.append( mSymbol.get() );
140  return lst;
141 }
142 
143 
145 {
146  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
147  if ( symbolsElem.isNull() )
148  return nullptr;
149 
150  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
151 
152  if ( !symbolMap.contains( QStringLiteral( "0" ) ) )
153  return nullptr;
154 
155  QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( symbolMap.take( QStringLiteral( "0" ) ) );
156 
157  // delete symbols if there are any more
159 
160  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
161  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
162  {
163  convertSymbolRotation( r->mSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
164  }
165 
166  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
167  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
168  {
170  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
171  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
172  }
173 
174  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
175  if ( !ddsLegendSizeElem.isNull() )
176  {
177  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
178  }
179 
180  // TODO: symbol levels
181  return r;
182 }
183 
185 {
186  // XXX this renderer can handle only one Rule!
187 
188  // get the first Rule element
189  QDomElement ruleElem = element.firstChildElement( QStringLiteral( "Rule" ) );
190  if ( ruleElem.isNull() )
191  {
192  QgsDebugMsg( QStringLiteral( "no Rule elements found!" ) );
193  return nullptr;
194  }
195 
196  QString label, description;
197  QgsSymbolLayerList layers;
198 
199  // retrieve the Rule element child nodes
200  QDomElement childElem = ruleElem.firstChildElement();
201  while ( !childElem.isNull() )
202  {
203  if ( childElem.localName() == QLatin1String( "Name" ) )
204  {
205  // <se:Name> tag contains the rule identifier,
206  // so prefer title tag for the label property value
207  if ( label.isEmpty() )
208  label = childElem.firstChild().nodeValue();
209  }
210  else if ( childElem.localName() == QLatin1String( "Description" ) )
211  {
212  // <se:Description> can contains a title and an abstract
213  QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) );
214  if ( !titleElem.isNull() )
215  {
216  label = titleElem.firstChild().nodeValue();
217  }
218 
219  QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) );
220  if ( !abstractElem.isNull() )
221  {
222  description = abstractElem.firstChild().nodeValue();
223  }
224  }
225  else if ( childElem.localName() == QLatin1String( "Abstract" ) )
226  {
227  // <sld:Abstract> (v1.0)
228  description = childElem.firstChild().nodeValue();
229  }
230  else if ( childElem.localName() == QLatin1String( "Title" ) )
231  {
232  // <sld:Title> (v1.0)
233  label = childElem.firstChild().nodeValue();
234  }
235  else if ( childElem.localName().endsWith( QLatin1String( "Symbolizer" ) ) )
236  {
237  // create symbol layers for this symbolizer
238  QgsSymbolLayerUtils::createSymbolLayerListFromSld( childElem, geomType, layers );
239  }
240 
241  childElem = childElem.nextSiblingElement();
242  }
243 
244  if ( layers.isEmpty() )
245  return nullptr;
246 
247  // now create the symbol
248  std::unique_ptr< QgsSymbol > symbol;
249  switch ( geomType )
250  {
252  symbol = qgis::make_unique< QgsLineSymbol >( layers );
253  break;
254 
256  symbol = qgis::make_unique< QgsFillSymbol >( layers );
257  break;
258 
260  symbol = qgis::make_unique< QgsMarkerSymbol >( layers );
261  break;
262 
263  default:
264  QgsDebugMsg( QStringLiteral( "invalid geometry type: found %1" ).arg( geomType ) );
265  return nullptr;
266  }
267 
268  // and finally return the new renderer
269  return new QgsSingleSymbolRenderer( symbol.release() );
270 }
271 
272 QDomElement QgsSingleSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
273 {
274  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
275  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "singleSymbol" ) );
276  rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
277  rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
278 
280  symbols[QStringLiteral( "0" )] = mSymbol.get();
281  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
282  rendererElem.appendChild( symbolsElem );
283 
284  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
285  rendererElem.appendChild( rotationElem );
286 
287  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
288  rendererElem.appendChild( sizeScaleElem );
289 
291  mPaintEffect->saveProperties( doc, rendererElem );
292 
293  if ( !mOrderBy.isEmpty() )
294  {
295  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
296  mOrderBy.save( orderBy );
297  rendererElem.appendChild( orderBy );
298  }
299  rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
300 
302  {
303  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
304  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
305  rendererElem.appendChild( ddsLegendElem );
306  }
307 
308  return rendererElem;
309 }
310 
312 {
314  {
315  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( mSymbol.get() );
316  QgsProperty sizeDD( symbol->dataDefinedSize() );
317  if ( sizeDD && sizeDD.isActive() )
318  {
320  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSymbol.get() ), sizeDD );
321  return ddSizeLegend.legendSymbolList();
322  }
323  }
324 
326  lst << QgsLegendSymbolItem( mSymbol.get(), QString(), QStringLiteral( "0" ) );
327  return lst;
328 }
329 
330 QSet< QString > QgsSingleSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
331 {
332  Q_UNUSED( feature )
333  Q_UNUSED( context )
334  return QSet< QString >() << QStringLiteral( "0" );
335 }
336 
338 {
339  Q_UNUSED( key )
340  setSymbol( symbol );
341 }
342 
344 {
345  QgsSingleSymbolRenderer *r = nullptr;
346  if ( renderer->type() == QLatin1String( "singleSymbol" ) )
347  {
348  r = dynamic_cast<QgsSingleSymbolRenderer *>( renderer->clone() );
349  }
350  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
351  {
352  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
353  if ( pointDistanceRenderer )
354  r = convertFromRenderer( pointDistanceRenderer->embeddedRenderer() );
355  }
356  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
357  {
358  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
359  if ( invertedPolygonRenderer )
360  r = convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
361  }
362 
363  if ( !r )
364  {
365  QgsRenderContext context;
366  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
367  if ( !symbols.isEmpty() )
368  {
369  r = new QgsSingleSymbolRenderer( symbols.at( 0 )->clone() );
370  }
371  }
372 
373  if ( r )
374  {
375  r->setOrderBy( renderer->orderBy() );
376  r->setOrderByEnabled( renderer->orderByEnabled() );
377  }
378 
379  return r;
380 }
381 
383 {
384  mDataDefinedSizeLegend.reset( settings );
385 }
386 
388 {
389  return mDataDefinedSizeLegend.get();
390 }
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new single symbol renderer from an XML element, using the supplied read/write context...
void toSld(QDomDocument &doc, QDomElement &element, const QgsStringMap &props=QgsStringMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
The class is used as a container of context for various read/write operations on other objects...
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:971
static QgsSymbol::ScaleMethod decodeScaleMethod(const QString &str)
QList< QgsLegendSymbolItem > QgsLegendSymbolList
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:533
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QgsStringMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
static QgsSingleSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a new single symbol renderer from an existing renderer.
Container of fields for a vector layer.
Definition: qgsfields.h:42
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:50
void setUsingSymbolLevels(bool usingSymbolLevels)
Definition: qgsrenderer.h:273
static void clearSymbolMap(QgsSymbolMap &symbols)
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:517
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
An interface for classes which can visit style entity (e.g.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
QMap< QString, QString > QgsStringMap
Definition: qgis.h:612
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:860
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
static QgsFeatureRenderer * createFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType)
Creates a new single symbol renderer from an SLD element.
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:44
QString type() const
Definition: qgsrenderer.h:130
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:51
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
static void convertSymbolSizeScale(QgsSymbol *symbol, QgsSymbol::ScaleMethod method, const QString &field)
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
A store for object properties.
Definition: qgsproperty.h:229
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer...
void setSymbol(QgsSymbol *s)
Sets the symbol which will be rendered for every feature.
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
void setOrderBy(const QgsFeatureRequest::OrderBy &orderBy)
Define the order in which features shall be processed by this renderer.
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1543
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
Marker symbol.
Definition: qgssymbol.h:85
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
QString dump() const override
Returns debug information about this renderer.
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Contains information about the context of a rendering operation.
bool usingSymbolLevels() const
Definition: qgsrenderer.h:272
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
Definition: qgsrenderer.cpp:93
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QMap< QString, QgsSymbol *> QgsSymbolMap
Definition: qgsrenderer.h:45
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:49
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols...
QgsSingleSymbolRenderer(QgsSymbol *symbol)
Constructor for QgsSingleSymbolRenderer.
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
Object that keeps configuration of appearance of marker symbol&#39;s data-defined size in legend...
static bool createSymbolLayerListFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType, QgsSymbolLayerList &layers)
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns nullptr on error...
Contains information relating to the style entity currently being visited.
std::unique_ptr< QgsSymbol > mSymbol
void setOrderByEnabled(bool enabled)
Sets whether custom ordering should be applied before features are processed by this renderer...
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsSingleSymbolRenderer * clone() const override
Create a deep copy of this renderer.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.