mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-16 00:03:12 -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();
|
void reloadAllLayers();
|
||||||
|
|
||||||
|
QList< QgsMapLayer * > layerOrder() const;
|
||||||
|
void setLayerOrder( const QList< QgsMapLayer * > &order );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
//! emitted when project is being read
|
//! emitted when project is being read
|
||||||
void readProject( const QDomDocument& );
|
void readProject( const QDomDocument& );
|
||||||
@ -623,12 +626,12 @@ class QgsProject : QObject, QgsExpressionContextGenerator
|
|||||||
*/
|
*/
|
||||||
//TODO QGIS 3.0 - rename to past tense
|
//TODO QGIS 3.0 - rename to past tense
|
||||||
void removeAll();
|
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 layerOrderChanged();
|
||||||
|
|
||||||
void legendLayersAdded( const QList<QgsMapLayer*>& layers );
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/**
|
/**
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "qgsvectordataprovider.h"
|
#include "qgsvectordataprovider.h"
|
||||||
#include "qgsprojectbadlayerhandler.h"
|
#include "qgsprojectbadlayerhandler.h"
|
||||||
#include "qgssettings.h"
|
#include "qgssettings.h"
|
||||||
|
#include "qgsmaplayerlistutils.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
@ -460,6 +461,7 @@ void QgsProject::clear()
|
|||||||
mEvaluateDefaultValues = false;
|
mEvaluateDefaultValues = false;
|
||||||
mDirty = false;
|
mDirty = false;
|
||||||
mCustomVariables.clear();
|
mCustomVariables.clear();
|
||||||
|
mLayerOrder.clear();
|
||||||
|
|
||||||
mEmbeddedLayers.clear();
|
mEmbeddedLayers.clear();
|
||||||
mRelationManager->clear();
|
mRelationManager->clear();
|
||||||
@ -881,6 +883,20 @@ bool QgsProject::read()
|
|||||||
// load embedded groups and layers
|
// load embedded groups and layers
|
||||||
loadEmbeddedNodes( mRootGroup );
|
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
|
// now that layers are loaded, we can resolve layer tree's references to the layers
|
||||||
mRootGroup->resolveReferences( this );
|
mRootGroup->resolveReferences( this );
|
||||||
|
|
||||||
@ -1244,6 +1260,16 @@ bool QgsProject::write()
|
|||||||
|
|
||||||
qgisNode.appendChild( projectLayersNode );
|
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
|
// now add the optional extra properties
|
||||||
|
|
||||||
dump_( mProperties );
|
dump_( mProperties );
|
||||||
@ -2091,6 +2117,8 @@ void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
|||||||
QStringList layerIds;
|
QStringList layerIds;
|
||||||
QList<QgsMapLayer *> layerList;
|
QList<QgsMapLayer *> layerList;
|
||||||
|
|
||||||
|
bool layerOrderHasChanged = false;
|
||||||
|
QList< QgsMapLayer * > currentOrder = layerOrder();
|
||||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||||
{
|
{
|
||||||
// check layer and the registry contains it
|
// check layer and the registry contains it
|
||||||
@ -2098,6 +2126,7 @@ void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
|||||||
{
|
{
|
||||||
layerIds << layer->id();
|
layerIds << layer->id();
|
||||||
layerList << layer;
|
layerList << layer;
|
||||||
|
layerOrderHasChanged = layerOrderHasChanged || currentOrder.contains( layer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2121,6 +2150,8 @@ void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
|||||||
}
|
}
|
||||||
|
|
||||||
emit layersRemoved( layerIds );
|
emit layersRemoved( layerIds );
|
||||||
|
if ( layerOrderHasChanged )
|
||||||
|
emit layerOrderChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsProject::removeMapLayer( const QString &layerId )
|
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 )
|
void QgsProject::onMapLayerDeleted( QObject *obj )
|
||||||
{
|
{
|
||||||
QString id = mMapLayers.key( static_cast<QgsMapLayer *>( obj ) );
|
QString id = mMapLayers.key( static_cast<QgsMapLayer *>( obj ) );
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "qgsexpressioncontextgenerator.h"
|
#include "qgsexpressioncontextgenerator.h"
|
||||||
#include "qgscoordinatereferencesystem.h"
|
#include "qgscoordinatereferencesystem.h"
|
||||||
#include "qgsprojectproperty.h"
|
#include "qgsprojectproperty.h"
|
||||||
|
#include "qgsmaplayer.h"
|
||||||
|
|
||||||
class QFileInfo;
|
class QFileInfo;
|
||||||
class QDomDocument;
|
class QDomDocument;
|
||||||
@ -690,6 +691,22 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
|||||||
*/
|
*/
|
||||||
void reloadAllLayers();
|
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:
|
signals:
|
||||||
//! emitted when project is being read
|
//! emitted when project is being read
|
||||||
void readProject( const QDomDocument & );
|
void readProject( const QDomDocument & );
|
||||||
@ -892,6 +909,13 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
|||||||
*/
|
*/
|
||||||
void legendLayersAdded( const QList<QgsMapLayer *> &layers );
|
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:
|
public slots:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -951,6 +975,8 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
|||||||
|
|
||||||
QMap<QString, QgsMapLayer *> mMapLayers;
|
QMap<QString, QgsMapLayer *> mMapLayers;
|
||||||
|
|
||||||
|
QgsWeakMapLayerPointerList mLayerOrder;
|
||||||
|
|
||||||
QString mErrorMessage;
|
QString mErrorMessage;
|
||||||
|
|
||||||
QgsProjectBadLayerHandler *mBadLayerHandler = nullptr;
|
QgsProjectBadLayerHandler *mBadLayerHandler = nullptr;
|
||||||
|
@ -140,6 +140,7 @@ void QgsLayerTreeMapCanvasBridge::setCanvasLayers()
|
|||||||
int currentLayerCount = layerNodes.count();
|
int currentLayerCount = layerNodes.count();
|
||||||
bool firstLayers = mAutoSetupOnFirstLayer && mLastLayerCount == 0 && currentLayerCount != 0;
|
bool firstLayers = mAutoSetupOnFirstLayer && mLastLayerCount == 0 && currentLayerCount != 0;
|
||||||
|
|
||||||
|
QgsProject::instance()->setLayerOrder( canvasLayers );
|
||||||
mCanvas->setLayers( canvasLayers );
|
mCanvas->setLayers( canvasLayers );
|
||||||
if ( mOverviewCanvas )
|
if ( mOverviewCanvas )
|
||||||
mOverviewCanvas->setLayers( overviewLayers );
|
mOverviewCanvas->setLayers( overviewLayers );
|
||||||
|
@ -18,12 +18,19 @@ import os
|
|||||||
|
|
||||||
import qgis # NOQA
|
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 qgis.testing import start_app, unittest
|
||||||
from utilities import (unitTestDataPath)
|
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()
|
TEST_DATA_DIR = unitTestDataPath()
|
||||||
|
|
||||||
|
|
||||||
@ -176,6 +183,85 @@ class TestQgsProject(unittest.TestCase):
|
|||||||
expected = ['polys', 'lines']
|
expected = ['polys', 'lines']
|
||||||
self.assertEqual(sorted(layers_names), sorted(expected))
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user