Skip to content
Permalink
Browse files
[api] Add method to add additional layers to QgsMapLayerModel
  • Loading branch information
nyalldawson committed Sep 6, 2021
1 parent 0896d59 commit 1d73ea86a63acef8dfe01cd46cac69d090745980
@@ -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`

@@ -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;
@@ -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 )
@@ -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;
@@ -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
*/
@@ -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;
@@ -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;
@@ -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

@@ -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')

0 comments on commit 1d73ea8

Please sign in to comment.