Skip to content

Commit 9faa628

Browse files
committed
Layer order in map themes must always respect project layer order
1 parent 6cfc6a1 commit 9faa628

File tree

4 files changed

+88
-58
lines changed

4 files changed

+88
-58
lines changed

python/core/qgsmapthemecollection.sip

Lines changed: 11 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -102,62 +102,22 @@ class QgsMapThemeCollection : QObject
102102
//! Returns a list of existing map theme names.
103103
QStringList mapThemes() const;
104104

105-
/**
106-
* Returns the recorded state of a map theme.
107-
*/
108-
MapThemeRecord mapThemeState( const QString& name ) const;
109105

110-
/**
111-
* Returns the list of layer IDs that are visible for the specified map theme.
112-
*
113-
* @note The order of the returned list is not guaranteed to reflect the order of layers
114-
* in the canvas.
115-
* @note Added in QGIS 3.0
116-
*/
117-
QStringList mapThemeVisibleLayerIds( const QString& name ) const;
118106

119-
/**
120-
* Returns the list of layers that are visible for the specified map theme.
121-
*
122-
* @note The order of the returned list is not guaranteed to reflect the order of layers
123-
* in the canvas.
124-
* @note Added in QGIS 3.0
125-
*/
126-
QList<QgsMapLayer*> mapThemeVisibleLayers( const QString& name ) const;
127107

128-
/**
129-
* Get layer style overrides (for QgsMapSettings) of the visible layers for given map theme.
130-
*/
131-
QMap<QString, QString> mapThemeStyleOverrides( const QString& name );
132108

133-
/**
134-
* Reads the map theme collection state from XML
135-
* @param doc DOM document
136-
* @see writeXml
137-
*/
138-
void readXml( const QDomDocument& doc );
109+
MapThemeRecord mapThemeState( const QString &name ) const;
110+
QStringList mapThemeVisibleLayerIds( const QString &name ) const;
111+
QList<QgsMapLayer *> mapThemeVisibleLayers( const QString &name ) const;
112+
QMap<QString, QString> mapThemeStyleOverrides( const QString &name );
113+
void readXml( const QDomDocument &doc );
114+
void writeXml( QDomDocument &doc );
115+
static MapThemeRecord createThemeFromCurrentState( QgsLayerTreeGroup *root, QgsLayerTreeModel *model );
116+
void applyTheme( const QString &name, QgsLayerTreeGroup *root, QgsLayerTreeModel *model );
117+
QgsProject *project();
118+
void setProject( QgsProject *project );
119+
QList< QgsMapLayer * > masterLayerOrder() const;
139120

140-
/** Writes the map theme collection state to XML.
141-
* @param doc DOM document
142-
* @see readXml
143-
*/
144-
void writeXml( QDomDocument& doc );
145-
146-
/**
147-
* Static method to create theme from the current state of layer visibilities in layer tree,
148-
* current style of layers and check state of legend items (from a layer tree model).
149-
* @note added in QGIS 3.0
150-
*/
151-
static MapThemeRecord createThemeFromCurrentState( QgsLayerTreeGroup* root, QgsLayerTreeModel* model );
152-
153-
/**
154-
* Apply theme given by its name and modify layer tree, current style of layers and checked
155-
* legend items of passed layer tree model.
156-
* @note added in QGIS 3.0
157-
*/
158-
void applyTheme( const QString& name, QgsLayerTreeGroup* root, QgsLayerTreeModel* model );
159-
QgsProject* project();
160-
void setProject( QgsProject* project );
161121
signals:
162122

163123
void mapThemesChanged();

src/core/qgsmapthemecollection.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,14 @@ void QgsMapThemeCollection::setProject( QgsProject *project )
175175
emit projectChanged();
176176
}
177177

178+
QList<QgsMapLayer *> QgsMapThemeCollection::masterLayerOrder() const
179+
{
180+
if ( !mProject )
181+
return QList< QgsMapLayer * >();
182+
183+
return mProject->layerOrder();
184+
}
185+
178186

