QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsprovidersublayermodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprovidersublayermodel.cpp
3  ----------------------
4  begin : June 2021
5  copyright : (C) 2021 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
20 #include "qgsiconutils.h"
21 #include <QLocale>
22 
24  : QAbstractItemModel( parent )
25 {
26 
27 }
28 
29 void QgsProviderSublayerModel::setSublayerDetails( const QList<QgsProviderSublayerDetails> &details )
30 {
31  // remove layers which don't exist in new list
32  for ( int i = mSublayers.count() - 1; i >= 0; --i )
33  {
34  if ( !details.contains( mSublayers.at( i ) ) )
35  {
36  beginRemoveRows( QModelIndex(), i, i );
37  mSublayers.removeAt( i );
38  endRemoveRows();
39  }
40  }
41 
42  // and add new layers which exist only in new list
43  for ( const QgsProviderSublayerDetails &layer : details )
44  {
45  if ( !mSublayers.contains( layer ) )
46  {
47  beginInsertRows( QModelIndex(), mSublayers.count(), mSublayers.count() );
48  mSublayers.append( layer );
49  endInsertRows();
50  }
51  }
52 }
53 
54 QList<QgsProviderSublayerDetails> QgsProviderSublayerModel::sublayerDetails() const
55 {
56  return mSublayers;
57 }
58 
60 {
61  if ( index.isValid() && index.row() < mSublayers.count() )
62  {
63  return mSublayers.at( index.row() );
64  }
65 
67 }
68 
70 {
71  if ( index.isValid() && index.row() >= mSublayers.count() && index.row() < mSublayers.count() + mNonLayerItems.count() )
72  {
73  return mNonLayerItems.at( index.row() - mSublayers.count() );
74  }
75 
77 }
78 
80 {
81  beginInsertRows( QModelIndex(), mSublayers.count() + mNonLayerItems.count(), mSublayers.count() + mNonLayerItems.count() );
82  mNonLayerItems.append( item );
83  endInsertRows();
84 }
85 
86 QModelIndex QgsProviderSublayerModel::index( int row, int column, const QModelIndex &parent ) const
87 {
88  if ( column < 0 || column >= columnCount() )
89  {
90  //column out of bounds
91  return QModelIndex();
92  }
93 
94  if ( !parent.isValid() && row >= 0 && row < mSublayers.size() + mNonLayerItems.size() )
95  {
96  //return an index for the sublayer at this position
97  return createIndex( row, column );
98  }
99 
100  //only top level supported for now
101  return QModelIndex();
102 }
103 
104 QModelIndex QgsProviderSublayerModel::parent( const QModelIndex &index ) const
105 {
106  Q_UNUSED( index )
107 
108  //all items are top level for now
109  return QModelIndex();
110 }
111 
112 int QgsProviderSublayerModel::columnCount( const QModelIndex &parent ) const
113 {
114  Q_UNUSED( parent )
115  return static_cast< int >( Column::Description ) + 1;
116 }
117 
118 int QgsProviderSublayerModel::rowCount( const QModelIndex &parent ) const
119 {
120  if ( !parent.isValid() )
121  {
122  return mSublayers.size() + mNonLayerItems.size();
123  }
124  else
125  {
126  //no children for now
127  return 0;
128  }
129 }
130 
131 QVariant QgsProviderSublayerModel::data( const QModelIndex &index, int role ) const
132 {
133  if ( !index.isValid() )
134  return QVariant();
135 
136  if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
137  return QVariant();
138 
139  if ( index.row() < mSublayers.count() )
140  {
141  const QgsProviderSublayerDetails details = mSublayers.at( index.row() );
142 
143  switch ( role )
144  {
145  case Qt::DisplayRole:
146  case Qt::ToolTipRole:
147  case Qt::EditRole:
148  {
149  switch ( static_cast< Column >( index.column() ) )
150  {
152  return details.name();
154  {
155  switch ( details.type() )
156  {
158  {
159  QString count;
160  if ( details.featureCount() == static_cast< long long >( Qgis::FeatureCountState::Uncounted )
161  || details.featureCount() == static_cast< long long >( Qgis::FeatureCountState::UnknownCount ) )
162  count = tr( "Uncounted" );
163  else
164  count = QLocale().toString( details.featureCount() );
165 
166  if ( !details.description().isEmpty() )
167  return QStringLiteral( "%1 - %2 (%3)" ).arg( details.description(),
168  QgsWkbTypes::displayString( details.wkbType() ),
169  count );
170  else
171  return QStringLiteral( "%2 (%3)" ).arg(
172  QgsWkbTypes::displayString( details.wkbType() ),
173  count );
174  }
175 
182  return details.description();
183  }
184  break;
185 
186  }
187  }
188  return details.name();
189 
190  }
191 
192  case Qt::DecorationRole:
193  {
194  if ( index.column() == 0 )
195  return details.type() == QgsMapLayerType::VectorLayer
196  ? ( details.wkbType() != QgsWkbTypes::Unknown ? QgsIconUtils::iconForWkbType( details.wkbType() ) : QVariant() )
197  : QgsIconUtils::iconForLayerType( details.type() );
198  else
199  return QVariant();
200  }
201 
202  case static_cast< int >( Role::IsNonLayerItem ):
203  return false;
204 
205  case static_cast< int >( Role::ProviderKey ):
206  return details.providerKey();
207 
208  case static_cast< int >( Role::LayerType ):
209  return static_cast< int >( details.type() );
210 
211  case static_cast< int >( Role::Uri ):
212  return details.uri();
213 
214  case static_cast< int >( Role::Name ):
215  return details.name();
216 
217  case static_cast< int >( Role::Description ):
218  return details.description();
219 
220  case static_cast< int >( Role::Path ):
221  return details.path();
222 
223  case static_cast< int >( Role::FeatureCount ):
224  return details.featureCount();
225 
226  case static_cast< int >( Role::WkbType ):
227  return details.wkbType();
228 
229  case static_cast< int >( Role::GeometryColumnName ):
230  return details.geometryColumnName();
231 
232  case static_cast< int >( Role::LayerNumber ):
233  return details.layerNumber();
234 
235  case static_cast< int >( Role::Flags ):
236  return static_cast< int >( details.flags() );
237 
238  default:
239  return QVariant();
240  }
241  }
242  else
243  {
244  const NonLayerItem details = mNonLayerItems.at( index.row() - mSublayers.count() );
245 
246  switch ( role )
247  {
248  case Qt::DisplayRole:
249  case Qt::ToolTipRole:
250  case Qt::EditRole:
251  {
252  switch ( static_cast< Column >( index.column() ) )
253  {
255  return details.name();
257  return details.description();
258  }
259  return QVariant();
260  }
261 
262  case Qt::DecorationRole:
263  {
264  if ( index.column() == 0 )
265  return details.icon();
266  else
267  return QVariant();
268  }
269 
270  case static_cast< int >( Role::IsNonLayerItem ):
271  return true;
272 
273  case static_cast< int >( Role::Uri ):
274  return details.uri();
275 
276  case static_cast< int >( Role::Name ):
277  return details.name();
278 
279  case static_cast< int >( Role::Description ):
280  return details.description();
281 
282  case static_cast< int >( Role::NonLayerItemType ):
283  return details.type();
284 
285  default:
286  return QVariant();
287  }
288  }
289 }
290 
291 QVariant QgsProviderSublayerModel::headerData( int section, Qt::Orientation orientation, int role ) const
292 {
293  switch ( orientation )
294  {
295  case Qt::Vertical:
296  break;
297  case Qt::Horizontal:
298  {
299  switch ( role )
300  {
301  case Qt::DisplayRole:
302  case Qt::ToolTipRole:
303  {
304  switch ( static_cast< Column>( section ) )
305  {
307  return tr( "Item" );
309  return tr( "Description" );
310  }
311  break;
312  }
313  }
314  break;
315  }
316  }
317  return QVariant();
318 }
319 
320 
321 //
322 // QgsProviderSublayerModel::NonLayerItem
323 //
324 
326 {
327  return mType;
328 }
329 
331 {
332  mType = type;
333 }
334 
336 {
337  return mName;
338 }
339 
341 {
342  mName = name;
343 }
344 
346 {
347  return mDescription;
348 }
349 
351 {
352  mDescription = description;
353 }
354 
356 {
357  return mUri;
358 }
359 
361 {
362  mUri = uri;
363 }
364 
366 {
367  return mIcon;
368 }
369 
371 {
372  mIcon = icon;
373 }
374 
376 {
377  return mType == other.mType
378  && mName == other.mName
379  && mDescription == other.mDescription
380  && mUri == other.mUri;
381 }
382 
384 {
385  return !( *this == other );
386 }
387 
388 //
389 // QgsProviderSublayerProxyModel
390 //
391 
393  : QSortFilterProxyModel( parent )
394 {
395  setDynamicSortFilter( true );
396  sort( 0 );
397 }
398 
399 bool QgsProviderSublayerProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
400 {
401  const QModelIndex sourceIndex = sourceModel()->index( source_row, 0, source_parent );
402 
403  if ( !mIncludeSystemTables && static_cast< Qgis::SublayerFlags >( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Flags ) ).toInt() ) & Qgis::SublayerFlag::SystemTable )
404  return false;
405 
406  if ( mFilterString.trimmed().isEmpty() )
407  return true;
408 
409  if ( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Name ) ).toString().contains( mFilterString, Qt::CaseInsensitive ) )
410  return true;
411 
412  if ( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Description ) ).toString().contains( mFilterString, Qt::CaseInsensitive ) )
413  return true;
414 
415  const QVariant wkbTypeVariant = sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::WkbType ) );
416  if ( wkbTypeVariant.isValid() )
417  {
418  const QgsWkbTypes::Type wkbType = static_cast< QgsWkbTypes::Type >( wkbTypeVariant.toInt() );
419  if ( QgsWkbTypes::displayString( wkbType ).contains( mFilterString, Qt::CaseInsensitive ) )
420  return true;
421  }
422 
423  return false;
424 }
425 
426 bool QgsProviderSublayerProxyModel::lessThan( const QModelIndex &source_left, const QModelIndex &source_right ) const
427 {
428  const bool leftIsNonLayer = sourceModel()->data( source_left, static_cast< int >( QgsProviderSublayerModel::Role::IsNonLayerItem ) ).toBool();
429  const bool rightIsNonLayer = sourceModel()->data( source_right, static_cast< int >( QgsProviderSublayerModel::Role::IsNonLayerItem ) ).toBool();
430 
431  if ( leftIsNonLayer && !rightIsNonLayer )
432  return true;
433  else if ( rightIsNonLayer && !leftIsNonLayer )
434  return false;
435 
436  const QString leftName = sourceModel()->data( source_left, static_cast< int >( QgsProviderSublayerModel::Role::Name ) ).toString();
437  const QString rightName = sourceModel()->data( source_right, static_cast< int >( QgsProviderSublayerModel::Role::Name ) ).toString();
438 
439  return QString::localeAwareCompare( leftName, rightName ) < 0;
440 }
441 
443 {
444  return mIncludeSystemTables;
445 }
446 
448 {
449  mIncludeSystemTables = include;
450  invalidateFilter();
451 }
452 
454 {
455  return mFilterString;
456 }
457 
459 {
460  mFilterString = filter;
461  invalidateFilter();
462 }
@ SystemTable
Sublayer is a system or internal table, which should be hidden by default.
static QIcon iconForWkbType(QgsWkbTypes::Type type)
Returns the icon for a vector layer whose geometry type is provided.
static QIcon iconForLayerType(QgsMapLayerType type)
Returns the default icon for the specified layer type.
Contains details about a sub layer available from a dataset.
QString description() const
Returns the layer's description.
QStringList path() const
Returns the path to the sublayer.
long long featureCount() const
Returns the layer's feature count.
int layerNumber() const
Returns the associated layer number, for providers which order sublayers.
QgsWkbTypes::Type wkbType() const
Returns the layer's WKB type, or QgsWkbTypes::Unknown if the WKB type is not application or unknown.
QString uri() const
Returns the layer's URI.
QgsMapLayerType type() const
Returns the layer type.
QString providerKey() const
Returns the associated data provider key.
QString geometryColumnName() const
Returns the layer's geometry column name, or an empty string if not applicable.
Qgis::SublayerFlags flags() const
Returns the layer's flags, which indicate properties of the layer.
QString name() const
Returns the layer's name.
Contains details for a non-sublayer item to include in a QgsProviderSublayerModel.
void setName(const QString &name)
Sets the item's name.
void setDescription(const QString &description)
Sets the item's description.
void setType(const QString &type)
Sets the item's type.
QString type() const
Returns the item's type.
QString uri() const
Returns the item's URI.
QString name() const
Returns the item's name.
QIcon icon() const
Returns the item's icon.
bool operator!=(const QgsProviderSublayerModel::NonLayerItem &other) const
void setUri(const QString &uri)
Set the item's uri.
bool operator==(const QgsProviderSublayerModel::NonLayerItem &other) const
QString description() const
Returns the item's description.
void setIcon(const QIcon &icon)
Sets the item's icon.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
QList< QgsProviderSublayerDetails > mSublayers
Sublayer list.
QList< QgsProviderSublayerDetails > sublayerDetails() const
Returns the sublayer details shown in the model.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role) const override
QgsProviderSublayerModel(QObject *parent=nullptr)
Constructor for QgsProviderSublayerModel, with the specified parent object.
QgsProviderSublayerDetails indexToSublayer(const QModelIndex &index) const
Returns the sublayer corresponding to the given index.
@ NonLayerItemType
Item type (for non-sublayer items)
@ IsNonLayerItem
true if item is a non-sublayer item (e.g. an embedded project)
@ FeatureCount
Feature count (for vector sublayers)
@ GeometryColumnName
Geometry column name (for vector sublayers)
@ Description
Layer description.
@ WkbType
WKB geometry type (for vector sublayers)
QgsProviderSublayerModel::NonLayerItem indexToNonLayerItem(const QModelIndex &index) const
Returns the non layer item corresponding to the given index.
void addNonLayerItem(const QgsProviderSublayerModel::NonLayerItem &item)
Adds a non-layer item (e.g.
void setSublayerDetails(const QList< QgsProviderSublayerDetails > &details)
Sets the sublayer details to show in the model.
QModelIndex parent(const QModelIndex &index) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
int rowCount(const QModelIndex &parent) const override
@ Description
Layer description.
QList< NonLayerItem > mNonLayerItems
Non layer item list.
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override
bool includeSystemTables() const
Returns true if system and internal tables will be shown in the model.
void setIncludeSystemTables(bool include)
Sets whether system and internal tables will be shown in the model.
QgsProviderSublayerProxyModel(QObject *parent=nullptr)
Constructor for QgsProviderSublayerProxyModel, with the specified parent object.
QString filterString() const
Returns the filter string used for filtering items in the model.
void setFilterString(const QString &filter)
Sets the filter string used for filtering items in the model.
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static QString displayString(Type type) SIP_HOLDGIL
Returns a non-translated display string type for a WKB type, e.g., the geometry name used in WKT geom...
@ Uncounted
Feature count not yet computed.
@ UnknownCount
Provider returned an unknown feature count.
@ PointCloudLayer
Added in 3.18.
@ MeshLayer
Added in 3.2.
@ VectorTileLayer
Added in 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.