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