QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsmaplayermodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaplayermodel.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 <QIcon>
17 
18 #include "qgsdataitem.h"
19 #include "qgsmaplayermodel.h"
20 #include "qgsproject.h"
21 #include "qgsapplication.h"
22 #include "qgsvectorlayer.h"
23 
24 
25 QgsMapLayerModel::QgsMapLayerModel( const QList<QgsMapLayer *> &layers, QObject *parent )
26  : QAbstractItemModel( parent )
27 {
28  connect( QgsProject::instance(), static_cast < void ( QgsProject::* )( const QStringList & ) >( &QgsProject::layersWillBeRemoved ), this, &QgsMapLayerModel::removeLayers );
29  addLayers( layers );
30 }
31 
33  : QAbstractItemModel( parent )
34 {
36  connect( QgsProject::instance(), static_cast < void ( QgsProject::* )( const QStringList & ) >( &QgsProject::layersWillBeRemoved ), this, &QgsMapLayerModel::removeLayers );
37  addLayers( QgsProject::instance()->mapLayers().values() );
38 }
39 
41 {
42  mItemCheckable = checkable;
43 }
44 
45 void QgsMapLayerModel::checkAll( Qt::CheckState checkState )
46 {
47  QMap<QString, Qt::CheckState>::iterator i = mLayersChecked.begin();
48  for ( ; i != mLayersChecked.end(); ++i )
49  {
50  *i = checkState;
51  }
52  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ) );
53 }
54 
55 void QgsMapLayerModel::setAllowEmptyLayer( bool allowEmpty )
56 {
57  if ( allowEmpty == mAllowEmpty )
58  return;
59 
60  if ( allowEmpty )
61  {
62  beginInsertRows( QModelIndex(), 0, 0 );
63  mAllowEmpty = true;
64  endInsertRows();
65  }
66  else
67  {
68  beginRemoveRows( QModelIndex(), 0, 0 );
69  mAllowEmpty = false;
70  endRemoveRows();
71  }
72 }
73 
75 {
76  if ( mShowCrs == showCrs )
77  return;
78 
79  mShowCrs = showCrs;
80  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ), QVector<int>() << Qt::DisplayRole );
81 }
82 
83 QList<QgsMapLayer *> QgsMapLayerModel::layersChecked( Qt::CheckState checkState )
84 {
85  QList<QgsMapLayer *> layers;
86  const auto constMLayers = mLayers;
87  for ( QgsMapLayer *layer : constMLayers )
88  {
89  if ( mLayersChecked[layer->id()] == checkState )
90  {
91  layers.append( layer );
92  }
93  }
94  return layers;
95 }
96 
97 QModelIndex QgsMapLayerModel::indexFromLayer( QgsMapLayer *layer ) const
98 {
99  int r = mLayers.indexOf( layer );
100  if ( r >= 0 && mAllowEmpty )
101  r++;
102  return index( r, 0 );
103 }
104 
106 {
107  return static_cast<QgsMapLayer *>( index.internalPointer() );
108 }
109 
110 void QgsMapLayerModel::setAdditionalItems( const QStringList &items )
111 {
112  if ( items == mAdditionalItems )
113  return;
114 
115  int offset = 0;
116  if ( mAllowEmpty )
117  offset++;
118 
119  offset += mLayers.count();
120 
121  //remove existing
122  if ( !mAdditionalItems.isEmpty() )
123  {
124  beginRemoveRows( QModelIndex(), offset, offset + mAdditionalItems.count() - 1 );
125  mAdditionalItems.clear();
126  endRemoveRows();
127  }
128 
129  //add new
130  beginInsertRows( QModelIndex(), offset, offset + items.count() - 1 );
131  mAdditionalItems = items;
132  endInsertRows();
133 }
134 
135 void QgsMapLayerModel::removeLayers( const QStringList &layerIds )
136 {
137  int offset = 0;
138  if ( mAllowEmpty )
139  offset++;
140 
141  const auto constLayerIds = layerIds;
142  for ( const QString &layerId : constLayerIds )
143  {
144  QModelIndex startIndex = index( 0, 0 );
145  QModelIndexList list = match( startIndex, LayerIdRole, layerId, 1 );
146  if ( !list.isEmpty() )
147  {
148  QModelIndex index = list[0];
149  beginRemoveRows( QModelIndex(), index.row(), index.row() );
150  mLayersChecked.remove( layerId );
151  mLayers.removeAt( index.row() - offset );
152  endRemoveRows();
153  }
154  }
155 }
156 
157 void QgsMapLayerModel::addLayers( const QList<QgsMapLayer *> &layers )
158 {
159  if ( !layers.empty( ) )
160  {
161  int offset = 0;
162  if ( mAllowEmpty )
163  offset++;
164 
165  beginInsertRows( QModelIndex(), mLayers.count() + offset, mLayers.count() + layers.count() - 1 + offset );
166  const auto constLayers = layers;
167  for ( QgsMapLayer *layer : constLayers )
168  {
169  mLayers.append( layer );
170  mLayersChecked.insert( layer->id(), Qt::Unchecked );
171  }
172  endInsertRows();
173  }
174 }
175 
176 QModelIndex QgsMapLayerModel::index( int row, int column, const QModelIndex &parent ) const
177 {
178  int offset = 0;
179  if ( mAllowEmpty )
180  offset++;
181 
182  if ( hasIndex( row, column, parent ) )
183  {
184  QgsMapLayer *layer = nullptr;
185  if ( row - offset >= 0 && row - offset < mLayers.count() )
186  layer = mLayers.at( row - offset );
187 
188  return createIndex( row, column, layer );
189  }
190 
191  return QModelIndex();
192 
193 }
194 
195 QModelIndex QgsMapLayerModel::parent( const QModelIndex &child ) const
196 {
197  Q_UNUSED( child )
198  return QModelIndex();
199 }
200 
201 
202 int QgsMapLayerModel::rowCount( const QModelIndex &parent ) const
203 {
204  if ( parent.isValid() )
205  return 0;
206 
207  return ( mAllowEmpty ? 1 : 0 ) + mLayers.length() + mAdditionalItems.count();
208 }
209 
210 int QgsMapLayerModel::columnCount( const QModelIndex &parent ) const
211 {
212  Q_UNUSED( parent )
213  return 1;
214 }
215 
216 
217 QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const
218 {
219  if ( !index.isValid() )
220  return QVariant();
221 
222  bool isEmpty = index.row() == 0 && mAllowEmpty;
223  int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();
224 
225  switch ( role )
226  {
227  case Qt::DisplayRole:
228  {
229  if ( index.row() == 0 && mAllowEmpty )
230  return QVariant();
231 
232  if ( additionalIndex >= 0 )
233  return mAdditionalItems.at( additionalIndex );
234 
235  QgsMapLayer *layer = static_cast<QgsMapLayer *>( index.internalPointer() );
236  if ( !layer )
237  return QVariant();
238 
239  if ( !mShowCrs || !layer->isSpatial() )
240  {
241  return layer->name();
242  }
243  else
244  {
245  return tr( "%1 [%2]" ).arg( layer->name(), layer->crs().authid() );
246  }
247  }
248 
249  case LayerIdRole:
250  {
251  if ( isEmpty || additionalIndex >= 0 )
252  return QVariant();
253 
254  QgsMapLayer *layer = static_cast<QgsMapLayer *>( index.internalPointer() );
255  return layer ? layer->id() : QVariant();
256  }
257 
258  case LayerRole:
259  {
260  if ( isEmpty || additionalIndex >= 0 )
261  return QVariant();
262 
263  return QVariant::fromValue<QgsMapLayer *>( static_cast<QgsMapLayer *>( index.internalPointer() ) );
264  }
265 
266  case EmptyRole:
267  return isEmpty;
268 
269  case AdditionalRole:
270  return additionalIndex >= 0;
271 
272  case Qt::CheckStateRole:
273  {
274  if ( mItemCheckable )
275  {
276  if ( isEmpty || additionalIndex >= 0 )
277  return QVariant();
278 
279  QgsMapLayer *layer = static_cast<QgsMapLayer *>( index.internalPointer() );
280  return layer ? mLayersChecked[layer->id()] : QVariant();
281  }
282 
283  return QVariant();
284  }
285 
286  case Qt::ToolTipRole:
287  {
288  QgsMapLayer *layer = static_cast<QgsMapLayer *>( index.internalPointer() );
289  if ( layer )
290  {
291  QStringList parts;
292  QString title = layer->title().isEmpty() ? layer->shortName() : layer->title();
293  if ( title.isEmpty() )
294  title = layer->name();
295  title = "<b>" + title + "</b>";
296  if ( layer->isSpatial() && layer->crs().isValid() )
297  {
298  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
299  title = tr( "%1 (%2 - %3)" ).arg( title, QgsWkbTypes::displayString( vl->wkbType() ), layer->crs().authid() );
300  else
301  title = tr( "%1 (%2) " ).arg( title, layer->crs().authid() );
302  }
303  parts << title;
304 
305  if ( !layer->abstract().isEmpty() )
306  parts << "<br/>" + layer->abstract().replace( QLatin1String( "\n" ), QLatin1String( "<br/>" ) );
307  parts << "<i>" + layer->publicSource() + "</i>";
308  return parts.join( QStringLiteral( "<br/>" ) );
309  }
310  return QVariant();
311  }
312 
313  case Qt::DecorationRole:
314  {
315  if ( isEmpty || additionalIndex >= 0 )
316  return QVariant();
317 
318  QgsMapLayer *layer = static_cast<QgsMapLayer *>( index.internalPointer() );
319  if ( !layer )
320  return QVariant();
321 
322  return iconForLayer( layer );
323  }
324  }
325 
326  return QVariant();
327 }
328 
329 QHash<int, QByteArray> QgsMapLayerModel::roleNames() const
330 {
331  QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
332  roles[LayerIdRole] = "layerId";
333  roles[LayerRole] = "layer";
334 
335  return roles;
336 }
337 
338 Qt::ItemFlags QgsMapLayerModel::flags( const QModelIndex &index ) const
339 {
340  if ( !index.isValid() )
341  {
342  return nullptr;
343  }
344 
345  bool isEmpty = index.row() == 0 && mAllowEmpty;
346  int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();
347 
348  Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
349  if ( mItemCheckable && !isEmpty && additionalIndex < 0 )
350  {
351  flags |= Qt::ItemIsUserCheckable;
352  }
353  return flags;
354 }
355 
357 {
358  switch ( layer->type() )
359  {
361  {
362  return QgsLayerItem::iconRaster();
363  }
364 
366  {
367  return QgsLayerItem::iconMesh();
368  }
369 
371  {
372  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
373  if ( !vl )
374  {
375  return QIcon();
376  }
377  QgsWkbTypes::GeometryType geomType = vl->geometryType();
378  switch ( geomType )
379  {
381  {
382  return QgsLayerItem::iconPoint();
383  }
385  {
386  return QgsLayerItem::iconPolygon();
387  }
389  {
390  return QgsLayerItem::iconLine();
391  }
393  {
394  return QgsLayerItem::iconTable();
395  }
396  default:
397  {
398  return QIcon();
399  }
400  }
401  }
402  default:
403  {
404  return QIcon();
405  }
406  }
407 }
408 
409 
410 bool QgsMapLayerModel::setData( const QModelIndex &index, const QVariant &value, int role )
411 {
412  bool isEmpty = index.row() == 0 && mAllowEmpty;
413  int additionalIndex = index.row() - ( mAllowEmpty ? 1 : 0 ) - mLayers.count();
414 
415  if ( role == Qt::CheckStateRole && !isEmpty && additionalIndex < 0 )
416  {
417  QgsMapLayer *layer = static_cast<QgsMapLayer *>( index.internalPointer() );
418  mLayersChecked[layer->id()] = ( Qt::CheckState )value.toInt();
419  emit dataChanged( index, index );
420  return true;
421  }
422 
423  return false;
424 }
QgsMapLayer * layerFromIndex(const QModelIndex &index) const
Returns the map layer corresponding to the specified index.
static QIcon iconRaster()
Definition: qgsdataitem.cpp:72
QModelIndex indexFromLayer(QgsMapLayer *layer) const
indexFromLayer returns the model index for a given layer
Base class for all map layer types.
Definition: qgsmaplayer.h:78
void layersAdded(const QList< QgsMapLayer *> &layers)
Emitted when one or more layers were added to the registry.
QgsMapLayerType type() const
Returns the type of the layer.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:263
Stores the map layer ID.
void checkAll(Qt::CheckState checkState)
checkAll changes the checkstate for all the layers
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request. ...
Definition: qgsmaplayer.h:294
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
static QIcon iconLine()
Definition: qgsdataitem.cpp:57
static QIcon iconPoint()
Definition: qgsdataitem.cpp:52
Stores pointer to the map layer itself.
QModelIndex parent(const QModelIndex &child) const override
void setItemsCheckable(bool checkable)
setItemsCheckable defines if layers should be selectable in the widget
QgsMapLayerModel(QObject *parent=nullptr)
QgsMapLayerModel creates a model to display layers in widgets.
True if index corresponds to an additional (non map layer) item.
void addLayers(const QList< QgsMapLayer *> &layers)
void removeLayers(const QStringList &layerIds)
void setShowCrs(bool showCrs)
Sets whether the CRS of layers is also included in the model&#39;s display role.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
Qt::ItemFlags flags(const QModelIndex &index) const override
static QIcon iconPolygon()
Definition: qgsdataitem.cpp:62
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QMap< QString, Qt::CheckState > mLayersChecked
void setAllowEmptyLayer(bool allowEmpty)
Sets whether an optional empty layer ("not set") option is present in the model.
Reads and writes project states.
Definition: qgsproject.h:89
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
QList< QgsMapLayer * > mLayers
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:278
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
bool showCrs() const
Returns true if the model includes layer&#39;s CRS in the display role.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
QHash< int, QByteArray > roleNames() const override
Returns strings for all roles supported by this model.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:438
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
static QString displayString(Type type)
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
static QIcon iconTable()
Definition: qgsdataitem.cpp:67
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QString name
Definition: qgsmaplayer.h:82
void setAdditionalItems(const QStringList &items)
Sets a list of additional (non map layer) items to include at the end of the model.
static QIcon iconForLayer(QgsMapLayer *layer)
Returns the icon corresponding to a specified map layer.
Represents a vector layer which manages a vector based data sets.
static QIcon iconMesh()
Returns icon for mesh layer type.
Definition: qgsdataitem.cpp:77
QString authid() const
Returns the authority identifier for the CRS.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:85
QList< QgsMapLayer * > layersChecked(Qt::CheckState checkState=Qt::Checked)
layersChecked returns the list of layers which are checked (or unchecked)
True if index corresponds to the empty (not set) value.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.