QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgslayertreemapcanvasbridge.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayertreemapcanvasbridge.cpp
3 --------------------------------------
4 Date : May 2014
5 Copyright : (C) 2014 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 "qgslayertree.h"
19#include "qgslayertreeutils.h"
20#include "qgsmaplayer.h"
21#include "qgsvectorlayer.h"
22#include "qgsmapcanvas.h"
24#include "qgsproject.h"
25#include "qgssettings.h"
26#include "qgsgui.h"
27
29 : QObject( parent )
30 , mRoot( root )
31 , mCanvas( canvas )
32 , mPendingCanvasUpdate( false )
33 , mAutoSetupOnFirstLayer( true )
34 , mHasLayersLoaded( !root->findLayers().isEmpty() )
35{
36 connect( root, &QgsLayerTreeGroup::customPropertyChanged, this, &QgsLayerTreeMapCanvasBridge::nodeCustomPropertyChanged );
37 connect( root, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeMapCanvasBridge::nodeVisibilityChanged );
38 connect( root, &QgsLayerTree::layerOrderChanged, this, &QgsLayerTreeMapCanvasBridge::deferredSetCanvasLayers );
39
40 connect( QgsProject::instance(), &QgsProject::layersAdded, this, &QgsLayerTreeMapCanvasBridge::layersAdded );
41
43}
44
46{
47 QList<QgsMapLayer *> canvasLayers, overviewLayers, allLayerOrder;
48
49 if ( mRoot->hasCustomLayerOrder() )
50 {
51 const QList<QgsMapLayer *> customOrderLayers = mRoot->customLayerOrder();
52 for ( const QgsMapLayer *layer : customOrderLayers )
53 {
54 QgsLayerTreeLayer *nodeLayer = mRoot->findLayer( layer->id() );
55 if ( nodeLayer )
56 {
57 if ( !nodeLayer->layer()->isSpatial() )
58 continue;
59
60 allLayerOrder << nodeLayer->layer();
61 if ( nodeLayer->isVisible() )
62 canvasLayers << nodeLayer->layer();
63 if ( nodeLayer->customProperty( QStringLiteral( "overview" ), 0 ).toInt() )
64 overviewLayers << nodeLayer->layer();
65 }
66 }
67 }
68 else
69 {
70 setCanvasLayers( mRoot, canvasLayers, overviewLayers, allLayerOrder );
71 }
72
73 const QList<QgsLayerTreeLayer *> layerNodes = mRoot->findLayers();
74 int currentSpatialLayerCount = 0;
75 int currentValidSpatialLayerCount = 0;
76 for ( QgsLayerTreeLayer *layerNode : layerNodes )
77 {
78 if ( layerNode->layer() && layerNode->layer()->isSpatial() )
79 {
80 currentSpatialLayerCount++;
81 if ( layerNode->layer()->isValid() )
82 currentValidSpatialLayerCount++;
83 }
84 }
85
86 const bool firstLayers = mAutoSetupOnFirstLayer && !mHasLayersLoaded && currentSpatialLayerCount != 0;
87 const bool firstValidLayers = mAutoSetupOnFirstLayer && !mHasValidLayersLoaded && currentValidSpatialLayerCount != 0;
88
89 mCanvas->setLayers( canvasLayers );
90 if ( mOverviewCanvas )
91 mOverviewCanvas->setLayers( overviewLayers );
92
93 if ( firstValidLayers )
94 {
95 // if we are moving from zero to non-zero layers, let's zoom to those data (only consider valid layers here!)
96 mCanvas->zoomToProjectExtent();
97 }
98
99 if ( !mFirstCRS.isValid() )
100 {
101 // find out what is the first used CRS in case we may need to turn on OTF projections later
102 for ( const QgsLayerTreeLayer *layerNode : layerNodes )
103 {
104 if ( layerNode->layer() && layerNode->layer()->crs().isValid() )
105 {
106 mFirstCRS = layerNode->layer()->crs();
107 break;
108 }
109 }
110 }
111
112 if ( mFirstCRS.isValid() && firstLayers )
113 {
114 const QgsGui::ProjectCrsBehavior projectCrsBehavior = QgsSettings().enumValue( QStringLiteral( "/projections/newProjectCrsBehavior" ), QgsGui::UseCrsOfFirstLayerAdded, QgsSettings::App );
115 switch ( projectCrsBehavior )
116 {
118 {
119 const bool planimetric = QgsSettings().value( QStringLiteral( "measure/planimetric" ), true, QgsSettings::Core ).toBool();
120 // Only adjust ellipsoid to CRS if it's not set to planimetric
121 QgsProject::instance()->setCrs( mFirstCRS, !planimetric );
122 break;
123 }
124
126 break;
127 }
128 }
129
130 mHasLayersLoaded = currentSpatialLayerCount;
131 mHasValidLayersLoaded = currentValidSpatialLayerCount;
132 if ( currentSpatialLayerCount == 0 )
133 mFirstCRS = QgsCoordinateReferenceSystem();
134
135 mPendingCanvasUpdate = false;
136
137 emit canvasLayersChanged( canvasLayers );
138}
139
140void QgsLayerTreeMapCanvasBridge::setCanvasLayers( QgsLayerTreeNode *node, QList<QgsMapLayer *> &canvasLayers, QList<QgsMapLayer *> &overviewLayers, QList<QgsMapLayer *> &allLayers )
141{
142 if ( QgsLayerTree::isLayer( node ) )
143 {
144 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
145 if ( nodeLayer->layer() && nodeLayer->layer()->isSpatial() )
146 {
147 allLayers << nodeLayer->layer();
148 if ( nodeLayer->isVisible() )
149 canvasLayers << nodeLayer->layer();
150 if ( nodeLayer->customProperty( QStringLiteral( "overview" ), 0 ).toInt() )
151 overviewLayers << nodeLayer->layer();
152 }
153 }
154
155 const QList<QgsLayerTreeNode *> children = node->children();
156 for ( QgsLayerTreeNode *child : children )
157 {
158 if ( QgsLayerTreeGroup *group = QgsLayerTree::toGroup( node ) )
159 {
160 if ( QgsGroupLayer *groupLayer = group->groupLayer() )
161 {
162 canvasLayers << groupLayer;
163 continue;
164 }
165 }
166 setCanvasLayers( child, canvasLayers, overviewLayers, allLayers );
167 }
168}
169
170void QgsLayerTreeMapCanvasBridge::deferredSetCanvasLayers()
171{
172 if ( mPendingCanvasUpdate )
173 return;
174
175 mPendingCanvasUpdate = true;
176 QMetaObject::invokeMethod( this, "setCanvasLayers", Qt::QueuedConnection );
177}
178
179void QgsLayerTreeMapCanvasBridge::nodeVisibilityChanged()
180{
181 deferredSetCanvasLayers();
182}
183
184void QgsLayerTreeMapCanvasBridge::nodeCustomPropertyChanged( QgsLayerTreeNode *node, const QString &key )
185{
186 Q_UNUSED( node )
187 if ( key == QLatin1String( "overview" ) )
188 deferredSetCanvasLayers();
189}
190
191void QgsLayerTreeMapCanvasBridge::layersAdded( const QList<QgsMapLayer *> &layers )
192{
193 for ( QgsMapLayer *l : layers )
194 {
195 if ( l )
196 {
197 connect( l, &QgsMapLayer::dataSourceChanged, this, [ this, l ]
198 {
199 if ( l->isValid() && l->isSpatial() && mAutoSetupOnFirstLayer && !mHasValidLayersLoaded )
200 {
201 mHasValidLayersLoaded = true;
202 // if we are moving from zero valid layers to non-zero VALID layers, let's zoom to those data
203 mCanvas->zoomToProjectExtent();
204 }
205 } );
206 }
207 }
208}
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
A map layer which consists of a set of child layers, where all component layers are rendered as a sin...
Definition: qgsgrouplayer.h:42
ProjectCrsBehavior
Defines the behavior to use when setting the CRS for a newly created project.
Definition: qgsgui.h:67
@ UseCrsOfFirstLayerAdded
Set the project CRS to the CRS of the first layer added to a new project.
Definition: qgsgui.h:68
@ UsePresetCrs
Always set new projects to use a preset default CRS.
Definition: qgsgui.h:69
Layer tree group node serves as a container for layers and further groups.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
Layer tree node points to a map layer.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
Q_INVOKABLE void setCanvasLayers()
force update of canvas layers from the layer tree. Normally this should not be needed to be called.
void canvasLayersChanged(const QList< QgsMapLayer * > &layers)
Emitted when the set of layers (or order of layers) visible in the canvas changes.
QgsLayerTreeMapCanvasBridge(QgsLayerTree *root, QgsMapCanvas *canvas, QObject *parent SIP_TRANSFERTHIS=nullptr)
Constructor: does not take ownership of the layer tree nor canvas.
This class is a base class for nodes in a layer tree.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well)
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file.
void customPropertyChanged(QgsLayerTreeNode *node, const QString &key)
Emitted when a custom property of a node within the tree has been changed or removed.
void visibilityChanged(QgsLayerTreeNode *node)
Emitted when check state of a node within the tree has been changed.
Namespace with helper functions for layer tree operations.
Definition: qgslayertree.h:33
bool hasCustomLayerOrder() const
Determines if the layer order should be derived from the layer tree or if a custom override order sha...
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
void layerOrderChanged()
Emitted when the layer order has changed.
QList< QgsMapLayer * > customLayerOrder() const
The order in which layers will be rendered on the canvas.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
void zoomToProjectExtent()
Zoom to the full extent the project associated with this canvas.
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of layers that should be shown in the canvas.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
void setLayers(const QList< QgsMapLayer * > &layers)
updates layer set for overview
void setCrs(const QgsCoordinateReferenceSystem &crs, bool adjustEllipsoid=false)
Sets the project's native coordinate reference system.
Definition: qgsproject.cpp:869
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
void layersAdded(const QList< QgsMapLayer * > &layers)
Emitted when one or more layers were added to the registry.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
Definition: qgssettings.h:284