QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 
183  return details.description();
184  }
185  break;
186 
187  }
188  }
189  return details.name();
190 
191  }
192 
193  case Qt::DecorationRole:
194  {
195  if ( index.column() == 0 )
196  return details.type() == QgsMapLayerType::VectorLayer
197  ? ( details.wkbType() != QgsWkbTypes::Unknown ? QgsIconUtils::iconForWkbType( details.wkbType() ) : QVariant() )
198  : QgsIconUtils::iconForLayerType( details.type() );
199  else
200  return QVariant();
201  }
202 
203  case static_cast< int >( Role::IsNonLayerItem ):
204  return false;
205 
206  case static_cast< int >( Role::ProviderKey ):
207  return details.providerKey();
208 
209  case static_cast< int >( Role::LayerType ):
210  return static_cast< int >( details.type() );
211 
212  case static_cast< int >( Role::Uri ):
213  return details.uri();
214 
215  case static_cast< int >( Role::Name ):
216  return details.name();
217 
218  case static_cast< int >( Role::Description ):
219  return details.description();
220 
221  case static_cast< int >( Role::Path ):
222  return details.path();
223 
224  case static_cast< int >( Role::FeatureCount ):
225  return details.featureCount();
226 
227  case static_cast< int >( Role::WkbType ):
228  return details.wkbType();
229 
230  case static_cast< int >( Role::GeometryColumnName ):
231  return details.geometryColumnName();
232 
233  case static_cast< int >( Role::LayerNumber ):
234  return details.layerNumber();
235 
236  case static_cast< int >( Role::Flags ):
237  return static_cast< int >( details.flags() );
238 
239  default:
240  return QVariant();
241  }
242  }
243  else
244  {
245  const NonLayerItem details = mNonLayerItems.at( index.row() - mSublayers.count() );
246 
247  switch ( role )
248  {
249  case Qt::DisplayRole:
250  case Qt::ToolTipRole:
251  case Qt::EditRole:
252  {
253  switch ( static_cast< Column >( index.column() ) )
254  {
256  return details.name();
258  return details.description();
259  }
260  return QVariant();
261  }
262 
263  case Qt::DecorationRole:
264  {
265  if ( index.column() == 0 )
266  return details.icon();
267  else
268  return QVariant();
269  }
270 
271  case static_cast< int >( Role::IsNonLayerItem ):
272  return true;
273 
274  case static_cast< int >( Role::Uri ):
275  return details.uri();
276 
277  case static_cast< int >( Role::Name ):
278  return details.name();
279 
280  case static_cast< int >( Role::Description ):
281  return details.description();
282 
283  case static_cast< int >( Role::NonLayerItemType ):
284  return details.type();
285 
286  default:
287  return QVariant();
288  }
289  }
290 }
291 
292 QVariant QgsProviderSublayerModel::headerData( int section, Qt::Orientation orientation, int role ) const
293 {
294  switch ( orientation )
295  {
296  case Qt::Vertical:
297  break;
298  case Qt::Horizontal:
299  {
300  switch ( role )
301  {
302  case Qt::DisplayRole:
303  case Qt::ToolTipRole:
304  {
305  switch ( static_cast< Column>( section ) )
306  {
308  return tr( "Item" );
310  return tr( "Description" );
311  }
312  break;
313  }
314  }
315  break;
316  }
317  }
318  return QVariant();
319 }
320 
321 
322 //
323 // QgsProviderSublayerModel::NonLayerItem
324 //
325 
327 {
328  return mType;
329 }
330 
332 {
333  mType = type;
334 }
335 
337 {
338  return mName;
339 }
340 
342 {
343  mName = name;
344 }
345 
347 {
348  return mDescription;
349 }
350 
352 {
353  mDescription = description;
354 }
355 
357 {
358  return mUri;
359 }
360 
362 {
363  mUri = uri;
364 }
365 
367 {
368  return mIcon;
369 }
370 
372 {
373  mIcon = icon;
374 }
375 
377 {
378  return mType == other.mType
379  && mName == other.mName
380  && mDescription == other.mDescription
381  && mUri == other.mUri;
382 }
383 
385 {
386  return !( *this == other );
387 }
388 
389 //
390 // QgsProviderSublayerProxyModel
391 //
392 
394  : QSortFilterProxyModel( parent )
395 {
396  setDynamicSortFilter( true );
397  sort( 0 );
398 }
399 
400 bool QgsProviderSublayerProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
401 {
402  const QModelIndex sourceIndex = sourceModel()->index( source_row, 0, source_parent );
403 
404  if ( !mIncludeSystemTables && static_cast< Qgis::SublayerFlags >( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Flags ) ).toInt() ) & Qgis::SublayerFlag::SystemTable )
405  return false;
406 
407  if ( mFilterString.trimmed().isEmpty() )
408  return true;
409 
410  if ( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Name ) ).toString().contains( mFilterString, Qt::CaseInsensitive ) )
411  return true;
412 
413  if ( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Description ) ).toString().contains( mFilterString, Qt::CaseInsensitive ) )
414  return true;
415 
416  const QVariant wkbTypeVariant = sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::WkbType ) );
417  if ( wkbTypeVariant.isValid() )
418  {
419  const QgsWkbTypes::Type wkbType = static_cast< QgsWkbTypes::Type >( wkbTypeVariant.toInt() );
420  if ( QgsWkbTypes::displayString( wkbType ).contains( mFilterString, Qt::CaseInsensitive ) )
421  return true;
422  }
423 
424  return false;
425 }
426 
427 bool QgsProviderSublayerProxyModel::lessThan( const QModelIndex &source_left, const QModelIndex &source_right ) const
428 {
429  const bool leftIsNonLayer = sourceModel()->data( source_left, static_cast< int >( QgsProviderSublayerModel::Role::IsNonLayerItem ) ).toBool();
430  const bool rightIsNonLayer = sourceModel()->data( source_right, static_cast< int >( QgsProviderSublayerModel::Role::IsNonLayerItem ) ).toBool();
431 
432  if ( leftIsNonLayer && !rightIsNonLayer )
433  return true;
434  else if ( rightIsNonLayer && !leftIsNonLayer )
435  return false;
436 
437  const QString leftName = sourceModel()->data( source_left, static_cast< int >( QgsProviderSublayerModel::Role::Name ) ).toString();
438  const QString rightName = sourceModel()->data( source_right, static_cast< int >( QgsProviderSublayerModel::Role::Name ) ).toString();
439 
440  return QString::localeAwareCompare( leftName, rightName ) < 0;
441 }
442 
444 {
445  return mIncludeSystemTables;
446 }
447 
449 {
450  mIncludeSystemTables = include;
451  invalidateFilter();
452 }
453 
455 {
456  return mFilterString;
457 }
458 
460 {
461  mFilterString = filter;
462  invalidateFilter();
463 }
@ 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
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.