mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Allow retrieval of project layer order through QgsProject
Previously this was only accessible through app
This commit is contained in:
parent
9842fcbfc7
commit
6cfc6a1b98
@ -487,6 +487,9 @@ class QgsProject : QObject, QgsExpressionContextGenerator
|
||||
*/
|
||||
void reloadAllLayers();
|
||||
|
||||
QList< QgsMapLayer * > layerOrder() const;
|
||||
void setLayerOrder( const QList< QgsMapLayer * > &order );
|
||||
|
||||
signals:
|
||||
//! emitted when project is being read
|
||||
void readProject( const QDomDocument& );
|
||||
@ -623,12 +626,12 @@ class QgsProject : QObject, QgsExpressionContextGenerator
|
||||
*/
|
||||
//TODO QGIS 3.0 - rename to past tense
|
||||
void removeAll();
|
||||
void layersAdded( const QList<QgsMapLayer *> &layers );
|
||||
|
||||
void layersAdded( const QList<QgsMapLayer *>& layers );
|
||||
void layerWasAdded( QgsMapLayer *layer );
|
||||
void legendLayersAdded( const QList<QgsMapLayer *> &layers );
|
||||
|
||||
void layerWasAdded( QgsMapLayer* layer );
|
||||
|
||||
void legendLayersAdded( const QList<QgsMapLayer*>& layers );
|
||||
void layerOrderChanged();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsprojectbadlayerhandler.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgsmaplayerlistutils.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
@ -460,6 +461,7 @@ void QgsProject::clear()
|
||||
mEvaluateDefaultValues = false;
|
||||
mDirty = false;
|
||||
mCustomVariables.clear();
|
||||
mLayerOrder.clear();
|
||||
|
||||
mEmbeddedLayers.clear();
|
||||
mRelationManager->clear();
|
||||
@ -881,6 +883,20 @@ bool QgsProject::read()
|
||||
// load embedded groups and layers
|
||||
loadEmbeddedNodes( mRootGroup );
|
||||
|
||||
// load layer order
|
||||
QList< QgsMapLayer * > layerOrder;
|
||||
QDomNodeList layerOrderNodes = doc->elementsByTagName( QStringLiteral( "layerorder" ) );
|
||||
if ( layerOrderNodes.count() )
|
||||
{
|
||||
QDomElement layerOrderElem = layerOrderNodes.at( 0 ).toElement();
|
||||
for ( int i = 0; i < layerOrderElem.childNodes().count(); ++i )
|
||||
{
|
||||
QDomElement layerElem = layerOrderElem.childNodes().at( i ).toElement();
|
||||
layerOrder << mMapLayers.value( layerElem.attribute( QStringLiteral( "id" ) ) );
|
||||
}
|
||||
}
|
||||
setLayerOrder( layerOrder );
|
||||
|
||||
// now that layers are loaded, we can resolve layer tree's references to the layers
|
||||
mRootGroup->resolveReferences( this );
|
||||
|
||||
@ -1244,6 +1260,16 @@ bool QgsProject::write()
|
||||
|
||||
qgisNode.appendChild( projectLayersNode );
|
||||
|
||||
QDomElement layerOrderNode = doc->createElement( QStringLiteral( "layerorder" ) );
|
||||
Q_FOREACH ( QgsMapLayer *layer, layerOrder() )
|
||||
{
|
||||
QDomElement mapLayerElem = doc->createElement( QStringLiteral( "layer" ) );
|
||||
mapLayerElem.setAttribute( QStringLiteral( "id" ), layer->id() );
|
||||
layerOrderNode.appendChild( mapLayerElem );
|
||||
}
|
||||
qgisNode.appendChild( layerOrderNode );
|
||||
|
||||
|
||||
// now add the optional extra properties
|
||||
|
||||
dump_( mProperties );
|
||||
@ -2091,6 +2117,8 @@ void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
||||
QStringList layerIds;
|
||||
QList<QgsMapLayer *> layerList;
|
||||
|
||||
bool layerOrderHasChanged = false;
|
||||
QList< QgsMapLayer * > currentOrder = layerOrder();
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
// check layer and the registry contains it
|
||||
@ -2098,6 +2126,7 @@ void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
layerIds << layer->id();
|
||||
layerList << layer;
|
||||
layerOrderHasChanged = layerOrderHasChanged || currentOrder.contains( layer );
|
||||
}
|
||||
}
|
||||
|
||||
@ -2121,6 +2150,8 @@ void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
||||
}
|
||||
|
||||
emit layersRemoved( layerIds );
|
||||
if ( layerOrderHasChanged )
|
||||
emit layerOrderChanged();
|
||||
}
|
||||
|
||||
void QgsProject::removeMapLayer( const QString &layerId )
|
||||
@ -2151,6 +2182,20 @@ void QgsProject::reloadAllLayers()
|
||||
}
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsProject::layerOrder() const
|
||||
{
|
||||
return _qgis_listQPointerToRaw( mLayerOrder );
|
||||
}
|
||||
|
||||
void QgsProject::setLayerOrder( const QList<QgsMapLayer *> &order )
|
||||
{
|
||||
if ( order == layerOrder() )
|
||||
return;
|
||||
|
||||
mLayerOrder = _qgis_listRawToQPointer( order );
|
||||
emit layerOrderChanged();
|
||||
}
|
||||
|
||||
void QgsProject::onMapLayerDeleted( QObject *obj )
|
||||
{
|
||||
QString id = mMapLayers.key( static_cast<QgsMapLayer *>( obj ) );
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "qgsexpressioncontextgenerator.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsprojectproperty.h"
|
||||
#include "qgsmaplayer.h"
|
||||
|
||||
class QFileInfo;
|
||||
class QDomDocument;
|
||||
@ -690,6 +691,22 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
*/
|
||||
void reloadAllLayers();
|
||||
|
||||
/**
|
||||
* Returns an ordered list of layers. This list reflects the order of layers as
|
||||
* drawn in the main map canvas for the project.
|
||||
* @note added in QGIS 3.0
|
||||
* @see setLayerOrder()
|
||||
*/
|
||||
QList< QgsMapLayer * > layerOrder() const;
|
||||
|
||||
/**
|
||||
* Sets the \a order for layers in the project. This list reflects the order of layers shown in
|
||||
* the layer tree for the project.
|
||||
* @note added in QGIS 3.0
|
||||
* @see layerOrder()
|
||||
*/
|
||||
void setLayerOrder( const QList< QgsMapLayer * > &order );
|
||||
|
||||
signals:
|
||||
//! emitted when project is being read
|
||||
void readProject( const QDomDocument & );
|
||||
@ -892,6 +909,13 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
*/
|
||||
void legendLayersAdded( const QList<QgsMapLayer *> &layers );
|
||||
|
||||
/**
|
||||
* Emitted when the order of layers in the project is changed.
|
||||
* @note added in QGIS 3.0
|
||||
* @see setLayerOrder()
|
||||
*/
|
||||
void layerOrderChanged();
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@ -951,6 +975,8 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
|
||||
QMap<QString, QgsMapLayer *> mMapLayers;
|
||||
|
||||
QgsWeakMapLayerPointerList mLayerOrder;
|
||||
|
||||
QString mErrorMessage;
|
||||
|
||||
QgsProjectBadLayerHandler *mBadLayerHandler = nullptr;
|
||||
|
@ -140,6 +140,7 @@ void QgsLayerTreeMapCanvasBridge::setCanvasLayers()
|
||||
int currentLayerCount = layerNodes.count();
|
||||
bool firstLayers = mAutoSetupOnFirstLayer && mLastLayerCount == 0 && currentLayerCount != 0;
|
||||
|
||||
QgsProject::instance()->setLayerOrder( canvasLayers );
|
||||
mCanvas->setLayers( canvasLayers );
|
||||
if ( mOverviewCanvas )
|
||||
mOverviewCanvas->setLayers( overviewLayers );
|
||||
|
@ -18,12 +18,19 @@ import os
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
from qgis.core import QgsProject, QgsApplication, QgsUnitTypes, QgsCoordinateReferenceSystem
|
||||
|
||||
from qgis.core import (QgsProject,
|
||||
QgsApplication,
|
||||
QgsUnitTypes,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsVectorLayer)
|
||||
from qgis.gui import (QgsLayerTreeMapCanvasBridge,
|
||||
QgsMapCanvas)
|
||||
from qgis.testing import start_app, unittest
|
||||
from utilities import (unitTestDataPath)
|
||||
from qgis.PyQt.QtCore import QDir
|
||||
from qgis.PyQt.QtTest import QSignalSpy
|
||||
|
||||
start_app()
|
||||
app = start_app()
|
||||
TEST_DATA_DIR = unitTestDataPath()
|
||||
|
||||
|
||||
@ -176,6 +183,85 @@ class TestQgsProject(unittest.TestCase):
|
||||
expected = ['polys', 'lines']
|
||||
self.assertEqual(sorted(layers_names), sorted(expected))
|
||||
|
||||
def testLayerOrder(self):
|
||||
""" test project layer order"""
|
||||
prj = QgsProject()
|
||||
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])
|
||||
|
||||
layer_order_changed_spy = QSignalSpy(prj.layerOrderChanged)
|
||||
prj.setLayerOrder([layer2, layer])
|
||||
self.assertEqual(len(layer_order_changed_spy), 1)
|
||||
prj.setLayerOrder([layer2, layer])
|
||||
self.assertEqual(len(layer_order_changed_spy), 1) # no signal, order not changed
|
||||
|
||||
self.assertEqual(prj.layerOrder(), [layer2, layer])
|
||||
prj.setLayerOrder([layer])
|
||||
self.assertEqual(prj.layerOrder(), [layer])
|
||||
self.assertEqual(len(layer_order_changed_spy), 2)
|
||||
|
||||
# remove a layer
|
||||
prj.setLayerOrder([layer2, layer, layer3])
|
||||
self.assertEqual(len(layer_order_changed_spy), 3)
|
||||
prj.removeMapLayer(layer)
|
||||
self.assertEqual(prj.layerOrder(), [layer2, layer3])
|
||||
self.assertEqual(len(layer_order_changed_spy), 4)
|
||||
|
||||
# save and restore
|
||||
file_name = os.path.join(str(QDir.tempPath()), 'proj.qgs')
|
||||
prj.setFileName(file_name)
|
||||
prj.write()
|
||||
prj2 = QgsProject()
|
||||
prj2.setFileName(file_name)
|
||||
prj2.read()
|
||||
self.assertEqual([l.id() for l in prj2.layerOrder()], [layer2.id(), layer3.id()])
|
||||
|
||||
# clear project
|
||||
prj.clear()
|
||||
self.assertEqual(prj.layerOrder(), [])
|
||||
|
||||
def testLayerOrderUpdatedThroughBridge(self):
|
||||
""" test that project layer order is updated when layer tree changes """
|
||||
|
||||
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 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 layer tree order
|
||||
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()])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user