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