1 /***************************************************************************
2 qgsmaplayerproxymodel.cpp
3 --------------------------------------
4 Date : 01.04.2014
5 Copyright : (C) 2014 Denis Rouzaud
6 Email : denis.rouzaud@gmail.com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgsmaplayerproxymodel.h"
17 #include "qgsmaplayermodel.h"
18 #include "qgsmaplayer.h"
19 #include "qgsproject.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsrasterlayer.h"
22 #include "qgsmeshlayer.h"
23 #include "qgsvectordataprovider.h"
24 #include "qgsrasterdataprovider.h"
25 #include "qgsmeshdataprovider.h"
26
QgsMapLayerProxyModel(QObject * parent)27 QgsMapLayerProxyModel::QgsMapLayerProxyModel( QObject *parent )
28 : QSortFilterProxyModel( parent )
29 , mFilters( All )
30 , mModel( new QgsMapLayerModel( parent ) )
31 {
32 setSourceModel( mModel );
33 setDynamicSortFilter( true );
34 setSortLocaleAware( true );
35 setFilterCaseSensitivity( Qt::CaseInsensitive );
36 sort( 0 );
37 }
38
setFilters(Filters filters)39 QgsMapLayerProxyModel *QgsMapLayerProxyModel::setFilters( Filters filters )
40 {
41 mFilters = filters;
42 invalidateFilter();
43 return this;
44 }
45
layerMatchesFilters(const QgsMapLayer * layer,const Filters & filters)46 bool QgsMapLayerProxyModel::layerMatchesFilters( const QgsMapLayer *layer, const Filters &filters )
47 {
48 if ( filters.testFlag( All ) )
49 return true;
50
51 // layer type
52 if ( ( filters.testFlag( RasterLayer ) && layer->type() == QgsMapLayerType::RasterLayer ) ||
53 ( filters.testFlag( VectorLayer ) && layer->type() == QgsMapLayerType::VectorLayer ) ||
54 ( filters.testFlag( MeshLayer ) && layer->type() == QgsMapLayerType::MeshLayer ) ||
55 ( filters.testFlag( VectorTileLayer ) && layer->type() == QgsMapLayerType::VectorTileLayer ) ||
56 ( filters.testFlag( PluginLayer ) && layer->type() == QgsMapLayerType::PluginLayer ) )
57 return true;
58
59 // geometry type
60 bool detectGeometry = filters.testFlag( NoGeometry ) ||
61 filters.testFlag( PointLayer ) ||
62 filters.testFlag( LineLayer ) ||
63 filters.testFlag( PolygonLayer ) ||
64 filters.testFlag( HasGeometry );
65 if ( detectGeometry && layer->type() == QgsMapLayerType::VectorLayer )
66 {
67 if ( const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( layer ) )
68 {
69 if ( filters.testFlag( HasGeometry ) && vl->isSpatial() )
70 return true;
71 if ( filters.testFlag( NoGeometry ) && vl->geometryType() == QgsWkbTypes::NullGeometry )
72 return true;
73 if ( filters.testFlag( PointLayer ) && vl->geometryType() == QgsWkbTypes::PointGeometry )
74 return true;
75 if ( filters.testFlag( LineLayer ) && vl->geometryType() == QgsWkbTypes::LineGeometry )
76 return true;
77 if ( filters.testFlag( PolygonLayer ) && vl->geometryType() == QgsWkbTypes::PolygonGeometry )
78 return true;
79 }
80 }
81
82 return false;
83 }
84
setLayerWhitelist(const QList<QgsMapLayer * > & layers)85 void QgsMapLayerProxyModel::setLayerWhitelist( const QList<QgsMapLayer *> &layers )
86 {
87 setLayerAllowlist( layers );
88 }
89
setLayerAllowlist(const QList<QgsMapLayer * > & layers)90 void QgsMapLayerProxyModel::setLayerAllowlist( const QList<QgsMapLayer *> &layers )
91 {
92 if ( mLayerAllowlist == layers )
93 return;
94
95 mLayerAllowlist = layers;
96 invalidateFilter();
97 }
98
setExceptedLayerList(const QList<QgsMapLayer * > & exceptList)99 void QgsMapLayerProxyModel::setExceptedLayerList( const QList<QgsMapLayer *> &exceptList )
100 {
101 if ( mExceptList == exceptList )
102 return;
103
104 mExceptList = exceptList;
105 invalidateFilter();
106 }
107
setExceptedLayerIds(const QStringList & ids)108 void QgsMapLayerProxyModel::setExceptedLayerIds( const QStringList &ids )
109 {
110 mExceptList.clear();
111
112 const auto constIds = ids;
113 for ( const QString &id : constIds )
114 {
115 QgsMapLayer *l = QgsProject::instance()->mapLayer( id );
116 if ( l )
117 mExceptList << l;
118 }
119 invalidateFilter();
120 }
121
exceptedLayerIds() const122 QStringList QgsMapLayerProxyModel::exceptedLayerIds() const
123 {
124 QStringList lst;
125
126 const auto constMExceptList = mExceptList;
127 for ( QgsMapLayer *l : constMExceptList )
128 lst << l->id();
129
130 return lst;
131 }
132
setExcludedProviders(const QStringList & providers)133 void QgsMapLayerProxyModel::setExcludedProviders( const QStringList &providers )
134 {
135 mExcludedProviders = providers;
136 invalidateFilter();
137 }
138
acceptsLayer(QgsMapLayer * layer) const139 bool QgsMapLayerProxyModel::acceptsLayer( QgsMapLayer *layer ) const
140 {
141 if ( !layer )
142 return false;
143
144 if ( !mLayerAllowlist.isEmpty() && !mLayerAllowlist.contains( layer ) )
145 return false;
146
147 if ( mExceptList.contains( layer ) )
148 return false;
149
150 if ( layer->dataProvider() && mExcludedProviders.contains( layer->providerType() ) )
151 return false;
152
153 if ( mFilters.testFlag( WritableLayer ) && layer->readOnly() )
154 return false;
155
156 if ( !layer->name().contains( mFilterString, Qt::CaseInsensitive ) )
157 return false;
158
159 return layerMatchesFilters( layer, mFilters );
160 }
161
setFilterString(const QString & filter)162 void QgsMapLayerProxyModel::setFilterString( const QString &filter )
163 {
164 mFilterString = filter;
165 invalidateFilter();
166 }
167
filterAcceptsRow(int source_row,const QModelIndex & source_parent) const168 bool QgsMapLayerProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
169 {
170 if ( mFilters.testFlag( All ) && mExceptList.isEmpty() && mLayerAllowlist.isEmpty() && mExcludedProviders.isEmpty() && mFilterString.isEmpty() )
171 return true;
172
173 QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
174
175 if ( sourceModel()->data( index, QgsMapLayerModel::EmptyRole ).toBool()
176 || sourceModel()->data( index, QgsMapLayerModel::AdditionalRole ).toBool() )
177 return true;
178
179 return acceptsLayer( static_cast<QgsMapLayer *>( index.internalPointer() ) );
180 }
181
lessThan(const QModelIndex & left,const QModelIndex & right) const182 bool QgsMapLayerProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
183 {
184 // empty row is always first
185 if ( sourceModel()->data( left, QgsMapLayerModel::EmptyRole ).toBool() )
186 return true;
187 else if ( sourceModel()->data( right, QgsMapLayerModel::EmptyRole ).toBool() )
188 return false;
189
190 // additional rows are always last
191 bool leftAdditional = sourceModel()->data( left, QgsMapLayerModel::AdditionalRole ).toBool();
192 bool rightAdditional = sourceModel()->data( right, QgsMapLayerModel::AdditionalRole ).toBool();
193
194 if ( leftAdditional && !rightAdditional )
195 return false;
196 else if ( rightAdditional && !leftAdditional )
197 return true;
198
199 // default mode is alphabetical order
200 QString leftStr = sourceModel()->data( left ).toString();
201 QString rightStr = sourceModel()->data( right ).toString();
202 return QString::localeAwareCompare( leftStr, rightStr ) < 0;
203 }
204