mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -04:00
Add method to sort a list of layers by layer type
This commit is contained in:
parent
7c6baf8be8
commit
904a312f40
@ -56,6 +56,16 @@ uses a data provider which does not specify paths in a layer URI.
|
||||
.. versionadded:: 3.22
|
||||
%End
|
||||
|
||||
static QList< QgsMapLayer * > sortLayersByType( const QList< QgsMapLayer * > &layers, const QList< QgsMapLayerType > &order );
|
||||
%Docstring
|
||||
Sorts a list of map ``layers`` by their layer type, respecting the ``order`` of types specified.
|
||||
|
||||
Layer types which appear earlier in the ``order`` list will result in matching layers appearing earlier in the
|
||||
result list.
|
||||
|
||||
.. versionadded:: 3.26
|
||||
%End
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,108 @@ which are not wrapped by PyQt:
|
||||
- NULL QVariant which is missing in PyQt5 with sip.enableautoconversion
|
||||
*/
|
||||
|
||||
// adapted from the qpymultimedia_qlist.sip file from the PyQt6 sources
|
||||
%MappedType QList<QgsMapLayerType>
|
||||
/TypeHintIn="Iterable[QgsMapLayerType]",
|
||||
TypeHintOut="List[QgsMapLayerType]", TypeHintValue="[]"/
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include "qgis.h"
|
||||
%End
|
||||
|
||||
%ConvertFromTypeCode
|
||||
PyObject *l = PyList_New(sipCpp->size());
|
||||
|
||||
if (!l)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < sipCpp->size(); ++i)
|
||||
{
|
||||
PyObject *eobj = sipConvertFromEnum(static_cast<int>(sipCpp->at(i)),
|
||||
sipType_QgsMapLayerType);
|
||||
|
||||
if (!eobj)
|
||||
{
|
||||
Py_DECREF(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyList_SetItem(l, i, eobj);
|
||||
}
|
||||
|
||||
return l;
|
||||
%End
|
||||
|
||||
%ConvertToTypeCode
|
||||
PyObject *iter = PyObject_GetIter(sipPy);
|
||||
|
||||
if (!sipIsErr)
|
||||
{
|
||||
PyErr_Clear();
|
||||
Py_XDECREF(iter);
|
||||
|
||||
return (iter && !PyBytes_Check(sipPy) && !PyUnicode_Check(sipPy));
|
||||
}
|
||||
|
||||
if (!iter)
|
||||
{
|
||||
*sipIsErr = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<QgsMapLayerType> *ql = new QList<QgsMapLayerType>;
|
||||
|
||||
for (Py_ssize_t i = 0; ; ++i)
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyObject *itm = PyIter_Next(iter);
|
||||
|
||||
if (!itm)
|
||||
{
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
delete ql;
|
||||
Py_DECREF(iter);
|
||||
*sipIsErr = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
int v = sipConvertToEnum(itm, sipType_QgsMapLayerType);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"index %zd has type '%s' but 'QgsMapLayerType' is expected",
|
||||
i, sipPyTypeName(Py_TYPE(itm)));
|
||||
|
||||
Py_DECREF(itm);
|
||||
delete ql;
|
||||
Py_DECREF(iter);
|
||||
*sipIsErr = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ql->append(static_cast<QgsMapLayerType>(v));
|
||||
|
||||
Py_DECREF(itm);
|
||||
}
|
||||
|
||||
Py_DECREF(iter);
|
||||
|
||||
*sipCppPtr = ql;
|
||||
|
||||
return sipGetState(sipTransferObj);
|
||||
%End
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <TYPE>
|
||||
%MappedType QVector< QVector<TYPE> >
|
||||
|
@ -137,3 +137,20 @@ bool QgsMapLayerUtils::updateLayerSourcePath( QgsMapLayer *layer, const QString
|
||||
layer->setDataSource( newUri, layer->name(), layer->providerType() );
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsMapLayerUtils::sortLayersByType( const QList<QgsMapLayer *> &layers, const QList<QgsMapLayerType> &order )
|
||||
{
|
||||
QList< QgsMapLayer * > res = layers;
|
||||
std::sort( res.begin(), res.end(), [&order]( const QgsMapLayer * a, const QgsMapLayer * b ) -> bool
|
||||
{
|
||||
for ( QgsMapLayerType type : order )
|
||||
{
|
||||
if ( a->type() == type && b->type() != type )
|
||||
return true;
|
||||
else if ( b->type() == type )
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
} );
|
||||
return res;
|
||||
}
|
||||
|
@ -70,6 +70,16 @@ class CORE_EXPORT QgsMapLayerUtils
|
||||
*/
|
||||
static bool updateLayerSourcePath( QgsMapLayer *layer, const QString &newPath );
|
||||
|
||||
/**
|
||||
* Sorts a list of map \a layers by their layer type, respecting the \a order of types specified.
|
||||
*
|
||||
* Layer types which appear earlier in the \a order list will result in matching layers appearing earlier in the
|
||||
* result list.
|
||||
*
|
||||
* \since QGIS 3.26
|
||||
*/
|
||||
static QList< QgsMapLayer * > sortLayersByType( const QList< QgsMapLayer * > &layers, const QList< QgsMapLayerType > &order );
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,11 @@ from qgis.core import (
|
||||
QgsCoordinateTransformContext,
|
||||
QgsVectorLayer,
|
||||
QgsRasterLayer,
|
||||
QgsRectangle
|
||||
QgsAnnotationLayer,
|
||||
QgsGroupLayer,
|
||||
QgsRectangle,
|
||||
QgsProject,
|
||||
QgsMapLayerType
|
||||
)
|
||||
from qgis.testing import start_app, unittest
|
||||
from utilities import unitTestDataPath
|
||||
@ -123,6 +127,38 @@ class TestQgsMapLayerUtils(unittest.TestCase):
|
||||
self.assertFalse(QgsMapLayerUtils.updateLayerSourcePath(layer, unitTestDataPath() + '/mixed_layers22.gpkg'))
|
||||
self.assertEqual(layer.source(), old_source)
|
||||
|
||||
def test_sort_layers_by_type(self):
|
||||
vl1 = QgsVectorLayer("Point?field=x:string", 'vector 1', "memory")
|
||||
vl2 = QgsVectorLayer("Point?field=x:string", 'vector 2', "memory")
|
||||
options = QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())
|
||||
al1 = QgsAnnotationLayer('annotations 1', options)
|
||||
al2 = QgsAnnotationLayer('annotations 2', options)
|
||||
rl1 = QgsRasterLayer(f'GPKG:{unitTestDataPath()}/mixed_layers.gpkg:band1', 'raster 1')
|
||||
options = QgsGroupLayer.LayerOptions(QgsProject.instance().transformContext())
|
||||
gp1 = QgsGroupLayer('group 1', options)
|
||||
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], []), [vl1, rl1, gp1, vl2, al2, al1])
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.VectorLayer]), [vl1, vl2, rl1, gp1, al2, al1])
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.RasterLayer, QgsMapLayerType.VectorLayer]),
|
||||
[rl1, vl1, vl2, gp1, al2, al1])
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.GroupLayer, QgsMapLayerType.VectorLayer]),
|
||||
[gp1, vl1, vl2, rl1, al2, al1])
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.GroupLayer,
|
||||
QgsMapLayerType.VectorLayer,
|
||||
QgsMapLayerType.AnnotationLayer]),
|
||||
[gp1, vl1, vl2, al2, al1, rl1])
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2, al2, al1], [QgsMapLayerType.GroupLayer,
|
||||
QgsMapLayerType.VectorLayer,
|
||||
QgsMapLayerType.RasterLayer,
|
||||
QgsMapLayerType.AnnotationLayer]),
|
||||
[gp1, vl1, vl2, rl1, al2, al1])
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2], [QgsMapLayerType.GroupLayer,
|
||||
QgsMapLayerType.VectorLayer,
|
||||
QgsMapLayerType.RasterLayer]),
|
||||
[gp1, vl1, vl2, rl1])
|
||||
self.assertEqual(QgsMapLayerUtils.sortLayersByType([vl1, rl1, gp1, vl2], [QgsMapLayerType.AnnotationLayer]),
|
||||
[vl1, rl1, gp1, vl2])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user