QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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
23#include "moc_qgslayertreefilterproxymodel.cpp"
24
26 : QSortFilterProxyModel( parent )
27{
28 connect( QgsProject::instance(), &QgsProject::readProject, this, [this] // skip-keyword-check
29 {
30 beginResetModel();
31 endResetModel();
32 } );
33}
34
35void QgsLayerTreeFilterProxyModel::setCheckedLayers( const QList<QgsMapLayer *> layers )
36{
37 // do not use invalidate() since it's not the filter which changes but the data
38 beginResetModel();
39 mCheckedLayers = layers;
40 endResetModel();
41}
42
44{
45 Q_UNUSED( parent )
46 return 1;
47}
48
49Qt::ItemFlags QgsLayerTreeFilterProxyModel::flags( const QModelIndex &idx ) const
50{
51 if ( idx.column() == 0 )
52 {
53 return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
54 }
55 return Qt::NoItemFlags;
56}
57
58QModelIndex QgsLayerTreeFilterProxyModel::index( int row, int column, const QModelIndex &parent ) const
59{
60 QModelIndex newIndex = QSortFilterProxyModel::index( row, 0, parent );
61 if ( column == 0 )
62 return newIndex;
63
64 return createIndex( row, column, newIndex.internalId() );
65}
66
67QModelIndex QgsLayerTreeFilterProxyModel::parent( const QModelIndex &child ) const
68{
69 return QSortFilterProxyModel::parent( createIndex( child.row(), 0, child.internalId() ) );
70}
71
72QModelIndex QgsLayerTreeFilterProxyModel::sibling( int row, int column, const QModelIndex &idx ) const
73{
74 const QModelIndex parent = idx.parent();
75 return index( row, column, parent );
76}
77
79{
80 QgsLayerTreeNode *node = nullptr;
81 if ( idx.column() == 0 )
82 {
83 node = mLayerTreeModel->index2node( mapToSource( idx ) );
84 }
85
86 if ( !node || !QgsLayerTree::isLayer( node ) )
87 return nullptr;
88
89 return QgsLayerTree::toLayer( node )->layer();
90}
91
92void QgsLayerTreeFilterProxyModel::setFilterText( const QString &filterText )
93{
94 if ( filterText == mFilterText )
95 return;
96
97 mFilterText = filterText;
98 invalidateFilter();
99}
100
102{
103 return mLayerTreeModel;
104}
105
107{
108 mLayerTreeModel = layerTreeModel;
109 QSortFilterProxyModel::setSourceModel( layerTreeModel );
110}
111
113{
114 return mShowPrivateLayers;
115}
116
118{
119 if ( showPrivate == mShowPrivateLayers )
120 return;
121
122 mShowPrivateLayers = showPrivate;
123 invalidateFilter();
124}
125
127{
128 mFilters = filters;
129 invalidateFilter();
130}
131
132bool QgsLayerTreeFilterProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
133{
134 QgsLayerTreeNode *node = mLayerTreeModel->index2node( mLayerTreeModel->index( sourceRow, 0, sourceParent ) );
135 return nodeShown( node );
136}
137
139{
140 return mCheckedLayers.contains( layer );
141}
142
144{
145 if ( checked )
146 {
147 mCheckedLayers << layer;
148 }
149 else
150 {
151 mCheckedLayers.removeAll( layer );
152 }
153}
154
155void QgsLayerTreeFilterProxyModel::setLayerCheckedPrivate( QgsMapLayer *layer, bool checked )
156{
157 if ( checked && isLayerChecked( layer ) )
158 return;
159 if ( !checked && !isLayerChecked( layer ) )
160 return;
161
162 QgsLayerTreeNode *node = mLayerTreeModel->rootGroup()->findLayer( layer );
163 const QModelIndex index = mapFromSource( mLayerTreeModel->node2index( node ) );
164
165 setLayerChecked( layer, checked );
166
167 emit dataChanged( index, index );
168}
169
170bool QgsLayerTreeFilterProxyModel::layerShown( QgsMapLayer *layer ) const
171{
172 Q_UNUSED( layer )
173 return true;
174}
175
177{
178 if ( !node )
179 return false;
180 if ( node->nodeType() == QgsLayerTreeNode::NodeGroup )
181 {
182 const auto constChildren = node->children();
183 for ( QgsLayerTreeNode *child : constChildren )
184 {
185 if ( nodeShown( child ) )
186 {
187 return true;
188 }
189 }
190 return false;
191 }
192 else
193 {
194 QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
195 if ( !layer )
196 return false;
197 if ( !mFilterText.isEmpty() && !layer->name().contains( mFilterText, Qt::CaseInsensitive ) )
198 return false;
199 if ( ! mShowPrivateLayers && layer->flags().testFlag( QgsMapLayer::LayerFlag::Private ) )
200 {
201 return false;
202 }
203 if ( !QgsMapLayerProxyModel::layerMatchesFilters( layer, mFilters ) )
204 return false;
205
206 return layerShown( layer );
207 }
208}
209
210QVariant QgsLayerTreeFilterProxyModel::data( const QModelIndex &idx, int role ) const
211{
212 if ( idx.column() == 0 )
213 {
214 if ( role == Qt::CheckStateRole )
215 {
216 QgsMapLayer *layer = mapLayer( idx );
217 if ( layer )
218 {
219 if ( isLayerChecked( layer ) )
220 {
221 return Qt::Checked;
222 }
223 else
224 {
225 return Qt::Unchecked;
226 }
227 }
228 else
229 {
230 // i.e. this is a group, analyze its children
231 bool hasChecked = false, hasUnchecked = false;
232 int n;
233 for ( n = 0; !hasChecked || !hasUnchecked; n++ )
234 {
235 const QVariant v = data( index( n, 0, idx ), role );
236 if ( !v.isValid() )
237 break;
238
239 switch ( v.toInt() )
240 {
241 case Qt::PartiallyChecked:
242 // parent of partially checked child shared state
243 return Qt::PartiallyChecked;
244
245 case Qt::Checked:
246 hasChecked = true;
247 break;
248
249 case Qt::Unchecked:
250 hasUnchecked = true;
251 break;
252 }
253 }
254
255 // unchecked leaf
256 if ( n == 0 )
257 return Qt::Unchecked;
258
259 // both
260 if ( hasChecked && hasUnchecked )
261 return Qt::PartiallyChecked;
262
263 if ( hasChecked )
264 return Qt::Checked;
265
266 Q_ASSERT( hasUnchecked );
267 return Qt::Unchecked;
268 }
269 }
270 else
271 {
272 return mLayerTreeModel->data( mapToSource( idx ), role );
273 }
274 }
275 return QVariant();
276}
277
278bool QgsLayerTreeFilterProxyModel::setData( const QModelIndex &index, const QVariant &value, int role )
279{
280 if ( index.column() == 0 )
281 {
282 if ( role == Qt::CheckStateRole )
283 {
284 int i = 0;
285 for ( i = 0; ; i++ )
286 {
287 const QModelIndex child = QgsLayerTreeFilterProxyModel::index( i, 0, index );
288 if ( !child.isValid() )
289 break;
290
291 setData( child, value, role );
292 }
293
294 if ( i == 0 )
295 {
296 QgsMapLayer *layer = mapLayer( index );
297 if ( !layer )
298 {
299 return false;
300 }
301 if ( value.toInt() == Qt::Checked )
302 setLayerCheckedPrivate( layer, true );
303 else if ( value.toInt() == Qt::Unchecked )
304 setLayerCheckedPrivate( layer, false );
305 else
306 Q_ASSERT( false ); // expected checked or unchecked
307 }
308 emit dataChanged( index, index );
309 return true;
310 }
311
312 return mLayerTreeModel->setData( mapToSource( index ), value, role );
313 }
314
315 return false;
316}
QFlags< LayerFilter > LayerFilters
Definition qgis.h:227
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
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,...
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
QVariant data(const QModelIndex &index, int role) const override
QgsLayerTreeFilterProxyModel(QObject *parent=nullptr)
Constructor.
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.
A model representing the layer tree, including layers and groups of layers.
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...
QgsLayerTree * rootGroup() const
Returns pointer to the root node of the layer tree. Always a non nullptr value.
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:80
QString name
Definition qgsmaplayer.h:84
QgsMapLayer::LayerFlags flags
Definition qgsmaplayer.h:96
@ 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.