Improved docs for QgsMapCanvas::setTheme, handle setLayers and

setLayerStyleOverrides when canvas is following a map theme
This commit is contained in:
Nyall Dawson 2017-03-13 09:53:09 +10:00
parent 7b7c3e1a09
commit af532ecdf3
4 changed files with 118 additions and 251 deletions

View File

@ -18,298 +18,82 @@ class QgsMapCanvas : QGraphicsView
public:
//! Constructor
QgsMapCanvas( QWidget * parent /TransferThis/ = 0 );
QgsMapCanvas( QWidget *parent /TransferThis/ = 0 );
~QgsMapCanvas();
//! Returns the magnification factor
//! @note added in 2.16
double magnificationFactor() const;
//! Set list of layers that should be shown in the canvas
//! @note added in 3.0
void setLayers( const QList<QgsMapLayer*>& layers );
void setCurrentLayer( QgsMapLayer* layer );
//! Get access to properties used for map rendering
//! @note added in 2.4
const QgsMapSettings& mapSettings() const /KeepReference/;
//! sets destination coordinate reference system
//! @note added in 2.4
void setDestinationCrs( const QgsCoordinateReferenceSystem& crs );
//! Get access to the labeling results (may be null)
//! @note added in 2.4
const QgsLabelingResults* labelingResults() const;
//! Set whether to cache images of rendered layers
//! @note added in 2.4
void setLayers( const QList<QgsMapLayer *> &layers );
void setCurrentLayer( QgsMapLayer *layer );
const QgsMapSettings &mapSettings() const /KeepReference/;
void setDestinationCrs( const QgsCoordinateReferenceSystem &crs );
const QgsLabelingResults *labelingResults() const;
void setCachingEnabled( bool enabled );
//! Check whether images of rendered layers are curerently being cached
//! @note added in 2.4
bool isCachingEnabled() const;
//! Make sure to remove any rendered images from cache (does nothing if cache is not enabled)
//! @note added in 2.4
void clearCache();
//! Reload all layers, clear the cache and refresh the canvas
//! @note added in 2.9
void refreshAllLayers();
//! Set whether the layers are rendered in parallel or sequentially
//! @note added in 2.4
void setParallelRenderingEnabled( bool enabled );
//! Check whether the layers are rendered in parallel or sequentially
//! @note added in 2.4
bool isParallelRenderingEnabled() const;
//! Set how often map preview should be updated while it is being rendered (in milliseconds)
//! @note added in 2.4
void setMapUpdateInterval( int timeMilliseconds );
//! Find out how often map preview should be updated while it is being rendered (in milliseconds)
//! @note added in 2.4
int mapUpdateInterval() const;
//! Get the last reported scale of the canvas
double scale();
//! Returns the mapUnitsPerPixel (map units per pixel) for the canvas
double mapUnitsPerPixel() const;
//! Returns the current zoom extent of the map canvas
QgsRectangle extent() const;
//! Returns the combined extent for all layers on the map canvas
QgsRectangle fullExtent() const;
//! Set the extent of the map canvas
void setExtent( const QgsRectangle &r, bool magnified = false );
//! Get the current map canvas rotation in clockwise degrees
//! @note added in 2.8
double rotation() const;
//! Set the rotation of the map canvas in clockwise degrees
//! @note added in 2.8
void setRotation( double degrees );
//! Set the center of the map canvas, in geographical coordinates
//! @note added in 2.8
void setCenter( const QgsPoint& center );
//! Get map center, in geographical coordinates
//! @note added in 2.8
void setCenter( const QgsPoint &center );
QgsPoint center() const;
//! Zoom to the full extent of all layers
void zoomToFullExtent();
//! Zoom to the previous extent (view)
void zoomToPreviousExtent();
//! Zoom to the next extent (view)
void zoomToNextExtent();
// ! Clears the list of extents and sets current extent as first item
void clearExtentHistory();
/** Zoom to the extent of the selected features of current (vector) layer.
* @param layer optionally specify different than current layer
*/
void zoomToSelected( QgsVectorLayer* layer = 0 );
/** Set canvas extent to the bounding box of a set of features
@param layer the vector layer
@param ids the feature ids*/
void zoomToFeatureIds( QgsVectorLayer* layer, const QgsFeatureIds& ids );
/** Centers canvas extent to feature ids
@param layer the vector layer
@param ids the feature ids*/
void panToFeatureIds( QgsVectorLayer* layer, const QgsFeatureIds& ids );
//! Pan to the selected features of current (vector) layer keeping same extent.
void panToSelected( QgsVectorLayer* layer = 0 );
//! \brief Sets the map tool currently being used on the canvas
void setMapTool( QgsMapTool* mapTool );
/** \brief Unset the current map tool or last non zoom tool
*
* This is called from destructor of map tools to make sure
* that this map tool won't be used any more.
* You don't have to call it manualy, QgsMapTool takes care of it.
*/
void unsetMapTool( QgsMapTool* mapTool );
//! Returns the currently active tool
QgsMapTool* mapTool();
//! Write property of QColor bgColor.
void setCanvasColor( const QColor & _newVal );
//! Read property of QColor bgColor.
void zoomToSelected( QgsVectorLayer *layer = 0 );
void zoomToFeatureIds( QgsVectorLayer *layer, const QgsFeatureIds &ids );
void panToFeatureIds( QgsVectorLayer *layer, const QgsFeatureIds &ids );
void panToSelected( QgsVectorLayer *layer = 0 );
void setMapTool( QgsMapTool *mapTool );
void unsetMapTool( QgsMapTool *mapTool );
QgsMapTool *mapTool();
void setCanvasColor( const QColor &_newVal );
QColor canvasColor() const;
//! Set color of selected vector features
//! @note added in 2.4
void setSelectionColor( const QColor& color );
//! Emits signal scaleChanged to update scale in main window
void setSelectionColor( const QColor &color );
void updateScale();
//! return the map layer at position index in the layer stack
QgsMapLayer *layer( int index );
//! return number of layers on the map
int layerCount() const;
//! return list of layers within map canvas.
QList<QgsMapLayer*> layers() const;
QList<QgsMapLayer *> layers() const;
void freeze( bool frozen = true );
bool isFrozen() const;
bool renderFlag() const;
//! Get the current canvas map units
QgsUnitTypes::DistanceUnit mapUnits() const;
//! Getter for stored overrides of styles for layers.
//! @note added in 2.12
QMap<QString, QString> layerStyleOverrides() const;
//! Setter for stored overrides of styles for layers.
//! @note added in 2.12
void setLayerStyleOverrides( const QMap<QString, QString>& overrides );
void setLayerStyleOverrides( const QMap<QString, QString> &overrides );
void setTheme( const QString &theme );
QString theme() const;
const QgsMapToPixel *getCoordinateTransform();
bool isDrawing();
QgsMapLayer *currentLayer();
void setWheelFactor( double factor );
//! Zoom to a specific scale
void zoomScale( double scale );
//! Zoom with the factor supplied. Factor > 1 zooms out, interval (0,1) zooms in
//! If point is given, re-center on it
void zoomByFactor( double scaleFactor, const QgsPoint *center = 0 );
//! Zooms in/out with a given center
void zoomWithCenter( int x, int y, bool zoomIn );
//! Zooms to feature extent. Adds a small margin around the extent
//! and does a pan if rect is empty (point extent)
void zoomToFeatureExtent( QgsRectangle& rect );
//! Returns whether the scale is locked, so zooming can be performed using magnication.
//! @note added in 2.16
//! @see setScaleLocked()
void zoomToFeatureExtent( QgsRectangle &rect );
bool scaleLocked() const;
//! used to determine if anti-aliasing is enabled or not
void enableAntiAliasing( bool flag );
//! true if antialising is enabled
bool antiAliasingEnabled() const;
//! sets map tile rendering flag
void enableMapTileRendering( bool flag );
// following 2 methods should be moved elsewhere or changed to private
// currently used by pan map tool
//! Ends pan action and redraws the canvas.
void panActionEnd( QPoint releasePoint );
//! Called when mouse is moving and pan is activated
void panAction( QMouseEvent * event );
//! returns last position of mouse cursor
void panAction( QMouseEvent *event );
QPoint mouseLastXY();
/** Enables a preview mode for the map canvas
* @param previewEnabled set to true to enable a preview mode
* @see setPreviewMode
* @note added in 2.3 */
void setPreviewModeEnabled( bool previewEnabled );
/** Returns whether a preview mode is enabled for the map canvas
* @returns true if a preview mode is currently enabled
* @see setPreviewModeEnabled
* @see previewMode
* @note added in 2.3 */
bool previewModeEnabled() const;
/** Sets a preview mode for the map canvas. This setting only has an effect if
* previewModeEnabled is true.
* @param mode preview mode for the canvas
* @see previewMode
* @see setPreviewModeEnabled
* @see previewModeEnabled
* @note added in 2.3 */
void setPreviewMode( QgsPreviewEffect::PreviewMode mode );
/** Returns the current preview mode for the map canvas. This setting only has an effect if
* previewModeEnabled is true.
* @returns preview mode for map canvas
* @see setPreviewMode
* @see previewModeEnabled
* @note added in 2.3 */
QgsPreviewEffect::PreviewMode previewMode() const;
/** Return snapping utility class that is associated with map canvas.
* If no snapping utils instance has been associated previously, an internal will be created for convenience
* (so map tools do not need to test for existence of the instance).
*
* Main canvas in QGIS returns an instance which is always up-to-date with the project's snapping configuration.
* @note added in 2.8
*/
QgsSnappingUtils* snappingUtils() const;
/** Assign an instance of snapping utils to the map canvas.
* The instance is not owned by the canvas, so it is possible to use one instance in multiple canvases.
*
* For main canvas in QGIS, do not associate a different instance from the existing one (it is updated from
* the project's snapping configuration).
* @note added in 2.8
*/
void setSnappingUtils( QgsSnappingUtils* utils );
/** Sets an expression context scope for the map canvas. This scope is injected into the expression
* context used for rendering the map, and can be used to apply specific variable overrides for
* expression evaluation for the map canvas render. This method will overwrite the existing expression
* context scope for the canvas.
* @param scope new expression context scope
* @note added in QGIS 2.12
* @see expressionContextScope()
*/
void setExpressionContextScope( const QgsExpressionContextScope& scope );
/** Returns a reference to the expression context scope for the map canvas. This scope is injected
* into the expression context used for rendering the map, and can be used to apply specific variable
* overrides for expression evaluation for the map canvas render.
* @note added in QGIS 2.12
* @see setExpressionContextScope()
*/
QgsExpressionContextScope& expressionContextScope();
/** Returns a const reference to the expression context scope for the map canvas.
* @note added in QGIS 2.12
* @see setExpressionContextScope()
* @note not available in python bindings
*/
// const QgsExpressionContextScope& expressionContextScope() const;
/** Sets the segmentation tolerance applied when rendering curved geometries
@param tolerance the segmentation tolerance*/
QgsSnappingUtils *snappingUtils() const;
void setSnappingUtils( QgsSnappingUtils *utils );
void setExpressionContextScope( const QgsExpressionContextScope &scope );
QgsExpressionContextScope &expressionContextScope();
// const QgsExpressionContextScope &expressionContextScope() const;
void setSegmentationTolerance( double tolerance );
/** Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation)
@param type the segmentation tolerance typename*/
void setSegmentationToleranceType( QgsAbstractGeometry::SegmentationToleranceType type );
public slots:

