QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsgrouplayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgrouplayer.cpp
3  ----------------
4  Date : September 2021
5  Copyright : (C) 2021 by Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsgrouplayer.h"
19 #include "qgsmaplayerfactory.h"
20 #include "qgspainting.h"
21 #include "qgsmaplayerlistutils_p.h"
22 #include "qgsgrouplayerrenderer.h"
23 #include "qgsmaplayerref.h"
24 #include "qgsvectorlayer.h"
25 #include "qgscoordinatetransform.h"
26 #include "qgspainteffect.h"
27 #include "qgsmessagelog.h"
28 #include "qgspainteffectregistry.h"
29 #include "qgsapplication.h"
30 #include "qgsmaplayerutils.h"
31 
32 QgsGroupLayer::QgsGroupLayer( const QString &name, const LayerOptions &options )
34  , mTransformContext( options.transformContext )
35 {
36  mShouldValidateCrs = false;
37  mValid = true;
38 
39  mPaintEffect.reset( QgsPaintEffectRegistry::defaultStack() );
40  mPaintEffect->setEnabled( false );
41 
42  QgsDataProvider::ProviderOptions providerOptions;
43  providerOptions.transformContext = options.transformContext;
44  mDataProvider = new QgsGroupLayerDataProvider( providerOptions, QgsDataProvider::ReadFlags() );
45 }
46 
48 {
49  emit willBeDeleted();
50  delete mDataProvider;
51 }
52 
54 {
55  const QgsGroupLayer::LayerOptions options( mTransformContext );
56  std::unique_ptr< QgsGroupLayer > layer = std::make_unique< QgsGroupLayer >( name(), options );
57  QgsMapLayer::clone( layer.get() );
58  layer->setChildLayers( _qgis_listRefToRaw( mChildren ) );
59  layer->setPaintEffect( mPaintEffect ? mPaintEffect->clone() : nullptr );
60  return layer.release();
61 }
62 
64 {
65  return new QgsGroupLayerRenderer( this, context );
66 }
67 
69 {
70  return QgsMapLayerUtils::combinedExtent( childLayers(), crs(), mTransformContext );
71 }
72 
74 {
75  if ( mDataProvider )
76  mDataProvider->setTransformContext( context );
77 
78  mTransformContext = context;
80 }
81 
82 bool QgsGroupLayer::readXml( const QDomNode &layerNode, QgsReadWriteContext &context )
83 {
85  {
86  return false;
87  }
88 
89  const QList< QgsMapLayer * > currentLayers = _qgis_listRefToRaw( mChildren );
90  for ( QgsMapLayer *layer : currentLayers )
91  {
92  disconnect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapLayer::triggerRepaint );
93  }
94 
95  mChildren.clear();
96  const QDomNodeList childLayersElements = layerNode.toElement().elementsByTagName( QStringLiteral( "childLayers" ) );
97  const QDomNodeList children = childLayersElements.at( 0 ).childNodes();
98  for ( int i = 0; i < children.size(); ++i )
99  {
100  const QDomElement childElement = children.at( i ).toElement();
101  const QString id = childElement.attribute( QStringLiteral( "layerid" ) );
102  mChildren.append( QgsMapLayerRef( id ) );
103  }
105 
106  QString errorMsg;
107  readSymbology( layerNode, errorMsg, context );
108 
109  triggerRepaint();
110 
111  return mValid;
112 }
113 
114 bool QgsGroupLayer::writeXml( QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context ) const
115 {
116  // first get the layer element so that we can append the type attribute
117  QDomElement mapLayerNode = layer_node.toElement();
118 
119  if ( mapLayerNode.isNull() )
120  {
121  QgsDebugMsgLevel( QStringLiteral( "can't find maplayer node" ), 2 );
122  return false;
123  }
124 
125  mapLayerNode.setAttribute( QStringLiteral( "type" ), QgsMapLayerFactory::typeToString( QgsMapLayerType::GroupLayer ) );
126 
127  QDomElement childLayersElement = doc.createElement( QStringLiteral( "childLayers" ) );
128  for ( auto it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
129  {
130  QDomElement childElement = doc.createElement( QStringLiteral( "child" ) );
131  childElement.setAttribute( QStringLiteral( "layerid" ), it->layerId );
132  childLayersElement.appendChild( childElement );
133  }
134  mapLayerNode.appendChild( childLayersElement );
135 
136  // renderer specific settings
137  QString errorMsg;
138  return writeSymbology( layer_node, doc, errorMsg, context );
139 }
140 
141 bool QgsGroupLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString &, const QgsReadWriteContext &, QgsMapLayer::StyleCategories categories ) const
142 {
143  // add the layer opacity
144  if ( categories.testFlag( Rendering ) )
145  {
146  QDomElement layerOpacityElem = doc.createElement( QStringLiteral( "layerOpacity" ) );
147  const QDomText layerOpacityText = doc.createTextNode( QString::number( opacity() ) );
148  layerOpacityElem.appendChild( layerOpacityText );
149  node.appendChild( layerOpacityElem );
150 
151  if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect.get() ) )
152  {
153  QDomElement paintEffectElement = doc.createElement( QStringLiteral( "paintEffect" ) );
154  mPaintEffect->saveProperties( doc, paintEffectElement );
155  node.appendChild( paintEffectElement );
156  }
157  }
158 
159  if ( categories.testFlag( Symbology ) )
160  {
161  // add the blend mode field
162  QDomElement blendModeElem = doc.createElement( QStringLiteral( "blendMode" ) );
163  const QDomText blendModeText = doc.createTextNode( QString::number( QgsPainting::getBlendModeEnum( blendMode() ) ) );
164  blendModeElem.appendChild( blendModeText );
165  node.appendChild( blendModeElem );
166  }
167 
168  return true;
169 }
170 
171 bool QgsGroupLayer::readSymbology( const QDomNode &node, QString &, QgsReadWriteContext &, QgsMapLayer::StyleCategories categories )
172 {
173  if ( categories.testFlag( Rendering ) )
174  {
175  const QDomNode layerOpacityNode = node.namedItem( QStringLiteral( "layerOpacity" ) );
176  if ( !layerOpacityNode.isNull() )
177  {
178  const QDomElement e = layerOpacityNode.toElement();
179  setOpacity( e.text().toDouble() );
180  }
181 
182  //restore layer effect
183  const QDomElement effectElem = node.namedItem( QStringLiteral( "paintEffect" ) ).toElement();
184  if ( !effectElem.isNull() )
185  {
186  const QDomElement effectPropertiesElem = effectElem.firstChildElement( QStringLiteral( "effect" ) ).toElement();
187  mPaintEffect.reset( QgsApplication::paintEffectRegistry()->createEffect( effectPropertiesElem ) );
188  }
189  else
190  {
191  mPaintEffect.reset( QgsPaintEffectRegistry::defaultStack() );
192  mPaintEffect->setEnabled( false );
193  }
194  }
195 
196  if ( categories.testFlag( Symbology ) )
197  {
198  // get and set the blend mode if it exists
199  const QDomNode blendModeNode = node.namedItem( QStringLiteral( "blendMode" ) );
200  if ( !blendModeNode.isNull() )
201  {
202  const QDomElement e = blendModeNode.toElement();
203  setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( e.text().toInt() ) ) );
204  }
205  }
206 
207  return true;
208 }
209 
211 {
212  return mDataProvider;
213 }
214 
216 {
217  return mDataProvider;
218 }
219 
221 {
222  QString metadata = QStringLiteral( "<html>\n<body>\n<h1>" ) + tr( "General" ) + QStringLiteral( "</h1>\n<hr>\n" ) + QStringLiteral( "<table class=\"list-view\">\n" );
223 
224  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );
225 
226  // Extent
227  metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Extent" ) + QStringLiteral( "</td><td>" ) + extent().toString() + QStringLiteral( "</td></tr>\n" );
228 
229 
230  metadata += QLatin1String( "\n</body>\n</html>\n" );
231  return metadata;
232 }
233 
235 {
237  for ( int i = 0; i < mChildren.size(); ++i )
238  {
239  mChildren[i].resolve( project );
240 
241  if ( mChildren[i].layer )
242  {
243  connect( mChildren[i].layer, &QgsMapLayer::repaintRequested, this, &QgsMapLayer::triggerRepaint, Qt::UniqueConnection );
244 
245  // group layer inherits first valid child layer's crs
246  if ( !crs().isValid() )
247  {
248  setCrs( mChildren[i].layer->crs() );
249  mDataProvider->setCrs( crs() );
250  }
251  }
252  }
254 }
255 
256 void QgsGroupLayer::setChildLayers( const QList< QgsMapLayer * > &layers )
257 {
258  const QList< QgsMapLayer * > currentLayers = _qgis_listRefToRaw( mChildren );
259  for ( QgsMapLayer *layer : layers )
260  {
261  if ( !currentLayers.contains( layer ) )
262  {
263  connect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapLayer::triggerRepaint, Qt::UniqueConnection );
264  }
265  }
266  for ( QgsMapLayer *layer : currentLayers )
267  {
268  if ( !layers.contains( layer ) )
269  {
270  disconnect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapLayer::triggerRepaint );
271  }
272  }
273  mChildren = _qgis_listRawToRef( layers );
274 
275  // group layer inherits first valid child layer's crs
276  for ( const QgsMapLayer *layer : layers )
277  {
278  if ( layer->isValid() && layer->crs().isValid( ) )
279  {
280  setCrs( layer->crs() );
281  mDataProvider->setCrs( crs() );
282  break;
283  }
284  }
285 
286  triggerRepaint();
287 }
288 
289 QList< QgsMapLayer * > QgsGroupLayer::childLayers() const
290 {
291  return _qgis_listRefToRaw( mChildren );
292 }
293 
295 {
296  return mPaintEffect.get();
297 }
298 
300 {
301  mPaintEffect.reset( effect );
302 }
303 
304 //
305 // QgsGroupLayerDataProvider
306 //
308 QgsGroupLayerDataProvider::QgsGroupLayerDataProvider(
309  const ProviderOptions &options,
310  QgsDataProvider::ReadFlags flags )
311  : QgsDataProvider( QString(), options, flags )
312 {}
313 
314 void QgsGroupLayerDataProvider::setCrs( const QgsCoordinateReferenceSystem &crs )
315 {
316  mCrs = crs;
317 }
318 
320 {
321  return mCrs;
322 }
323 
324 QString QgsGroupLayerDataProvider::name() const
325 {
326  return QStringLiteral( "annotation" );
327 }
328 
329 QString QgsGroupLayerDataProvider::description() const
330 {
331  return QString();
332 }
333 
334 QgsRectangle QgsGroupLayerDataProvider::extent() const
335 {
336  return QgsRectangle();
337 }
338 
339 bool QgsGroupLayerDataProvider::isValid() const
340 {
341  return true;
342 }
344 
QgsGroupLayer::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &context) override
Sets the coordinate transform context to transformContext.
Definition: qgsgrouplayer.cpp:73
QgsMapLayer::willBeDeleted
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QgsMapLayer::resolveReferences
virtual void resolveReferences(QgsProject *project)
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects.
Definition: qgsmaplayer.cpp:772
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:57
QgsDataProvider::ProviderOptions
Setting options for creating vector data providers.
Definition: qgsdataprovider.h:107
QgsPainting::BlendMode
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:49
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsDataProvider
Abstract base class for spatial data provider implementations.
Definition: qgsdataprovider.h:40
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsMapLayer::opacity
double opacity
Definition: qgsmaplayer.h:82
QgsMapLayer::clone
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
QgsMapLayer::blendMode
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
Definition: qgsmaplayer.cpp:320
QgsMapLayer::mReadFlags
QgsMapLayer::ReadFlags mReadFlags
Read flags. It's up to the subclass to respect these when restoring state from XML.
Definition: qgsmaplayer.h:1987
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsGroupLayer::setPaintEffect
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the renderer.
Definition: qgsgrouplayer.cpp:299
QgsMapLayerType
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:46
QgsGroupLayer::readXml
bool readXml(const QDomNode &layerNode, QgsReadWriteContext &context) override
Called by readLayerXML(), used by children to read state specific to them from project files.
Definition: qgsgrouplayer.cpp:82
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsGroupLayer
A map layer which consists of a set of child layers, where all component layers are rendered as a sin...
Definition: qgsgrouplayer.h:41
qgspainteffectregistry.h
QgsMapLayer::setBlendMode
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
Definition: qgsmaplayer.cpp:310
QgsMapLayer::isValid
bool isValid
Definition: qgsmaplayer.h:81
QgsMapLayerRef
_LayerRef< QgsMapLayer > QgsMapLayerRef
Definition: qgsmaplayerref.h:295
qgspainteffect.h
QgsGroupLayer::htmlMetadata
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
Definition: qgsgrouplayer.cpp:220
QgsPaintEffectRegistry::defaultStack
static QgsPaintEffect * defaultStack()
Returns a new effect stack consisting of a sensible selection of default effects.
Definition: qgspainteffectregistry.cpp:114
QgsGroupLayer::resolveReferences
void resolveReferences(QgsProject *project) override
Resolve references to other layers (kept as layer IDs after reading XML) into layer objects.
Definition: qgsgrouplayer.cpp:234
QgsGroupLayer::paintEffect
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the group layer.
Definition: qgsgrouplayer.cpp:294
QgsMapLayer::setCrs
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Definition: qgsmaplayer.cpp:937
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsGroupLayer::createMapRenderer
QgsMapLayerRenderer * createMapRenderer(QgsRenderContext &rendererContext) override
Returns new instance of QgsMapLayerRenderer that will be used for rendering of given context.
Definition: qgsgrouplayer.cpp:63
QgsMapLayer::mShouldValidateCrs
bool mShouldValidateCrs
true if the layer's CRS should be validated and invalid CRSes are not permitted.
Definition: qgsmaplayer.h:1994
QgsGroupLayer::extent
QgsRectangle extent() const override
Returns the extent of the layer.
Definition: qgsgrouplayer.cpp:68
QgsGroupLayer::LayerOptions
Setting options for loading group layers.
Definition: qgsgrouplayer.h:51
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:103
QgsMapLayer::Rendering
@ Rendering
Rendering: scale visibility, simplify method, opacity.
Definition: qgsmaplayer.h:170
QgsMapLayerRenderer
Base class for utility classes that encapsulate information necessary for rendering of map layers.
Definition: qgsmaplayerrenderer.h:54
qgsmaplayerlistutils_p.h
QgsGroupLayer::writeXml
bool writeXml(QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context) const override
Called by writeLayerXML(), used by children to write state specific to them to project files.
Definition: qgsgrouplayer.cpp:114
qgsmaplayerfactory.h
qgsapplication.h
QgsPainting::getBlendModeEnum
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
QgsGroupLayerRenderer
Implementation of threaded rendering for group layers.
Definition: qgsgrouplayerrenderer.h:43
QgsMapLayer::triggerRepaint
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
Definition: qgsmaplayer.cpp:2114
QgsMapLayer::FlagDontResolveLayers
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:640
QgsMapLayerFactory::typeToString
static QString typeToString(QgsMapLayerType type)
Converts a map layer type to a string value.
Definition: qgsmaplayerfactory.cpp:51
QgsMapLayer::metadata
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
QgsPaintEffectRegistry::isDefaultStack
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
Definition: qgspainteffectregistry.cpp:134
QgsMapLayer::mValid
bool mValid
Indicates if the layer is valid and can be drawn.
Definition: qgsmaplayer.h:1938
QgsGroupLayer::~QgsGroupLayer
~QgsGroupLayer() override
Definition: qgsgrouplayer.cpp:47
qgsgrouplayer.h
QgsMapLayerType::GroupLayer
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
QgsMapLayer::repaintRequested
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
qgsmaplayerutils.h
QgsPainting::getCompositionMode
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
QgsMapLayer::setOpacity
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
Definition: qgsmaplayer.cpp:325
qgspainting.h
qgscoordinatetransform.h
QgsGroupLayer::writeSymbology
bool writeSymbology(QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &, StyleCategories categories=AllStyleCategories) const override
Write the style for the layer into the document provided.
Definition: qgsgrouplayer.cpp:141
QgsMapLayerUtils::combinedExtent
static QgsRectangle combinedExtent(const QList< QgsMapLayer * > &layers, const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &transformContext)
Returns the combined extent of a list of layers.
Definition: qgsmaplayerutils.cpp:30
QgsGroupLayer::childLayers
QList< QgsMapLayer * > childLayers() const
Returns the child layers contained by the group.
Definition: qgsgrouplayer.cpp:289
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsRectangle::toString
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
Definition: qgsrectangle.cpp:127
qgsvectorlayer.h
QgsGroupLayer::setChildLayers
void setChildLayers(const QList< QgsMapLayer * > &layers)
Sets the child layers contained by the group.
Definition: qgsgrouplayer.cpp:256
QgsApplication::paintEffectRegistry
static QgsPaintEffectRegistry * paintEffectRegistry()
Returns the application's paint effect registry, used for managing paint effects.
Definition: qgsapplication.cpp:2315
QgsGroupLayer::dataProvider
QgsDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
Definition: qgsgrouplayer.cpp:210
QgsGroupLayer::clone
QgsGroupLayer * clone() const override
Returns a new instance equivalent to this one except for the id which is still unique.
Definition: qgsgrouplayer.cpp:53
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
qgsgrouplayerrenderer.h
QgsMapLayer::invalidateWgs84Extent
void invalidateWgs84Extent()
Invalidates the WGS84 extent.
Definition: qgsmaplayer.cpp:2294
QgsPaintEffect
Base class for visual effects which can be applied to QPicture drawings.
Definition: qgspainteffect.h:52
QgsMapLayer::Symbology
@ Symbology
Symbology.
Definition: qgsmaplayer.h:161
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:76
QgsGroupLayer::LayerOptions::transformContext
QgsCoordinateTransformContext transformContext
Coordinate transform context.
Definition: qgsgrouplayer.h:64
QgsDataProvider::ProviderOptions::transformContext
QgsCoordinateTransformContext transformContext
Coordinate transform context.
Definition: qgsdataprovider.h:113
qgsmaplayerref.h
QgsMapLayer::project
QgsProject * project() const
Returns the parent project if this map layer is added to a project.
Definition: qgsmaplayer.cpp:2237
QgsGroupLayer::readSymbology
bool readSymbology(const QDomNode &node, QString &errorMessage, QgsReadWriteContext &context, StyleCategories categories=AllStyleCategories) override
Read the symbology for the current layer from the DOM node supplied.
Definition: qgsgrouplayer.cpp:171
QgsGroupLayer::QgsGroupLayer
QgsGroupLayer(const QString &name, const QgsGroupLayer::LayerOptions &options)
Constructor for a new QgsGroupLayer with the specified layer name.
Definition: qgsgrouplayer.cpp:32
qgsmessagelog.h