Skip to content

Commit 1e6bffe

Browse files
committedMar 12, 2017
Allow setting map canvases to auto follow a map theme
1 parent cd7b19c commit 1e6bffe

File tree

7 files changed

+198
-15
lines changed

7 files changed

+198
-15
lines changed
 

‎python/gui/qgsmapcanvas.sip

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -185,16 +185,11 @@ class QgsMapCanvas : QGraphicsView
185185
//! @note added in 2.12
186186
void setLayerStyleOverrides( const QMap<QString, QString>& overrides );
187187

188-
//! Get the current coordinate transform
189-
const QgsMapToPixel* getCoordinateTransform();
190-
191-
//! Find out whether rendering is in progress
188+
void setTheme( const QString &theme );
189+
QString theme() const;
190+
const QgsMapToPixel *getCoordinateTransform();
192191
bool isDrawing();
193-
194-
//! returns current layer (set by legend widget)
195-
QgsMapLayer* currentLayer();
196-
197-
//! set wheel zoom factor (should be greater than 1)
192+
QgsMapLayer *currentLayer();
198193
void setWheelFactor( double factor );
199194

200195
//! Zoom to a specific scale
@@ -434,12 +429,9 @@ class QgsMapCanvas : QGraphicsView
434429
//! @note added in 2.8
435430
void currentLayerChanged( QgsMapLayer* layer );
436431

437-
//! Emitted when the configuration of overridden layer styles changes
438-
//! @note added in 2.12
439432
void layerStyleOverridesChanged();
440-
441-
//! emit a message (usually to be displayed in a message bar)
442-
void messageEmitted( const QString& title, const QString& message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );
433+
void themeChanged( const QString &theme );
434+
void messageEmitted( const QString &title, const QString &message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );
443435

444436
protected:
445437

‎src/gui/qgsmapcanvas.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ email : sherman at mrcc.com
6363
#include "qgsrubberband.h"
6464
#include "qgsvectorlayer.h"
6565
#include "qgscursors.h"
66+
#include "qgsmapthemecollection.h"
6667
#include <cmath>
6768

6869

@@ -140,6 +141,8 @@ QgsMapCanvas::QgsMapCanvas( QWidget *parent )
140141
connect( QgsProject::instance(), &QgsProject::writeProject,
141142
this, &QgsMapCanvas::writeProject );
142143

144+
connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeChanged, this, &QgsMapCanvas::mapThemeChanged );
145+
143146
mSettings.setFlag( QgsMapSettings::DrawEditingInfo );
144147
mSettings.setFlag( QgsMapSettings::UseRenderingOptimization );
145148
mSettings.setFlag( QgsMapSettings::RenderPartialOutput );
@@ -482,6 +485,16 @@ void QgsMapCanvas::refreshMap()
482485

483486
mSettings.setExpressionContext( expressionContext );
484487

488+
if ( !mTheme.isEmpty() )
489+
{
490+
mSettings.setLayerStyleOverrides( QgsProject::instance()->mapThemeCollection()->mapThemeStyleOverrides( mTheme ) );
491+
mSettings.setLayers( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
492+
}
493+
else
494+
{
495+
mSettings.setLayerStyleOverrides( QMap< QString, QString>() );
496+
}
497+
485498
// create the renderer job
486499
Q_ASSERT( !mJob );
487500
mJobCanceled = false;
@@ -518,6 +531,16 @@ void QgsMapCanvas::refreshMap()
518531
emit renderStarting();
519532
}
520533