View File

@ -291,6 +291,15 @@ const QgsMapToPixel *QgsMapCanvas::getCoordinateTransform()
}
void QgsMapCanvas::setLayers( const QList<QgsMapLayer *> &layers )
{
// following a theme => request denied!
if ( !mTheme.isEmpty() )
return;
setLayersPrivate( layers );
}
void QgsMapCanvas::setLayersPrivate( const QList<QgsMapLayer *> &layers )
{
QList<QgsMapLayer *> oldLayers = mSettings.layers();
@ -487,6 +496,12 @@ void QgsMapCanvas::refreshMap()
if ( !mTheme.isEmpty() )
{
// IMPORTANT: we MUST set the layer style overrides here! (At the time of writing this
// comment) retrieving layer styles from the theme collection gives an XML snapshot of the
// current state of the style. If we had stored the style overrides earlier (such as in
// mapThemeChanged slot) then this xml could be out of date...
// TODO: if in future QgsMapThemeCollection::mapThemeStyleOverrides is changed to
// just return the style name, we can instead set the overrides in mapThemeChanged and not here
mSettings.setLayerStyleOverrides( QgsProject::instance()->mapThemeCollection()->mapThemeStyleOverrides( mTheme ) );
}
@ -530,7 +545,17 @@ void QgsMapCanvas::mapThemeChanged( const QString &theme )
{
if ( theme == mTheme )
{
setLayers( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
// set the canvas layers to match the new layers contained in the map theme
// NOTE: we do this when the theme layers change and not when we are refreshing the map
// as setLayers() sets up necessary connections to handle changes to the layers
setLayersPrivate( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
// IMPORTANT: we don't set the layer style overrides here! (At the time of writing this
// comment) retrieving layer styles from the theme collection gives an XML snapshot of the
// current state of the style. If changes were made to the style then this xml
// snapshot goes out of sync...
// TODO: if in future QgsMapThemeCollection::mapThemeStyleOverrides is changed to
// just return the style name, we can instead set the overrides here and not in refreshMap()
clearCache();
refresh();
}
@ -1628,7 +1653,7 @@ void QgsMapCanvas::setTheme( const QString &theme )
else
{
mTheme = theme;
setLayers( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
setLayersPrivate( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
emit themeChanged( theme );
}
}

View File

@ -85,8 +85,17 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! @note added in 2.16
double magnificationFactor() const;
//! Set list of layers that should be shown in the canvas
//! @note added in 3.0
/**
* Sets the list of \a layers that should be shown in the canvas.
*
* If the map canvas has been associated with a map theme via a call
* to setTheme(), then any calls to setLayers() are ignored. It is necessary
* to first clear the theme association by calling setTheme() with an
* empty string before setLayers() calls can be made.
*
* @note added in 3.0
* @see layers()
*/
void setLayers( const QList<QgsMapLayer *> &layers );
void setCurrentLayer( QgsMapLayer *layer );
@ -227,7 +236,10 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! return number of layers on the map
int layerCount() const;
//! return list of layers within map canvas.
/**
* Return the list of layers shown within the map canvas.
* @see setLayers()
*/
QList<QgsMapLayer *> layers() const;
/**
@ -266,17 +278,39 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
*/
QgsUnitTypes::DistanceUnit mapUnits() const;
//! Getter for stored overrides of styles for layers.
//! @note added in 2.12
/**
* Returns the stored overrides of styles for layers.
* @note added in 2.12
* @see setLayerStyleOverrides().
*/
QMap<QString, QString> layerStyleOverrides() const;
//! Setter for stored overrides of styles for layers.
//! @note added in 2.12
/**
* Sets the stored overrides of styles for rendering layers.
*
* If the map canvas has been associated with a map theme via a call
* to setTheme(), then any calls to setLayerStyleOverrides() are ignored. It is necessary
* to first clear the theme association by calling setTheme() with an
* empty string before setLayerStyleOverrides() calls can be made.
*
* @note added in 2.12
* @see layerStyleOverrides()
*/
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.
*
* When the canvas is associated to a map theme, it will automatically follow
* the layer selection and layer styles from that theme. Calls to setLayers()
* or setLayerStyleOverrides() will have no effect, and canvases associated
* with a QgsLayerTreeMapCanvasBridge will no longer synchronize their
* state with the layer tree. In these cases it is necessary to call
* setTheme() with an empty string to clear the theme association and
* allow map updates with setLayers(), setLayerStyleOverrides(), or via
* QgsLayerTreeMapCanvasBridge.
*
* If an empty string is passed then the current theme association will be
* cleared. The layers from the previously associated theme will remain
* in the canvas, and a call to setLayers() may be necessary to define
@ -571,7 +605,7 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
void layerStyleOverridesChanged();
/**
* Emitted when the map theme set for the canvas is changed.
* Emitted when the canvas has been assigned a different map theme.
* @see setTheme()
* @note added in QGIS 3.0
*/
@ -763,6 +797,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
@return true in case of success*/
bool boundingBoxOfFeatureIds( const QgsFeatureIds &ids, QgsVectorLayer *layer, QgsRectangle &bbox, QString &errorMsg ) const;
void setLayersPrivate( const QList<QgsMapLayer *> &layers );
friend class TestQgsMapCanvas;
}; // class QgsMapCanvas

View File

@ -312,6 +312,7 @@ class TestQgsMapCanvas(unittest.TestCase):
self.assertTrue(self.canvasImageCheck('theme3', 'theme3', canvas))
# change the appearance of an active style
layer2.styleManager().addStyleFromLayer('original')
layer2.styleManager().addStyleFromLayer('style4')
record3.currentStyle = 'style4'
record3.usingCurrentStyle = True
@ -336,6 +337,27 @@ class TestQgsMapCanvas(unittest.TestCase):
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas))
# try setting layers while a theme is in place
canvas.setLayers([layer])
canvas.refresh()
# should be no change... setLayers should be ignored if canvas is following a theme!
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas))
# setLayerStyleOverrides while theme is in place
canvas.setLayerStyleOverrides({layer2.id(): 'original'})
# should be no change... setLayerStyleOverrides should be ignored if canvas is following a theme!
canvas.refresh()
while not canvas.isDrawing():
app.processEvents()
while canvas.isDrawing():
app.processEvents()
self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas))
def canvasImageCheck(self, name, reference_image, canvas):
self.report += "<h2>Render {}</h2>\n".format(name)
temp_dir = QDir.tempPath() + '/'