diff --git a/src/gui/layertree/qgslayertreemapcanvasbridge.cpp b/src/gui/layertree/qgslayertreemapcanvasbridge.cpp index ad22efce5f6..c522da94ec1 100644 --- a/src/gui/layertree/qgslayertreemapcanvasbridge.cpp +++ b/src/gui/layertree/qgslayertreemapcanvasbridge.cpp @@ -37,6 +37,7 @@ QgsLayerTreeMapCanvasBridge::QgsLayerTreeMapCanvasBridge( QgsLayerTreeGroup *roo connect( root, &QgsLayerTreeGroup::customPropertyChanged, this, &QgsLayerTreeMapCanvasBridge::nodeCustomPropertyChanged ); connect( root, &QgsLayerTreeGroup::removedChildren, this, &QgsLayerTreeMapCanvasBridge::nodeRemovedChildren ); connect( root, &QgsLayerTreeNode::visibilityChanged, this, &QgsLayerTreeMapCanvasBridge::nodeVisibilityChanged ); + connect( QgsProject::instance(), &QgsProject::layerOrderChanged, this, &QgsLayerTreeMapCanvasBridge::projectLayerOrderChanged ); setCanvasLayers(); } @@ -141,7 +142,9 @@ void QgsLayerTreeMapCanvasBridge::setCanvasLayers() int currentLayerCount = layerNodes.count(); bool firstLayers = mAutoSetupOnFirstLayer && mLastLayerCount == 0 && currentLayerCount != 0; + mUpdatingProjectLayerOrder = true; QgsProject::instance()->setLayerOrder( allLayerOrder ); + mUpdatingProjectLayerOrder = false; mCanvas->setLayers( canvasLayers ); if ( mOverviewCanvas ) mOverviewCanvas->setLayers( overviewLayers ); @@ -318,3 +321,18 @@ void QgsLayerTreeMapCanvasBridge::nodeCustomPropertyChanged( QgsLayerTreeNode *n deferredSetCanvasLayers(); } +void QgsLayerTreeMapCanvasBridge::projectLayerOrderChanged() +{ + if ( mUpdatingProjectLayerOrder ) + return; + + setHasCustomLayerOrder( true ); + QStringList ids; + Q_FOREACH( QgsMapLayer* layer, QgsProject::instance()->layerOrder() ) + { + if ( layer ) + ids << layer->id(); + } + setCustomLayerOrder( ids ); +} + diff --git a/src/gui/layertree/qgslayertreemapcanvasbridge.h b/src/gui/layertree/qgslayertreemapcanvasbridge.h index ebb2c0078a0..ebdc0581bd6 100644 --- a/src/gui/layertree/qgslayertreemapcanvasbridge.h +++ b/src/gui/layertree/qgslayertreemapcanvasbridge.h @@ -110,6 +110,10 @@ class GUI_EXPORT QgsLayerTreeMapCanvasBridge : public QObject void nodeVisibilityChanged(); void nodeCustomPropertyChanged( QgsLayerTreeNode *node, const QString &key ); + private slots: + + void projectLayerOrderChanged(); + protected: QgsLayerTreeGroup *mRoot = nullptr; QgsMapCanvas *mCanvas = nullptr; @@ -124,6 +128,8 @@ class GUI_EXPORT QgsLayerTreeMapCanvasBridge : public QObject bool mHasFirstLayer; bool mLastLayerCount; + bool mUpdatingProjectLayerOrder = false; + QgsCoordinateReferenceSystem mFirstCRS; }; diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt index 8b98641a352..1d4c425c4b4 100644 --- a/tests/src/python/CMakeLists.txt +++ b/tests/src/python/CMakeLists.txt @@ -63,6 +63,7 @@ ADD_PYTHON_TEST(PyQgsGeometryValidator test_qgsgeometryvalidator.py) ADD_PYTHON_TEST(PyQgsGraduatedSymbolRenderer test_qgsgraduatedsymbolrenderer.py) ADD_PYTHON_TEST(PyQgsInterval test_qgsinterval.py) ADD_PYTHON_TEST(PyQgsJSONUtils test_qgsjsonutils.py) +ADD_PYTHON_TEST(PyQgsLayerTreeMapCanvasBridge test_qgslayertreemapcanvasbridge.py) ADD_PYTHON_TEST(PyQgsLineSymbolLayers test_qgslinesymbollayers.py) ADD_PYTHON_TEST(PyQgsMapCanvas test_qgsmapcanvas.py) ADD_PYTHON_TEST(PyQgsMapCanvasAnnotationItem test_qgsmapcanvasannotationitem.py) diff --git a/tests/src/python/test_qgslayertreemapcanvasbridge.py b/tests/src/python/test_qgslayertreemapcanvasbridge.py new file mode 100644 index 00000000000..735b20228e2 --- /dev/null +++ b/tests/src/python/test_qgslayertreemapcanvasbridge.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +"""QGIS Unit tests for QgsLayerTreeMapCanvasBridge. + +.. note:: This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +""" +__author__ = 'Nyall Dawson' +__date__ = '8/03/2017' +__copyright__ = 'Copyright 2017, The QGIS Project' +# This will get replaced with a git SHA1 when you do a git archive +__revision__ = '$Format:%H$' + +import os + +import qgis # NOQA + +from qgis.core import (QgsProject, + QgsApplication, + QgsUnitTypes, + QgsCoordinateReferenceSystem, + QgsVectorLayer) +from qgis.gui import (QgsLayerTreeMapCanvasBridge, + QgsMapCanvas, + QgsCustomLayerOrderWidget) +from qgis.testing import start_app, unittest +from utilities import (unitTestDataPath) + +app = start_app() +TEST_DATA_DIR = unitTestDataPath() + + +class TestQgsLayerTreeMapCanvasBridge(unittest.TestCase): + + def __init__(self, methodName): + """Run once on class initialization.""" + unittest.TestCase.__init__(self, methodName) + + def testCustomLayerOrderUpdatedFromProject(self): + """ test that setting project layer order is reflected in custom layer order panel """ + + prj = QgsProject.instance() + layer = QgsVectorLayer("Point?field=fldtxt:string", + "layer1", "memory") + layer2 = QgsVectorLayer("Point?field=fldtxt:string", + "layer2", "memory") + layer3 = QgsVectorLayer("Point?field=fldtxt:string", + "layer3", "memory") + prj.addMapLayers([layer, layer2, layer3]) + + canvas = QgsMapCanvas() + bridge = QgsLayerTreeMapCanvasBridge(prj.layerTreeRoot(), canvas) + custom_order_widget = QgsCustomLayerOrderWidget(bridge) + + #custom layer order + bridge.setHasCustomLayerOrder(True) + bridge.setCustomLayerOrder([layer3.id(), layer.id(), layer2.id()]) + app.processEvents() + self.assertEqual([l.id() for l in prj.layerOrder()], [layer3.id(), layer.id(), layer2.id()]) + + # no custom layer order + bridge.setHasCustomLayerOrder(False) + app.processEvents() + self.assertEqual([l.id() for l in prj.layerOrder()], [layer.id(), layer2.id(), layer3.id()]) + + # mess around with the project layer order + prj.setLayerOrder([layer3, layer, layer2]) + app.processEvents() + # make sure bridge respects this new order + self.assertTrue(bridge.hasCustomLayerOrder()) + self.assertEqual(bridge.customLayerOrder(), [layer3.id(), layer.id(), layer2.id()]) + + # try reordering through bridge + bridge.setHasCustomLayerOrder(False) + app.processEvents() + self.assertEqual([l.id() for l in prj.layerOrder()], [layer.id(), layer2.id(), layer3.id()]) + root = prj.layerTreeRoot() + layer_node = root.findLayer(layer2.id()) + cloned_node = layer_node.clone() + parent = layer_node.parent() + parent.insertChildNode(0, cloned_node) + parent.removeChildNode(layer_node) + app.processEvents() + # make sure project respects this + self.assertEqual([l.id() for l in prj.layerOrder()], [layer2.id(), layer.id(), layer3.id()]) + self.assertFalse(bridge.hasCustomLayerOrder()) + +if __name__ == '__main__': + unittest.main()