534+
void QgsMapCanvas::mapThemeChanged( const QString &theme )
535+
{
536+
if ( theme == mTheme )
537+
{
538+
setLayers( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
539+
clearCache();
540+
refresh();
541+
}
542+
}
543+
521544

522545
void QgsMapCanvas::rendererJobFinished()
523546
{
@@ -1595,6 +1618,15 @@ void QgsMapCanvas::setLayerStyleOverrides( const QMap<QString, QString> &overrid
15951618
emit layerStyleOverridesChanged();
15961619
}
15971620

1621+
void QgsMapCanvas::setTheme( const QString &theme )
1622+
{
1623+
if ( mTheme == theme )
1624+
return;
1625+
1626+
mTheme = theme;
1627+
clearCache();
1628+
emit themeChanged( theme );
1629+
}
15981630

15991631
void QgsMapCanvas::setRenderFlag( bool flag )
16001632
{

‎src/gui/qgsmapcanvas.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class QgsRubberBand;
7272
class GUI_EXPORT QgsMapCanvas : public QGraphicsView
7373
{
7474
Q_OBJECT
75+
Q_PROPERTY( QString theme READ theme WRITE setTheme NOTIFY themeChanged )
7576

7677
public:
7778

@@ -273,6 +274,21 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
273274
//! @note added in 2.12
274275
void setLayerStyleOverrides( const QMap<QString, QString> &overrides );
275276

277+
/**
278+
* Sets a map \a theme to show in the canvas. The theme name must match
279+
* a theme present in the associated project's QgsMapThemeCollection.
280+
* @note added in QGIS 3.0
281+
* @see theme()
282+
*/
283+
void setTheme( const QString &theme );
284+
285+
/**
286+
* Returns the map's theme shown in the canvas, if set.
287+
* @note added in QGIS 3.0
288+
* @see setTheme()
289+
*/
290+
QString theme() const { return mTheme; }
291+
276292
//! Get the current coordinate transform
277293
const QgsMapToPixel *getCoordinateTransform();
278294

@@ -472,6 +488,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
472488

473489
void refreshMap();
474490

491+
void mapThemeChanged( const QString &theme );
492+
475493
signals:
476494

477495
/** Emits current mouse position
@@ -548,6 +566,13 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
548566
//! @note added in 2.12
549567
void layerStyleOverridesChanged();
550568

569+
/**
570+
* Emitted when the map theme set for the canvas is changed.
571+
* @see setTheme()
572+
* @note added in QGIS 3.0
573+
*/
574+
void themeChanged( const QString &theme );
575+
551576
//! emit a message (usually to be displayed in a message bar)
552577
void messageEmitted( const QString &title, const QString &message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );
553578

@@ -708,6 +733,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
708733

709734
QTimer mAutoRefreshTimer;
710735

736+
QString mTheme;
737+
711738
//! Force a resize of the map canvas item
712739
//! @note added in 2.16
713740
void updateMapSize();

‎tests/src/python/test_qgsmapcanvas.py

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
QgsVectorLayer,
2020
QgsFeature,
2121
QgsGeometry,
22-
QgsMultiRenderChecker)
22+
QgsMultiRenderChecker,
23+
QgsFillSymbol,
24+
QgsSingleSymbolRenderer,
25+
QgsMapThemeCollection,
26+
QgsProject)
2327
from qgis.gui import (QgsMapCanvas)
2428

2529
from qgis.PyQt.QtCore import QDir
@@ -179,6 +183,134 @@ def testCancelAndDestroy(self):
179183
canvas.stopRendering()
180184
del canvas
181185

186+
def testMapTheme(self):
187+
canvas = QgsMapCanvas()
188+
canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326))
189+
canvas.setFrameStyle(0)
190+
canvas.resize(600, 400)
191+
self.assertEqual(canvas.width(), 600)
192+
self.assertEqual(canvas.height(), 400)
193+
194+
layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string",
195+
"layer", "memory")
196+
# add a polygon to layer
197+
f = QgsFeature()
198+
f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45)))
199+
self.assertTrue(layer.dataProvider().addFeatures([f]))
200+
201+
# create a style
202+
sym1 = QgsFillSymbol.createSimple({'color': '#ffb200'})
203+
renderer = QgsSingleSymbolRenderer(sym1)
204+
layer.setRenderer(renderer)
205+
206+
canvas.setLayers([layer])
207+
canvas.setExtent(QgsRectangle(10, 30, 20, 35))
208+
canvas.show()
209+
210+
# need to wait until first redraw can occur (note that we first need to wait till drawing starts!)
211+
while not canvas.isDrawing():
212+
app.processEvents()
213+
while canvas.isDrawing():
214+
app.processEvents()
215+
216+
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))
217+
218+
# add some styles
219+
layer.styleManager().addStyleFromLayer('style1')
220+
sym2 = QgsFillSymbol.createSimple({'color': '#00b2ff'})
221+
renderer2 = QgsSingleSymbolRenderer(sym2)
222+
layer.setRenderer(renderer2)
223+
layer.styleManager().addStyleFromLayer('style2')
224+
225+
canvas.refresh()
226+
while not canvas.isDrawing():
227+
app.processEvents()
228+
while canvas.isDrawing():
229+
app.processEvents()
230+
self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas))
231+
232+
layer.styleManager().setCurrentStyle('style1')
233+
canvas.refresh()
234+
while not canvas.isDrawing():
235+
app.processEvents()
236+
while canvas.isDrawing():
237+
app.processEvents()
238+
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))
239+
240+
# ok, so all good with setting/rendering map styles
241+
# try setting canvas to a particular theme
242+
243+
# make some themes...
244+
theme1 = QgsMapThemeCollection.MapThemeRecord()
245+
record1 = QgsMapThemeCollection.MapThemeLayerRecord(layer)
246+
record1.currentStyle = 'style1'
247+
record1.usingCurrentStyle = True
248+
theme1.setLayerRecords([record1])
249+
250+
theme2 = QgsMapThemeCollection.MapThemeRecord()
251+
record2 = QgsMapThemeCollection.MapThemeLayerRecord(layer)
252+
record2.currentStyle = 'style2'
253+
record2.usingCurrentStyle = True
254+
theme2.setLayerRecords([record2])
255+
256+
QgsProject.instance().mapThemeCollection().insert('theme1', theme1)
257+
QgsProject.instance().mapThemeCollection().insert('theme2', theme2)
258+
259+
canvas.setTheme('theme2')
260+
canvas.refresh()
261+
while not canvas.isDrawing():
262+
app.processEvents()
263+
while canvas.isDrawing():
264+
app.processEvents()
265+
self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas))
266+
267+
canvas.setTheme('theme1')
268+
canvas.refresh()
269+
while not canvas.isDrawing():
270+
app.processEvents()
271+
while canvas.isDrawing():
272+
app.processEvents()
273+
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))
274+
275+
# add another layer
276+
layer2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string",
277+
"layer2", "memory")
278+
f = QgsFeature()
279+
f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45)))
280+
self.assertTrue(layer2.dataProvider().addFeatures([f]))
281+
282+
# create a style
283+
sym1 = QgsFillSymbol.createSimple({'color': '#b2ff00'})
284+
renderer = QgsSingleSymbolRenderer(sym1)
285+
layer2.setRenderer(renderer)
286+
287+
# rerender canvas - should NOT show new layer
288+
canvas.refresh()
289+
while not canvas.isDrawing():
290+
app.processEvents()
291+
while canvas.isDrawing():
292+
app.processEvents()
293+
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))
294+
# test again - this time refresh all layers
295+
canvas.refreshAllLayers()
296+
while not canvas.isDrawing():
297+
app.processEvents()
298+
while canvas.isDrawing():
299+
app.processEvents()
300+
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))
301+
302+
# add layer 2 to theme1
303+
record3 = QgsMapThemeCollection.MapThemeLayerRecord(layer2)
304+
theme1.setLayerRecords([record3])
305+
QgsProject.instance().mapThemeCollection().update('theme1', theme1)
306+
307+
canvas.refresh()
308+
while not canvas.isDrawing():
309+
app.processEvents()
310+
while canvas.isDrawing():
311+
app.processEvents()
312+
self.assertTrue(self.canvasImageCheck('theme3', 'theme3', canvas))
313+
182314
def canvasImageCheck(self, name, reference_image, canvas):
183315
self.report += "<h2>Render {}</h2>\n".format(name)
184316
temp_dir = QDir.tempPath() + '/'
Loading
Loading
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.