Skip to content
Permalink
Browse files

Allow setting map canvases to auto follow a map theme

  • Loading branch information
nyalldawson committed Mar 12, 2017
1 parent cd7b19c commit 1e6bffe414fe66698baaf7befe86f03bcc12375e
@@ -185,16 +185,11 @@ class QgsMapCanvas : QGraphicsView
//! @note added in 2.12
void setLayerStyleOverrides( const QMap<QString, QString>& overrides );

//! Get the current coordinate transform
const QgsMapToPixel* getCoordinateTransform();

//! Find out whether rendering is in progress
void setTheme( const QString &theme );
QString theme() const;
const QgsMapToPixel *getCoordinateTransform();
bool isDrawing();

//! returns current layer (set by legend widget)
QgsMapLayer* currentLayer();

//! set wheel zoom factor (should be greater than 1)
QgsMapLayer *currentLayer();
void setWheelFactor( double factor );

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

//! Emitted when the configuration of overridden layer styles changes
//! @note added in 2.12
void layerStyleOverridesChanged();

//! emit a message (usually to be displayed in a message bar)
void messageEmitted( const QString& title, const QString& message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );
void themeChanged( const QString &theme );
void messageEmitted( const QString &title, const QString &message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );

protected:

@@ -63,6 +63,7 @@ email : sherman at mrcc.com
#include "qgsrubberband.h"
#include "qgsvectorlayer.h"
#include "qgscursors.h"
#include "qgsmapthemecollection.h"
#include <cmath>


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

connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeChanged, this, &QgsMapCanvas::mapThemeChanged );

mSettings.setFlag( QgsMapSettings::DrawEditingInfo );
mSettings.setFlag( QgsMapSettings::UseRenderingOptimization );
mSettings.setFlag( QgsMapSettings::RenderPartialOutput );
@@ -482,6 +485,16 @@ void QgsMapCanvas::refreshMap()

mSettings.setExpressionContext( expressionContext );

if ( !mTheme.isEmpty() )
{
mSettings.setLayerStyleOverrides( QgsProject::instance()->mapThemeCollection()->mapThemeStyleOverrides( mTheme ) );
mSettings.setLayers( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
}
else
{
mSettings.setLayerStyleOverrides( QMap< QString, QString>() );
}

// create the renderer job
Q_ASSERT( !mJob );
mJobCanceled = false;
@@ -518,6 +531,16 @@ void QgsMapCanvas::refreshMap()
emit renderStarting();
}

void QgsMapCanvas::mapThemeChanged( const QString &theme )
{
if ( theme == mTheme )
{
setLayers( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
clearCache();
refresh();
}
}


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

void QgsMapCanvas::setTheme( const QString &theme )
{
if ( mTheme == theme )
return;

mTheme = theme;
clearCache();
emit themeChanged( theme );
}

void QgsMapCanvas::setRenderFlag( bool flag )
{
@@ -72,6 +72,7 @@ class QgsRubberBand;
class GUI_EXPORT QgsMapCanvas : public QGraphicsView
{
Q_OBJECT
Q_PROPERTY( QString theme READ theme WRITE setTheme NOTIFY themeChanged )

public:

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

/**
* Sets a map \a theme to show in the canvas. The theme name must match
* a theme present in the associated project's QgsMapThemeCollection.
* @note added in QGIS 3.0
* @see theme()
*/
void setTheme( const QString &theme );

/**
* Returns the map's theme shown in the canvas, if set.
* @note added in QGIS 3.0
* @see setTheme()
*/
QString theme() const { return mTheme; }

//! Get the current coordinate transform
const QgsMapToPixel *getCoordinateTransform();

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

void refreshMap();

void mapThemeChanged( const QString &theme );

signals:

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

/**
* Emitted when the map theme set for the canvas is changed.
* @see setTheme()
* @note added in QGIS 3.0
*/
void themeChanged( const QString &theme );

//! emit a message (usually to be displayed in a message bar)
void messageEmitted( const QString &title, const QString &message, QgsMessageBar::MessageLevel = QgsMessageBar::INFO );

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

QTimer mAutoRefreshTimer;

QString mTheme;

//! Force a resize of the map canvas item
//! @note added in 2.16
void updateMapSize();
@@ -19,7 +19,11 @@
QgsVectorLayer,
QgsFeature,
QgsGeometry,
QgsMultiRenderChecker)
QgsMultiRenderChecker,
QgsFillSymbol,
QgsSingleSymbolRenderer,
QgsMapThemeCollection,
QgsProject)
from qgis.gui import (QgsMapCanvas)

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

def testMapTheme(self):
canvas = QgsMapCanvas()
canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326))
canvas.setFrameStyle(0)
canvas.resize(600, 400)
self.assertEqual(canvas.width(), 600)
self.assertEqual(canvas.height(), 400)

layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string",
"layer", "memory")
# add a polygon to layer
f = QgsFeature()
f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45)))
self.assertTrue(layer.dataProvider().addFeatures([f]))

# create a style
sym1 = QgsFillSymbol.createSimple({'color': '#ffb200'})
renderer = QgsSingleSymbolRenderer(sym1)
layer.setRenderer(renderer)

canvas.setLayers([layer])
canvas.setExtent(QgsRectangle(10, 30, 20, 35))
canvas.show()

# need to wait until first redraw can occur (note that we first need to wait till drawing starts!)
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()

self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))

# add some styles
layer.styleManager().addStyleFromLayer('style1')
sym2 = QgsFillSymbol.createSimple({'color': '#00b2ff'})
renderer2 = QgsSingleSymbolRenderer(sym2)
layer.setRenderer(renderer2)
layer.styleManager().addStyleFromLayer('style2')

canvas.refresh()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas))

layer.styleManager().setCurrentStyle('style1')
canvas.refresh()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))

# ok, so all good with setting/rendering map styles
# try setting canvas to a particular theme

# make some themes...
theme1 = QgsMapThemeCollection.MapThemeRecord()
record1 = QgsMapThemeCollection.MapThemeLayerRecord(layer)
record1.currentStyle = 'style1'
record1.usingCurrentStyle = True
theme1.setLayerRecords([record1])

theme2 = QgsMapThemeCollection.MapThemeRecord()
record2 = QgsMapThemeCollection.MapThemeLayerRecord(layer)
record2.currentStyle = 'style2'
record2.usingCurrentStyle = True
theme2.setLayerRecords([record2])

QgsProject.instance().mapThemeCollection().insert('theme1', theme1)
QgsProject.instance().mapThemeCollection().insert('theme2', theme2)

canvas.setTheme('theme2')
canvas.refresh()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas))

canvas.setTheme('theme1')
canvas.refresh()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))

# add another layer
layer2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string",
"layer2", "memory")
f = QgsFeature()
f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45)))
self.assertTrue(layer2.dataProvider().addFeatures([f]))

# create a style
sym1 = QgsFillSymbol.createSimple({'color': '#b2ff00'})
renderer = QgsSingleSymbolRenderer(sym1)
layer2.setRenderer(renderer)

# rerender canvas - should NOT show new layer
canvas.refresh()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))
# test again - this time refresh all layers
canvas.refreshAllLayers()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas))

# add layer 2 to theme1
record3 = QgsMapThemeCollection.MapThemeLayerRecord(layer2)
theme1.setLayerRecords([record3])
QgsProject.instance().mapThemeCollection().update('theme1', theme1)

canvas.refresh()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme3', 'theme3', canvas))

def canvasImageCheck(self, name, reference_image, canvas):
self.report += "<h2>Render {}</h2>\n".format(name)
temp_dir = QDir.tempPath() + '/'
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 1e6bffe

Please sign in to comment.
You can’t perform that action at this time.