1 /***************************************************************************
2 qgslayertreeviewindicatorprovider.cpp - QgsLayerTreeViewIndicatorProvider
3
4 ---------------------
5 begin : 17.10.2018
6 copyright : (C) 2018 by Alessandro Pasotti
7 email : elpaso@itopen.it
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16 #include "qgslayertreeviewindicatorprovider.h"
17
18 #include "qgslayertree.h"
19 #include "qgslayertreemodel.h"
20 #include "qgslayertreeutils.h"
21 #include "qgslayertreeview.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsrasterlayer.h"
24 #include "qgspointcloudlayer.h"
25 #include "qgsmeshlayer.h"
26 #include "qgisapp.h"
27 #include "qgsapplication.h"
28
QgsLayerTreeViewIndicatorProvider(QgsLayerTreeView * view)29 QgsLayerTreeViewIndicatorProvider::QgsLayerTreeViewIndicatorProvider( QgsLayerTreeView *view )
30 : QObject( view )
31 , mLayerTreeView( view )
32 {
33
34 QgsLayerTree *tree = mLayerTreeView->layerTreeModel()->rootGroup();
35 onAddedChildren( tree, 0, tree->children().count() - 1 );
36
37 connect( tree, &QgsLayerTree::addedChildren, this, &QgsLayerTreeViewIndicatorProvider::onAddedChildren );
38 connect( tree, &QgsLayerTree::willRemoveChildren, this, &QgsLayerTreeViewIndicatorProvider::onWillRemoveChildren );
39 }
40
onAddedChildren(QgsLayerTreeNode * node,int indexFrom,int indexTo)41 void QgsLayerTreeViewIndicatorProvider::onAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
42 {
43 // recursively populate indicators
44 QList<QgsLayerTreeNode *> children = node->children();
45 for ( int i = indexFrom; i <= indexTo; ++i )
46 {
47 QgsLayerTreeNode *childNode = children[i];
48
49 if ( QgsLayerTree::isGroup( childNode ) )
50 {
51 onAddedChildren( childNode, 0, childNode->children().count() - 1 );
52 }
53 else if ( QgsLayerTree::isLayer( childNode ) )
54 {
55 if ( QgsLayerTreeLayer *layerNode = qobject_cast< QgsLayerTreeLayer * >( childNode ) )
56 {
57 if ( layerNode->layer() )
58 {
59 connectSignals( layerNode->layer() );
60 addOrRemoveIndicator( childNode, layerNode->layer() );
61 }
62 else
63 {
64 // wait for layer to be loaded (e.g. when loading project, first the tree is loaded, afterwards the references to layers are resolved)
65 connect( layerNode, &QgsLayerTreeLayer::layerLoaded, this, &QgsLayerTreeViewIndicatorProvider::onLayerLoaded );
66 }
67 }
68 }
69 }
70 }
71
onWillRemoveChildren(QgsLayerTreeNode * node,int indexFrom,int indexTo)72 void QgsLayerTreeViewIndicatorProvider::onWillRemoveChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
73 {
74 // recursively call disconnect signals
75
76 QList<QgsLayerTreeNode *> children = node->children();
77 for ( int i = indexFrom; i <= indexTo; ++i )
78 {
79 QgsLayerTreeNode *childNode = children[i];
80
81 if ( QgsLayerTree::isGroup( childNode ) )
82 {
83 onWillRemoveChildren( childNode, 0, childNode->children().count() - 1 );
84 }
85 else if ( QgsLayerTree::isLayer( childNode ) )
86 {
87 QgsLayerTreeLayer *childLayerNode = QgsLayerTree::toLayer( childNode );
88 if ( QgsLayerTreeUtils::countMapLayerInTree( mLayerTreeView->layerTreeModel()->rootGroup(), childLayerNode->layer() ) == 1 )
89 disconnectSignals( childLayerNode->layer() );
90 }
91 }
92 }
93
onLayerLoaded()94 void QgsLayerTreeViewIndicatorProvider::onLayerLoaded()
95 {
96
97 QgsLayerTreeLayer *layerNode = qobject_cast<QgsLayerTreeLayer *>( sender() );
98 if ( !layerNode )
99 return;
100
101 if ( !( qobject_cast<QgsVectorLayer *>( layerNode->layer() ) ||
102 qobject_cast<QgsRasterLayer *>( layerNode->layer() ) ||
103 qobject_cast<QgsMeshLayer *>( layerNode->layer() ) ||
104 qobject_cast<QgsPointCloudLayer *>( layerNode->layer() ) ) )
105 return;
106
107 if ( QgsMapLayer *mapLayer = layerNode->layer() )
108 {
109 if ( mapLayer )
110 {
111 connectSignals( mapLayer );
112 addOrRemoveIndicator( layerNode, mapLayer );
113 }
114 }
115 }
116
onLayerChanged()117 void QgsLayerTreeViewIndicatorProvider::onLayerChanged()
118 {
119 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
120 if ( !layer )
121 return;
122
123 updateLayerIndicator( layer );
124 }
125
connectSignals(QgsMapLayer * layer)126 void QgsLayerTreeViewIndicatorProvider::connectSignals( QgsMapLayer *layer )
127 {
128 if ( !( qobject_cast<QgsVectorLayer *>( layer )
129 || qobject_cast<QgsRasterLayer *>( layer )
130 || qobject_cast<QgsMeshLayer *>( layer )
131 || qobject_cast<QgsPointCloudLayer *>( layer ) ) )
132 return;
133
134 QgsMapLayer *mapLayer = layer;
135 connect( mapLayer, &QgsMapLayer::dataSourceChanged, this, &QgsLayerTreeViewIndicatorProvider::onLayerChanged );
136 }
137
disconnectSignals(QgsMapLayer * layer)138 void QgsLayerTreeViewIndicatorProvider::disconnectSignals( QgsMapLayer *layer )
139 {
140 if ( !( qobject_cast<QgsVectorLayer *>( layer )
141 || qobject_cast<QgsRasterLayer *>( layer )
142 || qobject_cast<QgsMeshLayer *>( layer )
143 || qobject_cast<QgsPointCloudLayer *>( layer ) ) )
144 return;
145 QgsMapLayer *mapLayer = layer;
146 disconnect( mapLayer, &QgsMapLayer::dataSourceChanged, this, &QgsLayerTreeViewIndicatorProvider::onLayerChanged );
147 }
148
updateLayerIndicator(QgsMapLayer * layer)149 void QgsLayerTreeViewIndicatorProvider::updateLayerIndicator( QgsMapLayer *layer )
150 {
151 // walk the tree and find layer node that needs to be updated
152 const QList<QgsLayerTreeLayer *> layerNodes = mLayerTreeView->layerTreeModel()->rootGroup()->findLayers();
153 for ( QgsLayerTreeLayer *node : layerNodes )
154 {
155 if ( node->layer() && node->layer() == layer )
156 {
157 addOrRemoveIndicator( node, layer );
158 break;
159 }
160 }
161 }
162
newIndicator(QgsMapLayer * layer)163 std::unique_ptr< QgsLayerTreeViewIndicator > QgsLayerTreeViewIndicatorProvider::newIndicator( QgsMapLayer *layer )
164 {
165 std::unique_ptr< QgsLayerTreeViewIndicator > indicator = std::make_unique< QgsLayerTreeViewIndicator >( this );
166 indicator->setIcon( QgsApplication::getThemeIcon( iconName( layer ) ) );
167 indicator->setToolTip( tooltipText( layer ) );
168 connect( indicator.get(), &QgsLayerTreeViewIndicator::clicked, this, &QgsLayerTreeViewIndicatorProvider::onIndicatorClicked );
169 mIndicators.insert( indicator.get() );
170 return indicator;
171 }
172
addOrRemoveIndicator(QgsLayerTreeNode * node,QgsMapLayer * layer)173 void QgsLayerTreeViewIndicatorProvider::addOrRemoveIndicator( QgsLayerTreeNode *node, QgsMapLayer *layer )
174 {
175
176 if ( acceptLayer( layer ) )
177 {
178 const QList<QgsLayerTreeViewIndicator *> nodeIndicators = mLayerTreeView->indicators( node );
179
180 // maybe the indicator exists already
181 for ( QgsLayerTreeViewIndicator *indicator : nodeIndicators )
182 {
183 if ( mIndicators.contains( indicator ) )
184 {
185 // Update just in case ...
186 indicator->setToolTip( tooltipText( layer ) );
187 indicator->setIcon( QgsApplication::getThemeIcon( iconName( layer ) ) );
188 return;
189 }
190 }
191
192 // it does not exist: need to create a new one
193 mLayerTreeView->addIndicator( node, newIndicator( layer ).release() );
194 }
195 else
196 {
197 const QList<QgsLayerTreeViewIndicator *> nodeIndicators = mLayerTreeView->indicators( node );
198
199 // there may be existing indicator we need to get rid of
200 for ( QgsLayerTreeViewIndicator *indicator : nodeIndicators )
201 {
202 if ( mIndicators.contains( indicator ) )
203 {
204 mLayerTreeView->removeIndicator( node, indicator );
205 indicator->deleteLater();
206 return;
207 }
208 }
209
210 // no indicator was there before, nothing to do
211 }
212 }
213
214