QGIS API Documentation  3.23.0-Master (dd0cd13a00)
qgsbrowserproxymodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsbrowserproxymodel.cpp
3  ---------------------
4  begin : October 2018
5  copyright : (C) 2018 by Nyall Dawson
6  email : nyall dot dawson at gmail dot 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 "qgsbrowserproxymodel.h"
17 #include "qgsbrowsermodel.h"
18 #include "qgslayeritem.h"
19 #include "qgsdatacollectionitem.h"
20 
21 #include <QRegularExpression>
22 
24  : QSortFilterProxyModel( parent )
25 {
26  setDynamicSortFilter( true );
27  setSortRole( QgsBrowserModel::SortRole );
28  setSortCaseSensitivity( Qt::CaseInsensitive );
29  sort( 0 );
30 }
31 
33 {
34  mModel = model;
35  setSourceModel( model );
36 }
37 
38 QgsDataItem *QgsBrowserProxyModel::dataItem( const QModelIndex &index ) const
39 {
40  const QModelIndex sourceIndex = mapToSource( index );
41  return mModel ? mModel->dataItem( sourceIndex ) : nullptr;
42 }
43 
45 {
46  if ( mPatternSyntax == syntax )
47  return;
48  mPatternSyntax = syntax;
49  updateFilter();
50 }
51 
53 {
54  return mPatternSyntax;
55 }
56 
57 void QgsBrowserProxyModel::setFilterString( const QString &filter )
58 {
59  if ( mFilter == filter )
60  return;
61  mFilter = filter;
62  updateFilter();
63 }
64 
66 {
67  return mFilter;
68 }
69 
70 void QgsBrowserProxyModel::setFilterCaseSensitivity( Qt::CaseSensitivity sensitivity )
71 {
72  mCaseSensitivity = sensitivity;
73  updateFilter();
74 }
75 
76 Qt::CaseSensitivity QgsBrowserProxyModel::caseSensitivity() const
77 {
78  return mCaseSensitivity;
79 }
80 
81 void QgsBrowserProxyModel::updateFilter()
82 {
83  mREList.clear();
84  switch ( mPatternSyntax )
85  {
86  case Normal:
87  {
88  const QStringList filterParts = mFilter.split( '|' );
89  for ( const QString &f : filterParts )
90  {
91  const QRegularExpression rx( QRegularExpression::wildcardToRegularExpression( QStringLiteral( "*%1*" ).arg( f.trimmed() ) ),
92  mCaseSensitivity == Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption );
93  mREList.append( rx );
94  }
95  break;
96  }
97  case Wildcards:
98  {
99  const QStringList filterParts = mFilter.split( '|' );
100  for ( const QString &f : filterParts )
101  {
102  const QRegularExpression rx( QRegularExpression::wildcardToRegularExpression( f.trimmed() ),
103  mCaseSensitivity == Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption );
104  mREList.append( rx );
105  }
106  break;
107  }
108  case RegularExpression:
109  {
110  const QRegularExpression rx( mFilter.trimmed(), mCaseSensitivity == Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption );
111  mREList.append( rx );
112  break;
113  }
114  }
115  invalidateFilter();
116 }
117 
118 bool QgsBrowserProxyModel::filterAcceptsString( const QString &value ) const
119 {
120  for ( const QRegularExpression &rx : mREList )
121  {
122  if ( rx.match( value ).hasMatch() )
123  return true;
124  }
125 
126  return false;
127 }
128 
129 bool QgsBrowserProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
130 {
131  if ( ( mFilter.isEmpty() && !mFilterByLayerType && mHiddenDataItemsKeys.empty() && mShownDataItemsKeys.empty() ) || !mModel )
132  return true;
133 
134  const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
135  if ( !filterAcceptsProviderKey( sourceIndex ) || !filterRootAcceptsProviderKey( sourceIndex ) )
136  return false;
137 
138  if ( ! mShowLayers )
139  {
140  QgsDataItem *item = mModel->dataItem( sourceIndex );
141  if ( qobject_cast< QgsLayerItem * >( item ) )
142  {
143  return false;
144  }
145  }
146 
147  return filterAcceptsItem( sourceIndex ) || filterAcceptsAncestor( sourceIndex ) || filterAcceptsDescendant( sourceIndex );
148 }
149 
151 {
152  return mShowLayers;
153 }
154 
155 void QgsBrowserProxyModel::setShowLayers( bool showLayers )
156 {
157  mShowLayers = showLayers;
158 }
159 
161 {
162  return mLayerType;
163 }
164 
166 {
167  mLayerType = type;
168  invalidateFilter();
169 }
170 
171 void QgsBrowserProxyModel::setFilterByLayerType( bool filterByLayerType )
172 {
173  mFilterByLayerType = filterByLayerType;
174  invalidateFilter();
175 }
176 
177 bool QgsBrowserProxyModel::filterAcceptsAncestor( const QModelIndex &sourceIndex ) const
178 {
179  if ( !mModel )
180  return true;
181 
182  if ( mFilterByLayerType )
183  return false;
184 
185  const QModelIndex sourceParentIndex = mModel->parent( sourceIndex );
186  if ( !sourceParentIndex.isValid() )
187  return false;
188  if ( filterAcceptsItem( sourceParentIndex ) )
189  return true;
190 
191  return filterAcceptsAncestor( sourceParentIndex );
192 }
193 
194 bool QgsBrowserProxyModel::filterAcceptsDescendant( const QModelIndex &sourceIndex ) const
195 {
196  if ( !mModel )
197  return true;
198 
199  for ( int i = 0; i < mModel->rowCount( sourceIndex ); i++ )
200  {
201  const QModelIndex sourceChildIndex = mModel->index( i, 0, sourceIndex );
202  if ( filterAcceptsItem( sourceChildIndex ) )
203  return true;
204  if ( filterAcceptsDescendant( sourceChildIndex ) )
205  return true;
206  }
207  return false;
208 }
209 
210 bool QgsBrowserProxyModel::filterAcceptsItem( const QModelIndex &sourceIndex ) const
211 {
212  if ( !mModel )
213  return true;
214 
215  if ( mFilterByLayerType )
216  {
217  QgsDataItem *item = mModel->dataItem( sourceIndex );
218  if ( QgsLayerItem *layerItem = qobject_cast< QgsLayerItem * >( item ) )
219  {
220  if ( layerItem->mapLayerType() != mLayerType )
221  return false;
222  }
223  else if ( !qobject_cast< QgsDataCollectionItem * >( item ) )
224  return false;
225  }
226 
227  if ( !mFilter.isEmpty() )
228  {
229  //accept item if either displayed text or comment role matches string
230  const QString comment = mModel->data( sourceIndex, QgsBrowserModel::CommentRole ).toString();
231  return ( filterAcceptsString( mModel->data( sourceIndex, Qt::DisplayRole ).toString() )
232  || ( !comment.isEmpty() && filterAcceptsString( comment ) ) );
233  }
234 
235  return true;
236 }
237 
238 bool QgsBrowserProxyModel::filterAcceptsProviderKey( const QModelIndex &sourceIndex ) const
239 {
240  if ( !mModel )
241  return true;
242 
243  const QString providerKey = mModel->data( sourceIndex, QgsBrowserModel::ProviderKeyRole ).toString();
244  if ( providerKey.isEmpty() )
245  return true;
246 
247  return !mHiddenDataItemsKeys.contains( providerKey ) && ( mShownDataItemsKeys.isEmpty() || mShownDataItemsKeys.contains( providerKey ) );
248 }
249 
250 bool QgsBrowserProxyModel::filterRootAcceptsProviderKey( const QModelIndex &sourceIndex ) const
251 {
252  if ( !mModel )
253  return true;
254 
255  const QModelIndex sourceParentIndex = mModel->parent( sourceIndex );
256  if ( !sourceParentIndex.isValid() )
257  {
258  return filterAcceptsProviderKey( sourceIndex );
259  }
260 
261  return filterRootAcceptsProviderKey( sourceParentIndex );
262 }
263 
265 {
266  mHiddenDataItemsKeys = filter;
267  invalidateFilter();
268 }
269 
271 {
272  mShownDataItemsKeys = filter;
273  invalidateFilter();
274 }
275 
276 
277 bool QgsBrowserProxyModel::hasChildren( const QModelIndex &parent ) const
278 {
279  const bool isFertile { QSortFilterProxyModel::hasChildren( parent ) };
280  if ( isFertile && parent.isValid() )
281  {
282  QgsDataItem *item = dataItem( parent );
283  if ( ! mShowLayers )
284  {
285  return ! item->layerCollection();
286  }
287  // Hide everything below layers if filter is set
288  else if ( mFilterByLayerType && qobject_cast< QgsLayerItem * >( item ) )
289  {
290  return false;
291  }
292  }
293  return isFertile;
294 }
A model for showing available data sources and other items in a structured tree.
QgsDataItem * dataItem(const QModelIndex &idx) const
Returns the data item at the specified index, or nullptr if no item exists at the index.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex parent(const QModelIndex &index) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
@ CommentRole
Item comment.
@ ProviderKeyRole
Data item provider key that created the item, see QgsDataItem::providerKey()
@ SortRole
Custom sort role, see QgsDataItem::sortKey()
void setShowLayers(bool showLayers)
Sets show layers to showLayers.
FilterSyntax
Filter syntax options.
@ RegularExpression
Regular expression filtering.
@ Wildcards
Wildcard filtering.
@ Normal
Standard string filtering.
void setShownDataItemProviderKeyFilter(const QStringList &shownItemsFilter)
Sets a filter to show data items based on QgsDataItem::providerKey() associated with the item.
void setHiddenDataItemProviderKeyFilter(const QStringList &hiddenItemsFilter)
Sets a filter to hide data items based on QgsDataItem::providerKey() associated with the item.
void setFilterByLayerType(bool enabled)
Sets whether the model is filtered by map layer type.
bool hasChildren(const QModelIndex &parent=QModelIndex()) const override
void setFilterString(const QString &filter)
Sets the filter string to use when filtering items in the model.
QgsDataItem * dataItem(const QModelIndex &index) const
Returns the data item at the specified proxy index, or nullptr if no item exists at the index.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
void setFilterCaseSensitivity(Qt::CaseSensitivity sensitivity)
Sets whether item filtering should be case sensitive.
QString filterString() const
Returns the filter string used when filtering items in the model.
QgsBrowserProxyModel(QObject *parent=nullptr)
Constructor for QgsBrowserProxyModel, with the specified parent object.
void setFilterSyntax(FilterSyntax syntax)
Sets the filter syntax.
QgsMapLayerType layerType() const
Returns the layer type to filter the model by.
void setLayerType(QgsMapLayerType type)
Sets the layer type to filter the model by.
Qt::CaseSensitivity caseSensitivity() const
Returns whether item filtering is case sensitive.
bool filterByLayerType() const
Returns true if the model is filtered by map layer type.
bool showLayers() const
Returns true if layers must be shown, this flag is TRUE by default.
FilterSyntax filterSyntax() const
Returns the filter syntax.
void setBrowserModel(QgsBrowserModel *model)
Sets the underlying browser model.
QgsBrowserModel * mModel
Reference to associated browser model.
Base class for all items in the model.
Definition: qgsdataitem.h:46
virtual bool layerCollection() const
Returns true if the data item is a collection of layers The default implementation returns false,...
Item that represents a layer that can be opened with one of the providers.
Definition: qgslayeritem.h:30
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:47