QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgslayertreefilterproxymodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreefilterproxymodel.cpp
3 
4  ---------------------
5  begin : 05.06.2020
6  copyright : (C) 2020 by Denis Rouzaud
7  email : [email protected]
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 
18 
19 #include "qgslayertree.h"
20 #include "qgslayertreemodel.h"
21 
23  : QSortFilterProxyModel( parent )
24 {
25  connect( QgsProject::instance(), &QgsProject::readProject, this, [ = ]
26  {
27  beginResetModel();
28  endResetModel();
29  } );
30 }
31 
32 void QgsLayerTreeFilterProxyModel::setCheckedLayers( const QList<QgsMapLayer *> layers )
33 {
34  // do not use invalidate() since it's not the filter which changes but the data
35  beginResetModel();
36  mCheckedLayers = layers;
37  endResetModel();
38 }
39 
40 int QgsLayerTreeFilterProxyModel::columnCount( const QModelIndex &parent ) const
41 {
42  Q_UNUSED( parent )
43  return 1;
44 }
45 
46 Qt::ItemFlags QgsLayerTreeFilterProxyModel::flags( const QModelIndex &idx ) const
47 {
48  if ( idx.column() == 0 )
49  {
50  return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
51  }
52  return Qt::NoItemFlags;
53 }
54 
55 QModelIndex QgsLayerTreeFilterProxyModel::index( int row, int column, const QModelIndex &parent ) const
56 {
57  QModelIndex newIndex = QSortFilterProxyModel::index( row, 0, parent );
58  if ( column == 0 )
59  return newIndex;
60 
61  return createIndex( row, column, newIndex.internalId() );
62 }
63 
64 QModelIndex QgsLayerTreeFilterProxyModel::parent( const QModelIndex &child ) const
65 {
66  return QSortFilterProxyModel::parent( createIndex( child.row(), 0, child.internalId() ) );
67 }
68 
69 QModelIndex QgsLayerTreeFilterProxyModel::sibling( int row, int column, const QModelIndex &idx ) const
70 {
71  QModelIndex parent = idx.parent();
72  return index( row, column, parent );
73 }
74 
75 QgsMapLayer *QgsLayerTreeFilterProxyModel::mapLayer( const QModelIndex &idx ) const
76 {
77  QgsLayerTreeNode *node = nullptr;
78  if ( idx.column() == 0 )
79  {
80  node = mLayerTreeModel->index2node( mapToSource( idx ) );
81  }
82 
83  if ( !node || !QgsLayerTree::isLayer( node ) )
84  return nullptr;
85 
86  return QgsLayerTree::toLayer( node )->layer();
87 }
88 
89 void QgsLayerTreeFilterProxyModel::setFilterText( const QString &filterText )
90 {
91  if ( filterText == mFilterText )
92  return;
93 
94  mFilterText = filterText;
95  invalidateFilter();
96 }
97 
99 {
100  return mLayerTreeModel;
101 }
102 
104 {
105  mLayerTreeModel = layerTreeModel;
106  QSortFilterProxyModel::setSourceModel( layerTreeModel );
107 }
108 
109 void QgsLayerTreeFilterProxyModel::setFilters( const QgsMapLayerProxyModel::Filters &filters )
110 {
111  mFilters = filters;
112  invalidateFilter();
113 }
114 
115 bool QgsLayerTreeFilterProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
116 {
117  QgsLayerTreeNode *node = mLayerTreeModel->index2node( mLayerTreeModel->index( sourceRow, 0, sourceParent ) );
118  return nodeShown( node );
119 }
120 
122 {
123  return mCheckedLayers.contains( layer );
124 }
125 
127 {
128  if ( checked )
129  {
130  mCheckedLayers << layer;
131  }
132  else
133  {
134  mCheckedLayers.removeAll( layer );
135  }
136 }
137 
138 void QgsLayerTreeFilterProxyModel::setLayerCheckedPrivate( QgsMapLayer *layer, bool checked )
139 {
140  if ( checked && isLayerChecked( layer ) )
141  return;
142  if ( !checked && !isLayerChecked( layer ) )
143  return;
144 
145  QgsLayerTreeNode *node = mLayerTreeModel->rootGroup()->findLayer( layer );
146  QModelIndex index = mapFromSource( mLayerTreeModel->node2index( node ) );
147 
148  setLayerChecked( layer, checked );
149 
150  emit dataChanged( index, index );
151 }
152 
153 bool QgsLayerTreeFilterProxyModel::layerShown( QgsMapLayer *layer ) const
154 {
155  Q_UNUSED( layer )
156  return true;
157 }
158 
159 bool QgsLayerTreeFilterProxyModel::nodeShown( QgsLayerTreeNode *node ) const
160 {
161  if ( !node )
162  return false;
163  if ( node->nodeType() == QgsLayerTreeNode::NodeGroup )
164  {
165  const auto constChildren = node->children();
166  for ( QgsLayerTreeNode *child : constChildren )
167  {
168  if ( nodeShown( child ) )
169  {
170  return true;
171  }
172  }
173  return false;
174  }
175  else
176  {
177  QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
178  if ( !layer )
179  return false;
180  if ( !mFilterText.isEmpty() && !layer->name().contains( mFilterText, Qt::CaseInsensitive ) )
181  return false;
182  if ( !QgsMapLayerProxyModel::layerMatchesFilters( layer, mFilters ) )
183  return false;
184 
185  return layerShown( layer );
186  }
187 }
188 
189 QVariant QgsLayerTreeFilterProxyModel::data( const QModelIndex &idx, int role ) const
190 {
191  if ( idx.column() == 0 )
192  {
193  if ( role == Qt::CheckStateRole )
194  {
195  QgsMapLayer *layer = mapLayer( idx );
196  if ( layer )
197  {
198  if ( isLayerChecked( layer ) )
199  {
200  return Qt::Checked;
201  }
202  else
203  {
204  return Qt::Unchecked;
205  }
206  }
207  else
208  {
209  // i.e. this is a group, analyze its children
210  bool hasChecked = false, hasUnchecked = false;
211  int n;
212  for ( n = 0; !hasChecked || !hasUnchecked; n++ )
213  {
214  QVariant v = data( index( n, 0, idx ), role );
215  if ( !v.isValid() )
216  break;
217 
218  switch ( v.toInt() )
219  {
220  case Qt::PartiallyChecked:
221  // parent of partially checked child shared state
222  return Qt::PartiallyChecked;
223 
224  case Qt::Checked:
225  hasChecked = true;
226  break;
227 
228  case Qt::Unchecked:
229  hasUnchecked = true;
230  break;
231  }
232  }
233 
234  // unchecked leaf
235  if ( n == 0 )
236  return Qt::Unchecked;
237 
238  // both
239  if ( hasChecked && hasUnchecked )
240  return Qt::PartiallyChecked;
241 
242  if ( hasChecked )
243  return Qt::Checked;
244 
245  Q_ASSERT( hasUnchecked );
246  return Qt::Unchecked;
247  }
248  }
249  else
250  {
251  return mLayerTreeModel->data( mapToSource( idx ), role );
252  }
253  }
254  return QVariant();
255 }
256 
257 bool QgsLayerTreeFilterProxyModel::setData( const QModelIndex &index, const QVariant &value, int role )
258 {
259  if ( index.column() == 0 )
260  {
261  if ( role == Qt::CheckStateRole )
262  {
263  int i = 0;
264  for ( i = 0; ; i++ )
265  {
266  QModelIndex child = QgsLayerTreeFilterProxyModel::index( i, 0, index );
267  if ( !child.isValid() )
268  break;
269 
270  setData( child, value, role );
271  }
272 
273  if ( i == 0 )
274  {
275  QgsMapLayer *layer = mapLayer( index );
276  if ( !layer )
277  {
278  return false;
279  }
280  if ( value.toInt() == Qt::Checked )
281  setLayerCheckedPrivate( layer, true );
282  else if ( value.toInt() == Qt::Unchecked )
283  setLayerCheckedPrivate( layer, false );
284  else
285  Q_ASSERT( false ); // expected checked or unchecked
286  }
287  emit dataChanged( index, index );
288  return true;
289  }
290 
291  return mLayerTreeModel->setData( mapToSource( index ), value, role );
292  }
293 
294  return false;
295 }
QgsLayerTreeNode::NodeGroup
@ NodeGroup
Container of other groups and layers.
Definition: qgslayertreenode.h:101
QgsLayerTreeFilterProxyModel::setData
virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override
Definition: qgslayertreefilterproxymodel.cpp:257
QgsLayerTreeGroup::findLayer
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
Definition: qgslayertreegroup.cpp:195
QgsLayerTreeNode
This class is a base class for nodes in a layer tree.
Definition: qgslayertreenode.h:75
QgsLayerTreeModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: qgslayertreemodel.cpp:99
QgsMapLayerProxyModel::layerMatchesFilters
static bool layerMatchesFilters(const QgsMapLayer *layer, const Filters &filters)
Returns if the layer matches the given filters.
Definition: qgsmaplayerproxymodel.cpp:46
QgsLayerTreeFilterProxyModel::data
virtual QVariant data(const QModelIndex &index, int role) const override
Definition: qgslayertreefilterproxymodel.cpp:189
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
QgsLayerTreeFilterProxyModel::parent
QModelIndex parent(const QModelIndex &child) const override
Definition: qgslayertreefilterproxymodel.cpp:64
QgsProject::readProject
void readProject(const QDomDocument &)
Emitted when a project is being read.
QgsLayerTree::toLayer
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
QgsLayerTreeModel
The QgsLayerTreeModel class is model implementation for Qt item views framework.
Definition: qgslayertreemodel.h:54
QgsLayerTreeFilterProxyModel::setLayerChecked
virtual void setLayerChecked(QgsMapLayer *layer, bool checked)
This will set if the layer is checked or not.
Definition: qgslayertreefilterproxymodel.cpp:126
QgsLayerTreeNode::nodeType
NodeType nodeType() const
Find out about type of the node. It is usually shorter to use convenience functions from QgsLayerTree...
Definition: qgslayertreenode.h:108
QgsLayerTreeFilterProxyModel::setFilters
void setFilters(const QgsMapLayerProxyModel::Filters &filters)
Defines the type layers (vector, raster, etc) shown in the tree If the list is empty,...
Definition: qgslayertreefilterproxymodel.cpp:109
QgsLayerTreeFilterProxyModel::isLayerChecked
virtual bool isLayerChecked(QgsMapLayer *layer) const
Returns if the layer is checked or not.
Definition: qgslayertreefilterproxymodel.cpp:121
QgsLayerTreeModel::node2index
QModelIndex node2index(QgsLayerTreeNode *node) const
Returns index for a given node. If the node does not belong to the layer tree, the result is undefine...
Definition: qgslayertreemodel.cpp:456
QgsLayerTreeFilterProxyModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: qgslayertreefilterproxymodel.cpp:55
QgsLayerTreeFilterProxyModel::layerTreeModel
QgsLayerTreeModel * layerTreeModel() const
Rerturns the layer tree model.
Definition: qgslayertreefilterproxymodel.cpp:98
QgsLayerTreeFilterProxyModel::flags
virtual Qt::ItemFlags flags(const QModelIndex &idx) const override
Definition: qgslayertreefilterproxymodel.cpp:46
QgsLayerTreeFilterProxyModel::setLayerTreeModel
void setLayerTreeModel(QgsLayerTreeModel *layerTreeModel)
Sets the layer tree model.
Definition: qgslayertreefilterproxymodel.cpp:103
QgsLayerTreeFilterProxyModel::setCheckedLayers
void setCheckedLayers(const QList< QgsMapLayer * > layers)
Initialize the list of checked layers.
Definition: qgslayertreefilterproxymodel.cpp:32
QgsLayerTreeFilterProxyModel::filterAcceptsRow
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Definition: qgslayertreefilterproxymodel.cpp:115
QgsLayerTreeFilterProxyModel::sibling
QModelIndex sibling(int row, int column, const QModelIndex &idx) const override
Definition: qgslayertreefilterproxymodel.cpp:69
QgsLayerTreeLayer::layer
QgsMapLayer * layer() const
Returns the map layer associated with this node.
Definition: qgslayertreelayer.h:74
qgslayertree.h
QgsLayerTreeModel::rootGroup
QgsLayerTree * rootGroup() const
Returns pointer to the root node of the layer tree. Always a non nullptr value.
Definition: qgslayertreemodel.cpp:519
QgsLayerTreeModel::index2node
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Returns layer tree node for given index.
Definition: qgslayertreemodel.cpp:63
QgsLayerTree::isLayer
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
QgsLayerTreeFilterProxyModel::columnCount
virtual int columnCount(const QModelIndex &parent) const override
Definition: qgslayertreefilterproxymodel.cpp:40
QgsMapLayer
Base class for all map layer types.
Definition: qgsmaplayer.h:83
QgsLayerTreeNode::children
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
Definition: qgslayertreenode.h:112
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:86
QgsLayerTreeFilterProxyModel::QgsLayerTreeFilterProxyModel
QgsLayerTreeFilterProxyModel(QObject *parent=nullptr)
Constructor.
Definition: qgslayertreefilterproxymodel.cpp:22
qgslayertreemodel.h
QgsLayerTreeModel::setData
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Definition: qgslayertreemodel.cpp:392
QgsLayerTreeFilterProxyModel::mapLayer
QgsMapLayer * mapLayer(const QModelIndex &idx) const
Returns the map layer at a given index.
Definition: qgslayertreefilterproxymodel.cpp:75
QgsLayerTreeModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Definition: qgslayertreemodel.cpp:158
qgslayertreefilterproxymodel.h
QgsLayerTreeFilterProxyModel::setFilterText
virtual void setFilterText(const QString &filterText=QString())
Sets the filter text to search for a layer in the tree.
Definition: qgslayertreefilterproxymodel.cpp:89