Navigation Menu

Skip to content

Commit

Permalink
[api] Add method to add additional layers to QgsMapLayerModel
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 6, 2021
1 parent 0896d59 commit 1d73ea8
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 5 deletions.
25 changes: 23 additions & 2 deletions python/core/auto_generated/qgsmaplayermodel.sip.in
Expand Up @@ -151,8 +151,8 @@ Returns the map layer corresponding to the specified ``index``.
void setAdditionalItems( const QStringList &items );
%Docstring
Sets a list of additional (non map layer) items to include at the end of the model.
These may represent additional layers such as layers which are not included in the map
layer registry, or paths to layers which have not yet been loaded into QGIS.
These may represent additional layers such as layers which are not included in the active project,
or paths to layers which have not yet been loaded into QGIS.

.. seealso:: :py:func:`additionalItems`

Expand All @@ -166,6 +166,27 @@ Returns the list of additional (non map layer) items included at the end of the
.. seealso:: :py:func:`setAdditionalItems`

.. versionadded:: 3.0
%End

void setAdditionalLayers( const QList<QgsMapLayer *> &layers );
%Docstring
Sets a list of additional ``layers`` to include in the model.

This method allows adding additional layers, which are not part of a project's
layers, into the model.

.. seealso:: :py:func:`additionalLayers`

.. versionadded:: 3.22
%End

QList< QgsMapLayer * > additionalLayers() const;
%Docstring
Returns the list of additional layers added to the model.

.. seealso:: :py:func:`setAdditionalLayers`

.. versionadded:: 3.22
%End

virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
Expand Down
32 changes: 32 additions & 0 deletions src/core/qgsmaplayermodel.cpp
Expand Up @@ -20,6 +20,7 @@
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include "qgsiconutils.h"
#include "qgsmaplayerlistutils.h"
#include <QMimeData>

QgsMapLayerModel::QgsMapLayerModel( const QList<QgsMapLayer *> &layers, QObject *parent, QgsProject *project )
Expand Down Expand Up @@ -160,6 +161,37 @@ void QgsMapLayerModel::setAdditionalItems( const QStringList &items )
endInsertRows();
}

void QgsMapLayerModel::setAdditionalLayers( const QList<QgsMapLayer *> &layers )
{
if ( layers == _qgis_listQPointerToRaw( mAdditionalLayers ) )
return;

QStringList layerIdsToRemove;
for ( QgsMapLayer *layer : std::as_const( mAdditionalLayers ) )
{
if ( layer )
layerIdsToRemove << layer->id();
}
removeLayers( layerIdsToRemove );

for ( QgsMapLayer *layer : layers )
{
if ( layer )
{
addLayers( { layer } );
const QString layerId = layer->id();
connect( layer, &QgsMapLayer::willBeDeleted, this, [this, layerId] { removeLayers( {layerId} ); } );
}
}

mAdditionalLayers = _qgis_listRawToQPointer( layers );
}

QList<QgsMapLayer *> QgsMapLayerModel::additionalLayers() const
{
return _qgis_listQPointerToRaw( mAdditionalLayers );
}

