diff --git a/python/core/qgsmapthemecollection.sip b/python/core/qgsmapthemecollection.sip index 48767b4226f..9e69b289500 100644 --- a/python/core/qgsmapthemecollection.sip +++ b/python/core/qgsmapthemecollection.sip @@ -102,62 +102,22 @@ class QgsMapThemeCollection : QObject //! Returns a list of existing map theme names. QStringList mapThemes() const; - /** - * Returns the recorded state of a map theme. - */ - MapThemeRecord mapThemeState( const QString& name ) const; - /** - * Returns the list of layer IDs that are visible for the specified map theme. - * - * @note The order of the returned list is not guaranteed to reflect the order of layers - * in the canvas. - * @note Added in QGIS 3.0 - */ - QStringList mapThemeVisibleLayerIds( const QString& name ) const; - /** - * Returns the list of layers that are visible for the specified map theme. - * - * @note The order of the returned list is not guaranteed to reflect the order of layers - * in the canvas. - * @note Added in QGIS 3.0 - */ - QList mapThemeVisibleLayers( const QString& name ) const; - /** - * Get layer style overrides (for QgsMapSettings) of the visible layers for given map theme. - */ - QMap mapThemeStyleOverrides( const QString& name ); - /** - * Reads the map theme collection state from XML - * @param doc DOM document - * @see writeXml - */ - void readXml( const QDomDocument& doc ); + MapThemeRecord mapThemeState( const QString &name ) const; + QStringList mapThemeVisibleLayerIds( const QString &name ) const; + QList mapThemeVisibleLayers( const QString &name ) const; + QMap mapThemeStyleOverrides( const QString &name ); + void readXml( const QDomDocument &doc ); + void writeXml( QDomDocument &doc ); + static MapThemeRecord createThemeFromCurrentState( QgsLayerTreeGroup *root, QgsLayerTreeModel *model ); + void applyTheme( const QString &name, QgsLayerTreeGroup *root, QgsLayerTreeModel *model ); + QgsProject *project(); + void setProject( QgsProject *project ); + QList< QgsMapLayer * > masterLayerOrder() const; - /** Writes the map theme collection state to XML. - * @param doc DOM document - * @see readXml - */ - void writeXml( QDomDocument& doc ); - - /** - * Static method to create theme from the current state of layer visibilities in layer tree, - * current style of layers and check state of legend items (from a layer tree model). - * @note added in QGIS 3.0 - */ - static MapThemeRecord createThemeFromCurrentState( QgsLayerTreeGroup* root, QgsLayerTreeModel* model ); - - /** - * Apply theme given by its name and modify layer tree, current style of layers and checked - * legend items of passed layer tree model. - * @note added in QGIS 3.0 - */ - void applyTheme( const QString& name, QgsLayerTreeGroup* root, QgsLayerTreeModel* model ); - QgsProject* project(); - void setProject( QgsProject* project ); signals: void mapThemesChanged(); diff --git a/src/core/qgsmapthemecollection.cpp b/src/core/qgsmapthemecollection.cpp index fddbe42c74a..eedfc5ab646 100644 --- a/src/core/qgsmapthemecollection.cpp +++ b/src/core/qgsmapthemecollection.cpp @@ -175,6 +175,14 @@ void QgsMapThemeCollection::setProject( QgsProject *project ) emit projectChanged(); } +QList QgsMapThemeCollection::masterLayerOrder() const +{ + if ( !mProject ) + return QList< QgsMapLayer * >(); + + return mProject->layerOrder(); +} + bool QgsMapThemeCollection::hasMapTheme( const QString &name ) const { @@ -229,23 +237,26 @@ QStringList QgsMapThemeCollection::mapThemes() const QStringList QgsMapThemeCollection::mapThemeVisibleLayerIds( const QString &name ) const { QStringList layerIds; - Q_FOREACH ( const MapThemeLayerRecord &layerRec, mMapThemes.value( name ).mLayerRecords ) + Q_FOREACH ( QgsMapLayer *layer, mapThemeVisibleLayers( name ) ) { - if ( layerRec.layer() ) - layerIds << layerRec.layer()->id(); + layerIds << layer->id(); } return layerIds; } - QList QgsMapThemeCollection::mapThemeVisibleLayers( const QString &name ) const { QList layers; - Q_FOREACH ( const MapThemeLayerRecord &layerRec, mMapThemes.value( name ).mLayerRecords ) + const QList &recs = mMapThemes.value( name ).mLayerRecords; + Q_FOREACH ( QgsMapLayer *layer, masterLayerOrder() ) { - if ( layerRec.layer() ) - layers << layerRec.layer(); + Q_FOREACH ( const MapThemeLayerRecord &layerRec, recs ) + { + if ( layerRec.layer() == layer ) + layers << layerRec.layer(); + } } + return layers; } diff --git a/src/core/qgsmapthemecollection.h b/src/core/qgsmapthemecollection.h index 9bed2f93c46..6adcd96ac14 100644 --- a/src/core/qgsmapthemecollection.h +++ b/src/core/qgsmapthemecollection.h @@ -242,6 +242,13 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject */ void setProject( QgsProject *project ); + /** + * Returns the master layer order (this will always match the project's QgsProject::layerOrder() ). + * All map themes will maintain the same layer order as the master layer order. + * @note added in QGIS 3.0 + */ + QList< QgsMapLayer * > masterLayerOrder() const; + signals: /** diff --git a/tests/src/python/test_qgsmapthemecollection.py b/tests/src/python/test_qgsmapthemecollection.py index bdc6833f98c..37360655291 100644 --- a/tests/src/python/test_qgsmapthemecollection.py +++ b/tests/src/python/test_qgsmapthemecollection.py @@ -97,6 +97,58 @@ class TestQgsMapThemeCollection(unittest.TestCase): app.processEvents() self.assertEqual(len(theme_changed_spy), 6) # signal should be emitted - layer is in record + def testMasterLayerOrder(self): + """ test master 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]) + + prj.setLayerOrder([layer2, layer]) + self.assertEqual(prj.mapThemeCollection().masterLayerOrder(), [layer2, layer]) + + prj.setLayerOrder([layer, layer2, layer3]) + # make some themes... + theme1 = QgsMapThemeCollection.MapThemeRecord() + theme1.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer3), + QgsMapThemeCollection.MapThemeLayerRecord(layer)]) + + theme2 = QgsMapThemeCollection.MapThemeRecord() + theme2.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer3), + QgsMapThemeCollection.MapThemeLayerRecord(layer2), + QgsMapThemeCollection.MapThemeLayerRecord(layer)]) + + theme3 = QgsMapThemeCollection.MapThemeRecord() + theme3.setLayerRecords([QgsMapThemeCollection.MapThemeLayerRecord(layer2), + QgsMapThemeCollection.MapThemeLayerRecord(layer)]) + + prj.mapThemeCollection().insert('theme1', theme1) + prj.mapThemeCollection().insert('theme2', theme2) + prj.mapThemeCollection().insert('theme3', theme3) + + #order of layers in theme should respect master order + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer, layer3]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer, layer2, layer3]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer, layer2]) + + # also check ids! + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer.id(), layer3.id()]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), [layer.id(), layer2.id(), layer3.id()]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer.id(), layer2.id()]) + + # reset master order + prj.setLayerOrder([layer2, layer3, layer]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme1'), [layer3, layer]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme2'), [layer2, layer3, layer]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayers('theme3'), [layer2, layer]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme1'), [layer3.id(), layer.id()]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme2'), [layer2.id(), layer3.id(), layer.id()]) + self.assertEqual(prj.mapThemeCollection().mapThemeVisibleLayerIds('theme3'), [layer2.id(), layer.id()]) + if __name__ == '__main__': unittest.main()