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