void QgsMapLayerModel::removeLayers( const QStringList &layerIds )
{
int offset = 0;
Expand Down
24 changes: 22 additions & 2 deletions src/core/qgsmaplayermodel.h
Expand Up @@ -156,8 +156,8 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel

/**
* Sets a list of additional (non map layer) items to include at the end of the model.
* These may represent additional layers such as layers which are not included in the map
* layer registry, or paths to layers which have not yet been loaded into QGIS.
* These may represent additional layers such as layers which are not included in the active project,
* or paths to layers which have not yet been loaded into QGIS.
* \see additionalItems()
* \since QGIS 3.0
*/
Expand All @@ -170,6 +170,25 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel
*/
QStringList additionalItems() const { return mAdditionalItems; }

/**
* Sets a list of additional \a layers to include in the model.
*
* This method allows adding additional layers, which are not part of a project's
* layers, into the model.
*
* \see additionalLayers()
* \since QGIS 3.22
*/
void setAdditionalLayers( const QList<QgsMapLayer *> &layers );

/**
* Returns the list of additional layers added to the model.
*
* \see setAdditionalLayers()
* \since QGIS 3.22
*/
QList< QgsMapLayer * > additionalLayers() const;

// QAbstractItemModel interface
QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
QModelIndex parent( const QModelIndex &child ) const override;
Expand Down Expand Up @@ -205,6 +224,7 @@ class CORE_EXPORT QgsMapLayerModel : public QAbstractItemModel

protected:
QList<QgsMapLayer *> mLayers;
QList< QPointer<QgsMapLayer> > mAdditionalLayers;
QMap<QString, Qt::CheckState> mLayersChecked;
bool mItemCheckable = false;
bool mCanReorder = false;
Expand Down
79 changes: 78 additions & 1 deletion tests/src/python/test_qgsmaplayermodel.py
Expand Up @@ -13,7 +13,12 @@
import qgis # NOQA

from qgis.core import QgsVectorLayer, QgsProject, QgsMapLayerModel, QgsApplication
from qgis.PyQt.QtCore import Qt, QModelIndex
from qgis.PyQt.QtCore import (
QCoreApplication,
Qt,
QModelIndex,
QEvent
)

from qgis.testing import start_app, unittest

Expand Down Expand Up @@ -162,6 +167,78 @@ def testAdditionalItems(self):
self.assertEqual(m.data(m.index(1, 0), Qt.DisplayRole), 'a')
self.assertEqual(m.data(m.index(2, 0), Qt.DisplayRole), 'b')

def testAdditionalLayers(self):
l1 = create_layer('l1')
l2 = create_layer('l2')
QgsProject.instance().addMapLayers([l1, l2])
m = QgsMapLayerModel()
self.assertEqual(m.rowCount(QModelIndex()), 2)
l3 = create_layer('l3')
l4 = create_layer('l4')
m.setAdditionalLayers([l3, l4])
self.assertEqual(m.rowCount(QModelIndex()), 4)

m.setAdditionalItems(['a', 'b'])
self.assertEqual(m.rowCount(QModelIndex()), 6)
self.assertEqual(m.data(m.index(0, 0), Qt.DisplayRole), 'l1')
self.assertEqual(m.data(m.index(1, 0), Qt.DisplayRole), 'l2')
self.assertEqual(m.data(m.index(2, 0), Qt.DisplayRole), 'l3')
self.assertEqual(m.data(m.index(3, 0), Qt.DisplayRole), 'l4')
self.assertEqual(m.data(m.index(4, 0), Qt.DisplayRole), 'a')
self.assertEqual(m.data(m.index(5, 0), Qt.DisplayRole), 'b')

m.setAllowEmptyLayer(True)
self.assertEqual(m.rowCount(QModelIndex()), 7)
self.assertFalse(m.data(m.index(0, 0), Qt.DisplayRole))
self.assertEqual(m.data(m.index(1, 0), Qt.DisplayRole), 'l1')
self.assertEqual(m.data(m.index(2, 0), Qt.DisplayRole), 'l2')
self.assertEqual(m.data(m.index(3, 0), Qt.DisplayRole), 'l3')
self.assertEqual(m.data(m.index(4, 0), Qt.DisplayRole), 'l4')
self.assertEqual(m.data(m.index(5, 0), Qt.DisplayRole), 'a')
self.assertEqual(m.data(m.index(6, 0), Qt.DisplayRole), 'b')

l3.deleteLater()
QCoreApplication.sendPostedEvents(None, QEvent.DeferredDelete)
self.assertEqual(m.rowCount(QModelIndex()), 6)
self.assertFalse(m.data(m.index(0, 0), Qt.DisplayRole))
self.assertEqual(m.data(m.index(1, 0), Qt.DisplayRole), 'l1')
self.assertEqual(m.data(m.index(2, 0), Qt.DisplayRole), 'l2')
self.assertEqual(m.data(m.index(3, 0), Qt.DisplayRole), 'l4')
self.assertEqual(m.data(m.index(4, 0), Qt.DisplayRole), 'a')
self.assertEqual(m.data(m.index(5, 0), Qt.DisplayRole), 'b')

l5 = create_layer('l5')
l6 = create_layer('l6')
m.setAdditionalLayers([l5, l6, l4])
self.assertEqual(m.rowCount(QModelIndex()), 8)
self.assertFalse(m.data(m.index(0, 0), Qt.DisplayRole))
self.assertEqual(m.data(m.index(1, 0), Qt.DisplayRole), 'l1')
self.assertEqual(m.data(m.index(2, 0), Qt.DisplayRole), 'l2')
self.assertEqual(m.data(m.index(3, 0), Qt.DisplayRole), 'l5')
self.assertEqual(m.data(m.index(4, 0), Qt.DisplayRole), 'l6')
self.assertEqual(m.data(m.index(5, 0), Qt.DisplayRole), 'l4')
self.assertEqual(m.data(m.index(6, 0), Qt.DisplayRole), 'a')
self.assertEqual(m.data(m.index(7, 0), Qt.DisplayRole), 'b')

m.setAdditionalLayers([l5, l4])
self.assertEqual(m.rowCount(QModelIndex()), 7)
self.assertFalse(m.data(m.index(0, 0), Qt.DisplayRole))
self.assertEqual(m.data(m.index(1, 0), Qt.DisplayRole), 'l1')
self.assertEqual(m.data(m.index(2, 0), Qt.DisplayRole), 'l2')
self.assertEqual(m.data(m.index(3, 0), Qt.DisplayRole), 'l5')
self.assertEqual(m.data(m.index(4, 0), Qt.DisplayRole), 'l4')
self.assertEqual(m.data(m.index(5, 0), Qt.DisplayRole), 'a')
self.assertEqual(m.data(m.index(6, 0), Qt.DisplayRole), 'b')

QgsProject.instance().removeMapLayers([l1.id(), l2.id()])

self.assertEqual(m.rowCount(QModelIndex()), 5)
self.assertFalse(m.data(m.index(0, 0), Qt.DisplayRole))
self.assertEqual(m.data(m.index(1, 0), Qt.DisplayRole), 'l5')
self.assertEqual(m.data(m.index(2, 0), Qt.DisplayRole), 'l4')
self.assertEqual(m.data(m.index(3, 0), Qt.DisplayRole), 'a')
self.assertEqual(m.data(m.index(4, 0), Qt.DisplayRole), 'b')

def testIndexFromLayer(self):
l1 = create_layer('l1')
l2 = create_layer('l2')
Expand Down

0 comments on commit 1d73ea8

Please sign in to comment.