179187
bool QgsMapThemeCollection::hasMapTheme( const QString &name ) const
180188
{
@@ -229,23 +237,26 @@ QStringList QgsMapThemeCollection::mapThemes() const
229237
QStringList QgsMapThemeCollection::mapThemeVisibleLayerIds( const QString &name ) const
230238
{
231239
QStringList layerIds;
232-
Q_FOREACH ( const MapThemeLayerRecord &layerRec, mMapThemes.value( name ).mLayerRecords )
240+
Q_FOREACH ( QgsMapLayer *layer, mapThemeVisibleLayers( name ) )
233241
{
234-
if ( layerRec.layer() )
235-
layerIds << layerRec.layer()->id();
242+
layerIds << layer->id();
236243
}
237244
return layerIds;
238245
}
239246

240-
241247
QList<QgsMapLayer *> QgsMapThemeCollection::mapThemeVisibleLayers( const QString &name ) const
242248
{
243249
QList<QgsMapLayer *> layers;
244-
Q_FOREACH ( const MapThemeLayerRecord &layerRec, mMapThemes.value( name ).mLayerRecords )
250+
const QList<MapThemeLayerRecord> &recs = mMapThemes.value( name ).mLayerRecords;
251+
Q_FOREACH ( QgsMapLayer *layer, masterLayerOrder() )
245252
{
246-
if ( layerRec.layer() )
247-
layers << layerRec.layer();
253+
Q_FOREACH ( const MapThemeLayerRecord &layerRec, recs )
254+
{
255+
if ( layerRec.layer() == layer )
256+
layers << layerRec.layer();
257+
}
248258
}
259+
249260
return layers;
250261
}
251262

src/core/qgsmapthemecollection.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,13 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
242242
*/
243243
void setProject( QgsProject *project );
244244

245+
/**
246+
* Returns the master layer order (this will always match the project's QgsProject::layerOrder() ).
247+
* All map themes will maintain the same layer order as the master layer order.
248+
* @note added in QGIS 3.0
249+
*/
250+
QList< QgsMapLayer * > masterLayerOrder() const;
251+
245252
signals:
246253

247254
/**

tests/src/python/test_qgsmapthemecollection.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,58 @@ def testThemeChanged(self):
9797
app.processEvents()
9898
self.assertEqual(len(theme_changed_spy), 6) # signal should be emitted - layer is in record
9999

100+
def testMasterLayerOrder(self):
101+
""" test master layer order"""
102+
prj = QgsProject()
103+
layer = QgsVectorLayer("Point?field=fldtxt:string",
104+
"layer1", "memory")
105+
layer2 = QgsVectorLayer("Point?field=fldtxt:string",
106+
"layer2", "memory")
107+
layer3 = QgsVectorLayer("Point?field=fldtxt:string",
108+
"layer3", "memory")
109+
prj.addMapLayers([layer, layer2, layer3])
110+
111+
prj.setLayerOrder([layer2, layer])
112+
self.assertEqual(prj.mapThemeCollection().masterLayerOrder(), [layer2, layer])
113+
114+
prj.setLayerOrder([layer, layer2, layer3])
115+
# make some themes...
116+
theme1 = QgsMapThemeCollection.MapThemeRecord()
117+
theme1.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer3),
118+
QgsMapThemeCollection.MapThemeLayerRecord(layer)])
119+
120+
theme2 = QgsMapThemeCollection.MapThemeRecord()
121+
theme2.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer3),
122+
QgsMapThemeCollection.MapThemeLayerRecord(layer2),
123+
QgsMapThemeCollection.MapThemeLayerRecord(layer)])
124+
125+
theme3 = QgsMapThemeCollection.MapThemeRecord()
126+
theme3.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer2),
127+
QgsMapThemeCollection.MapThemeLayerRecord(layer)])
128+
129+
prj.mapThemeCollection().insert('theme1', theme1)
130+
prj.mapThemeCollection().insert('theme2', theme2)
131+
prj.mapThemeCollection().insert('theme3', theme3)
132+
133+
#order of layers in theme should respect master order
134+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer, layer3])
135+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer, layer2, layer3])
136+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer, layer2])
137+
138+
# also check ids!
139+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer.id(), layer3.id()])
140+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), [layer.id(), layer2.id(), layer3.id()])
141+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer.id(), layer2.id()])
142+
143+
# reset master order
144+
prj.setLayerOrder([layer2, layer3, layer])
145+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer3, layer])
146+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer2, layer3, layer])
147+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer2, layer])
148+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer3.id(), layer.id()])
149+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), [layer2.id(), layer3.id(), layer.id()])
150+
self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer2.id(), layer.id()])
151+
100152

101153
if __name__ == '__main__':
102154
unittest.main()

0 commit comments

Comments
 (0)