Skip to content

Commit 94e1d5e

Browse files
committedJun 7, 2016
Fix crash when using inverted polygons with heatmap renderer
Add methods to QgsRendererV2AbstractMetadata and QgsRendererV2Registry to control renderer compatiblity by layer type. Should make it easier to avoid this recurring bug popping up again in future. Also add unit tests for QgsRendererV2Registry Fix #14968
1 parent fbc5e0f commit 94e1d5e

File tree

8 files changed

+340
-32
lines changed

8 files changed

+340
-32
lines changed
 

‎python/core/symbology-ng/qgsrendererv2registry.sip

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ class QgsRendererV2AbstractMetadata
1313
%End
1414

1515
public:
16+
17+
18+
//! Layer types the renderer is compatible with
19+
//! @note added in QGIS 2.16
20+
enum LayerType
21+
{
22+
PointLayer, //!< Compatible with point layers
23+
LineLayer, //!< Compatible with line layers
24+
PolygonLayer, //!< Compatible with polygon layers
25+
All, //!< Compatible with all vector layers
26+
};
27+
typedef QFlags<QgsRendererV2AbstractMetadata::LayerType> LayerTypes;
28+
1629
QgsRendererV2AbstractMetadata( const QString& name, const QString& visibleName, const QIcon& icon = QIcon() );
1730
virtual ~QgsRendererV2AbstractMetadata();
1831

@@ -22,6 +35,11 @@ class QgsRendererV2AbstractMetadata
2235
QIcon icon() const;
2336
void setIcon( const QIcon& icon );
2437

38+
/** Returns flags indicating the types of layer the renderer is compatible with.
39+
* @note added in QGIS 2.16
40+
*/
41+
virtual QgsRendererV2AbstractMetadata::LayerTypes compatibleLayerTypes() const;
42+
2543
/** Return new instance of the renderer given the DOM element. Returns NULL on error.
2644
* Pure virtual function: must be implemented in derived classes. */
2745
virtual QgsFeatureRendererV2* createRenderer( QDomElement& elem ) = 0 /Factory/;
@@ -37,6 +55,8 @@ class QgsRendererV2AbstractMetadata
3755
virtual QgsFeatureRendererV2* createRendererFromSld( QDomElement& elem, QGis::GeometryType geomType ) /Factory/;
3856
};
3957

58+
QFlags<QgsRendererV2AbstractMetadata::LayerType> operator|(QgsRendererV2AbstractMetadata::LayerType f1, QFlags<QgsRendererV2AbstractMetadata::LayerType> f2);
59+
4060
/**
4161
Convenience metadata class that uses static functions to create renderer and its widget.
4262
*/
@@ -55,15 +75,19 @@ class QgsRendererV2Metadata : QgsRendererV2AbstractMetadata
5575
// QgsFeatureRendererV2* (*)( QDomElement&, QGis::GeometryType geomType ) createFromSldFunction() const;
5676
// void setWidgetFunction( QgsRendererV2WidgetFunc f );
5777

78+
virtual QgsRendererV2AbstractMetadata::LayerTypes compatibleLayerTypes() const;
79+
5880
private:
5981
QgsRendererV2Metadata(); // pretend this is private
6082
};
6183

62-
/**
63-
Registry of renderers.
64-
65-
This is a singleton, renderers can be added / removed at any time
84+
/** \ingroup core
85+
* \class QgsRendererV2Registry
86+
* \brief Registry of renderers.
87+
*
88+
* This is a singleton, renderers can be added / removed at any time
6689
*/
90+
6791
class QgsRendererV2Registry
6892
{
6993
%TypeHeaderCode
@@ -72,19 +96,33 @@ class QgsRendererV2Registry
7296

7397
public:
7498

99+
//! Returns a pointer to the QgsRendererV2Registry singleton
75100
static QgsRendererV2Registry* instance();
76101

77-
//! add a renderer to registry. Takes ownership of the metadata object.
102+
//! Adds a renderer to the registry. Takes ownership of the metadata object.
103+
//! @param metadata renderer metadata
104+
//! @returns true if renderer was added successfully, or false if renderer could not
105+
//! be added (eg a renderer with a duplicate name already exists)
78106
bool addRenderer( QgsRendererV2AbstractMetadata* metadata /Transfer/ );
79107

80-
//! remove renderer from registry
108+
//! Removes a renderer from registry.
109+
//! @param rendererName name of renderer to remove from registry
110+
//! @returns true if renderer was sucessfully removed, or false if matching
111+
//! renderer could not be found
81112
bool removeRenderer( const QString& rendererName );
82113

83-
//! get metadata for particular renderer. Returns NULL if not found in registry.
114+
//! Returns the metadata for a specified renderer. Returns NULL if a matching
115+
//! renderer was not found in the registry.
84116
QgsRendererV2AbstractMetadata* rendererMetadata( const QString& rendererName );
85117

86-
//! return a list of available renderers
87-
QStringList renderersList();
118+
//! Returns a list of available renderers.
119+
//! @param layerTypes flags to filter the renderers by compatible layer types
120+
QStringList renderersList( QgsRendererV2AbstractMetadata::LayerTypes layerTypes = QgsRendererV2AbstractMetadata::All ) const;
121+
122+
//! Returns a list of available renderers which are compatible with a specified layer.
123+
//! @param layer vector layer
124+
//! @note added in QGIS 2.16
125+
QStringList renderersList( const QgsVectorLayer* layer ) const;
88126

89127
protected:
90128
//! protected constructor
@@ -93,5 +131,6 @@ class QgsRendererV2Registry
93131

94132
private:
95133
QgsRendererV2Registry( const QgsRendererV2Registry& rh );
134+
//QgsRendererV2Registry& operator=( const QgsRendererV2Registry& rh );
96135

97136
};

‎src/core/symbology-ng/qgsrendererv2registry.cpp

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "qgsheatmaprenderer.h"
2525
#include "qgs25drenderer.h"
2626
#include "qgsnullsymbolrenderer.h"
27+
#include "qgsvectorlayer.h"
2728

2829
QgsRendererV2Registry::QgsRendererV2Registry()
2930
{
@@ -52,20 +53,32 @@ QgsRendererV2Registry::QgsRendererV2Registry()
5253

5354
addRenderer( new QgsRendererV2Metadata( "pointDisplacement",
5455
QObject::tr( "Point displacement" ),
55-
QgsPointDisplacementRenderer::create ) );
56+
QgsPointDisplacementRenderer::create,
57+
QIcon(),
58+
nullptr,
59+
QgsRendererV2AbstractMetadata::PointLayer ) );
5660

5761
addRenderer( new QgsRendererV2Metadata( "invertedPolygonRenderer",
5862
QObject::tr( "Inverted polygons" ),
59-
QgsInvertedPolygonRenderer::create ) );
63+
QgsInvertedPolygonRenderer::create,
64+
QIcon(),
65+
nullptr,
66+
QgsRendererV2AbstractMetadata::PolygonLayer ) );
6067

6168
addRenderer( new QgsRendererV2Metadata( "heatmapRenderer",
6269
QObject::tr( "Heatmap" ),
63-
QgsHeatmapRenderer::create ) );
70+
QgsHeatmapRenderer::create,
71+
QIcon(),
72+
nullptr,
73+
QgsRendererV2AbstractMetadata::PointLayer ) );
6474

6575

6676
addRenderer( new QgsRendererV2Metadata( "25dRenderer",
6777
QObject::tr( "2.5 D" ),
68-
Qgs25DRenderer::create ) );
78+
Qgs25DRenderer::create,
79+
QIcon(),
80+
nullptr,
81+
QgsRendererV2AbstractMetadata::PolygonLayer ) );
6982
}
7083

7184
QgsRendererV2Registry::~QgsRendererV2Registry()
@@ -108,7 +121,39 @@ QgsRendererV2AbstractMetadata* QgsRendererV2Registry::rendererMetadata( const QS
108121

109122
QgsRendererV2Metadata::~QgsRendererV2Metadata() {}
110123

111-
QStringList QgsRendererV2Registry::renderersList()
124+
QStringList QgsRendererV2Registry::renderersList( QgsRendererV2AbstractMetadata::LayerTypes layerTypes ) const
112125
{
113-
return mRenderersOrder;
126+
QStringList renderers;
127+
Q_FOREACH ( const QString& renderer, mRenderersOrder )
128+
{
129+
if ( mRenderers.value( renderer )->compatibleLayerTypes() & layerTypes )
130+
renderers << renderer;
131+
}
132+
return renderers;
133+
}
134+
135+
QStringList QgsRendererV2Registry::renderersList( const QgsVectorLayer* layer ) const
136+
{
137+
QgsRendererV2AbstractMetadata::LayerType layerType = QgsRendererV2AbstractMetadata::All;
138+
139+
switch ( layer->geometryType() )
140+
{
141+
case QGis::Point:
142+
layerType = QgsRendererV2AbstractMetadata::PointLayer;
143+
break;
144+
145+
case QGis::Line:
146+
layerType = QgsRendererV2AbstractMetadata::LineLayer;
147+
break;
148+
149+
case QGis::Polygon:
150+
layerType = QgsRendererV2AbstractMetadata::PolygonLayer;
151+
break;
152+
153+
case QGis::UnknownGeometry:
154+
case QGis::NoGeometry:
155+
break;
156+
}
157+
158+
return renderersList( layerType );
114159
}

‎src/core/symbology-ng/qgsrendererv2registry.h

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ class QgsRendererV2Widget;
3636
class CORE_EXPORT QgsRendererV2AbstractMetadata
3737
{
3838
public:
39+
40+
//! Layer types the renderer is compatible with
41+
//! @note added in QGIS 2.16
42+
enum LayerType
43+
{
44+
PointLayer = 1, //!< Compatible with point layers
45+
LineLayer = 2, //!< Compatible with line layers
46+
PolygonLayer = 4, //!< Compatible with polygon layers
47+
All = PointLayer | LineLayer | PolygonLayer, //!< Compatible with all vector layers
48+
};
49+
Q_DECLARE_FLAGS( LayerTypes, LayerType )
50+
3951
QgsRendererV2AbstractMetadata( const QString& name, const QString& visibleName, const QIcon& icon = QIcon() )
4052
: mName( name )
4153
, mVisibleName( visibleName )
@@ -49,6 +61,11 @@ class CORE_EXPORT QgsRendererV2AbstractMetadata
4961
QIcon icon() const { return mIcon; }
5062
void setIcon( const QIcon& icon ) { mIcon = icon; }
5163

64+
/** Returns flags indicating the types of layer the renderer is compatible with.
65+
* @note added in QGIS 2.16
66+
*/
67+
virtual LayerTypes compatibleLayerTypes() const { return All; }
68+
5269
/** Return new instance of the renderer given the DOM element. Returns NULL on error.
5370
* Pure virtual function: must be implemented in derived classes. */
5471
virtual QgsFeatureRendererV2* createRenderer( QDomElement& elem ) = 0;
@@ -75,6 +92,9 @@ class CORE_EXPORT QgsRendererV2AbstractMetadata
7592
};
7693

7794

95+
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsRendererV2AbstractMetadata::LayerTypes )
96+
97+
7898
typedef QgsFeatureRendererV2*( *QgsRendererV2CreateFunc )( QDomElement& );
7999
typedef QgsRendererV2Widget*( *QgsRendererV2WidgetFunc )( QgsVectorLayer*, QgsStyleV2*, QgsFeatureRendererV2* );
80100
typedef QgsFeatureRendererV2*( *QgsRendererV2CreateFromSldFunc )( QDomElement&, QGis::GeometryType geomType );
@@ -92,11 +112,13 @@ class CORE_EXPORT QgsRendererV2Metadata : public QgsRendererV2AbstractMetadata
92112
const QString& visibleName,
93113
QgsRendererV2CreateFunc pfCreate,
94114
const QIcon& icon = QIcon(),
95-
QgsRendererV2WidgetFunc pfWidget = nullptr )
115+
QgsRendererV2WidgetFunc pfWidget = nullptr,
116+
QgsRendererV2AbstractMetadata::LayerTypes layerTypes = QgsRendererV2AbstractMetadata::All )
96117
: QgsRendererV2AbstractMetadata( name, visibleName, icon )
97118
, mCreateFunc( pfCreate )
98119
, mWidgetFunc( pfWidget )
99120
, mCreateFromSldFunc( nullptr )
121+
, mLayerTypes( layerTypes )
100122
{}
101123

102124
//! @note not available in python bindings
@@ -105,11 +127,13 @@ class CORE_EXPORT QgsRendererV2Metadata : public QgsRendererV2AbstractMetadata
105127
QgsRendererV2CreateFunc pfCreate,
106128
QgsRendererV2CreateFromSldFunc pfCreateFromSld,
107129
const QIcon& icon = QIcon(),
108-
QgsRendererV2WidgetFunc pfWidget = nullptr )
130+
QgsRendererV2WidgetFunc pfWidget = nullptr,
131+
QgsRendererV2AbstractMetadata::LayerTypes layerTypes = QgsRendererV2AbstractMetadata::All )
109132
: QgsRendererV2AbstractMetadata( name, visibleName, icon )
110133
, mCreateFunc( pfCreate )
111134
, mWidgetFunc( pfWidget )
112135
, mCreateFromSldFunc( pfCreateFromSld )
136+
, mLayerTypes( layerTypes )
113137
{}
114138

115139
virtual ~QgsRendererV2Metadata();
@@ -130,46 +154,70 @@ class CORE_EXPORT QgsRendererV2Metadata : public QgsRendererV2AbstractMetadata
130154
//! @note not available in python bindings
131155
void setWidgetFunction( QgsRendererV2WidgetFunc f ) { mWidgetFunc = f; }
132156

157+
virtual QgsRendererV2AbstractMetadata::LayerTypes compatibleLayerTypes() const override { return mLayerTypes; }
158+
133159
protected:
134160
//! pointer to function that creates an instance of the renderer when loading project / style
135161
QgsRendererV2CreateFunc mCreateFunc;
136162
//! pointer to function that creates a widget for configuration of renderer's params
137163
QgsRendererV2WidgetFunc mWidgetFunc;
138164
//! pointer to function that creates an instance of the renderer from SLD
139165
QgsRendererV2CreateFromSldFunc mCreateFromSldFunc;
166+
167+
private:
168+
169+
QgsRendererV2AbstractMetadata::LayerTypes mLayerTypes;
140170
};
141171

142-
/**
143-
Registry of renderers.
144172

145-
This is a singleton, renderers can be added / removed at any time
173+
/** \ingroup core
174+
* \class QgsRendererV2Registry
175+
* \brief Registry of renderers.
176+
*
177+
* This is a singleton, renderers can be added / removed at any time
146178
*/
179+
147180
class CORE_EXPORT QgsRendererV2Registry
148181
{
149182
public:
150183

184+
//! Returns a pointer to the QgsRendererV2Registry singleton
151185
static QgsRendererV2Registry* instance();
152186

153-
//! add a renderer to registry. Takes ownership of the metadata object.
187+
//! Adds a renderer to the registry. Takes ownership of the metadata object.
188+
//! @param metadata renderer metadata
189+
//! @returns true if renderer was added successfully, or false if renderer could not
190+
//! be added (eg a renderer with a duplicate name already exists)
154191
bool addRenderer( QgsRendererV2AbstractMetadata* metadata );
155192

156-
//! remove renderer from registry
193+
//! Removes a renderer from registry.
194+
//! @param rendererName name of renderer to remove from registry
195+
//! @returns true if renderer was sucessfully removed, or false if matching
196+
//! renderer could not be found
157197
bool removeRenderer( const QString& rendererName );
158198

159-
//! get metadata for particular renderer. Returns NULL if not found in registry.
199+
//! Returns the metadata for a specified renderer. Returns NULL if a matching
200+
//! renderer was not found in the registry.
160201
QgsRendererV2AbstractMetadata* rendererMetadata( const QString& rendererName );
161202

162-
//! return a list of available renderers
163-
QStringList renderersList();
203+
//! Returns a list of available renderers.
204+
//! @param layerTypes flags to filter the renderers by compatible layer types
205+
QStringList renderersList( QgsRendererV2AbstractMetadata::LayerTypes layerTypes = QgsRendererV2AbstractMetadata::All ) const;
206+
207+
//! Returns a list of available renderers which are compatible with a specified layer.
208+
//! @param layer vector layer
209+
//! @note added in QGIS 2.16
210+
QStringList renderersList( const QgsVectorLayer* layer ) const;
164211

165212
protected:
166213
//! protected constructor
167214
QgsRendererV2Registry();
168215
~QgsRendererV2Registry();
169216

217+
//! Map of name to renderer
170218
QMap<QString, QgsRendererV2AbstractMetadata*> mRenderers;
171219

172-
//! list to keep order in which renderers have been added
220+
//! List of renderers, maintained in the order that they have been added
173221
QStringList mRenderersOrder;
174222

175223
private:

‎src/gui/symbology-ng/qgsinvertedpolygonrendererwidget.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,13 @@ QgsInvertedPolygonRendererWidget::QgsInvertedPolygonRendererWidget( QgsVectorLay
6969

7070
int currentEmbeddedIdx = 0;
7171
//insert possible renderer types
72-
QStringList rendererList = QgsRendererV2Registry::instance()->renderersList();
72+
QStringList rendererList = QgsRendererV2Registry::instance()->renderersList( QgsRendererV2AbstractMetadata::PolygonLayer );
7373
QStringList::const_iterator it = rendererList.constBegin();
7474
int idx = 0;
7575
mRendererComboBox->blockSignals( true );
7676
for ( ; it != rendererList.constEnd(); ++it, ++idx )
7777
{
78-
if (( *it != "invertedPolygonRenderer" ) && //< an inverted renderer cannot contain another inverted renderer
79-
( *it != "pointDisplacement" ) ) //< an inverted renderer can only contain a polygon renderer
78+
if ( *it != "invertedPolygonRenderer" ) //< an inverted renderer cannot contain another inverted renderer
8079
{
8180
QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( *it );
8281
mRendererComboBox->addItem( m->icon(), m->visibleName(), /* data */ *it );

‎src/gui/symbology-ng/qgspointdisplacementrendererwidget.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ QgsPointDisplacementRendererWidget::QgsPointDisplacementRendererWidget( QgsVecto
8787
}
8888

8989
//insert possible renderer types
90-
QStringList rendererList = QgsRendererV2Registry::instance()->renderersList();
90+
QStringList rendererList = QgsRendererV2Registry::instance()->renderersList( QgsRendererV2AbstractMetadata::PointLayer );
9191
QStringList::const_iterator it = rendererList.constBegin();
9292
for ( ; it != rendererList.constEnd(); ++it )
9393
{
94-
if ( *it != "pointDisplacement" && *it != "heatmapRenderer" && *it != "invertedPolygonRenderer" )
94+
if ( *it != "pointDisplacement" )
9595
{
9696
QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( *it );
9797
mRendererComboBox->addItem( m->icon(), m->visibleName(), *it );

‎src/gui/symbology-ng/qgsrendererv2propertiesdialog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ QgsRendererV2PropertiesDialog::QgsRendererV2PropertiesDialog( QgsVectorLayer* la
100100
_initRendererWidgetFunctions();
101101

102102
QgsRendererV2Registry* reg = QgsRendererV2Registry::instance();
103-
QStringList renderers = reg->renderersList();
103+
QStringList renderers = reg->renderersList( mLayer );
104104
Q_FOREACH ( const QString& name, renderers )
105105
{
106106
QgsRendererV2AbstractMetadata* m = reg->rendererMetadata( name );

‎tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ ADD_PYTHON_TEST(PyQgsRasterLayer test_qgsrasterlayer.py)
6868
ADD_PYTHON_TEST(PyQgsRectangle test_qgsrectangle.py)
6969
ADD_PYTHON_TEST(PyQgsRelation test_qgsrelation.py)
7070
ADD_PYTHON_TEST(PyQgsRelationManager test_qgsrelationmanager.py)
71+
ADD_PYTHON_TEST(PyQgsRendererV2 test_qgsrendererv2.py)
7172
ADD_PYTHON_TEST(PyQgsRulebasedRenderer test_qgsrulebasedrenderer.py)
7273
ADD_PYTHON_TEST(PyQgsSingleSymbolRenderer test_qgssinglesymbolrenderer.py)
7374
ADD_PYTHON_TEST(PyQgsShapefileProvider test_provider_shapefile.py)
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for QgsFeatureRendererV2.
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = 'Nyall Dawson'
10+
__date__ = '07/06/2016'
11+
__copyright__ = 'Copyright 2016, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
15+
import qgis # NOQA
16+
17+
from qgis.core import (QgsFeatureRendererV2,
18+
QgsRendererV2AbstractMetadata,
19+
QgsRendererV2Registry,
20+
QgsVectorLayer
21+
)
22+
from qgis.testing import start_app, unittest
23+
24+
start_app()
25+
26+
27+
def createReferencingLayer():
28+
layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer",
29+
"referencinglayer", "memory")
30+
pr = layer.dataProvider()
31+
f1 = QgsFeature()
32+
f1.setFields(layer.pendingFields())
33+
f1.setAttributes(["test1", 123])
34+
f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200)))
35+
f2 = QgsFeature()
36+
f2.setFields(layer.pendingFields())
37+
f2.setAttributes(["test2", 123])
38+
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(101, 201)))
39+
assert pr.addFeatures([f1, f2])
40+
return layer
41+
42+
43+
class TestRenderer(QgsRendererV2AbstractMetadata):
44+
45+
def __init__(self, name, layerTypes=QgsRendererV2AbstractMetadata.All):
46+
QgsRendererV2AbstractMetadata.__init__(self, name, "Test Renderer")
47+
self.types = layerTypes
48+
49+
def compatibleLayerTypes(self):
50+
return self.types
51+
52+
def createRenderer(self, elem):
53+
return None
54+
55+
56+
def clearRegistry():
57+
# clear registry to start with
58+
for r in QgsRendererV2Registry.instance().renderersList():
59+
if r == 'singleSymbol':
60+
continue
61+
QgsRendererV2Registry.instance().removeRenderer(r)
62+
63+
64+
class TestQgsRendererV2Registry(unittest.TestCase):
65+
66+
def testInstance(self):
67+
""" test retrieving global instance """
68+
self.assertTrue(QgsRendererV2Registry.instance())
69+
70+
# instance should be initially populated with some default renderers
71+
self.assertTrue('singleSymbol' in QgsRendererV2Registry.instance().renderersList())
72+
73+
# register a renderer to the singleton, to test that the same instance is always returned
74+
self.assertFalse('test' in QgsRendererV2Registry.instance().renderersList())
75+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(TestRenderer('test')))
76+
self.assertTrue('test' in QgsRendererV2Registry.instance().renderersList())
77+
78+
def testAddRenderer(self):
79+
""" test adding renderers to registry """
80+
clearRegistry()
81+
82+
# add a renderer
83+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(TestRenderer('test2')))
84+
self.assertTrue('test2' in QgsRendererV2Registry.instance().renderersList())
85+
86+
# try adding it again - should be rejected due to duplicate name
87+
self.assertFalse(QgsRendererV2Registry.instance().addRenderer(TestRenderer('test2')))
88+
self.assertTrue('test2' in QgsRendererV2Registry.instance().renderersList())
89+
90+
def testRemoveRenderer(self):
91+
""" test removing renderers from registry """
92+
clearRegistry()
93+
94+
# try removing non-existant renderer
95+
self.assertFalse(QgsRendererV2Registry.instance().removeRenderer('test3'))
96+
97+
# now add it
98+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(TestRenderer('test3')))
99+
self.assertTrue('test3' in QgsRendererV2Registry.instance().renderersList())
100+
101+
# try removing it again - should be ok this time
102+
self.assertTrue(QgsRendererV2Registry.instance().removeRenderer('test3'))
103+
self.assertFalse('test3' in QgsRendererV2Registry.instance().renderersList())
104+
105+
# try removing it again - should be false since already removed
106+
self.assertFalse(QgsRendererV2Registry.instance().removeRenderer('test3'))
107+
108+
def testRetrieveRenderer(self):
109+
""" test retrieving renderer by name """
110+
clearRegistry()
111+
112+
# try non-existant renderer
113+
self.assertFalse(QgsRendererV2Registry.instance().rendererMetadata('test4'))
114+
115+
# now add it
116+
r = TestRenderer('test4')
117+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r))
118+
119+
# try retrieving it
120+
result = QgsRendererV2Registry.instance().rendererMetadata('test4')
121+
self.assertTrue(result)
122+
self.assertEqual(result.name(), 'test4')
123+
124+
def testRenderersList(self):
125+
""" test getting list of renderers from registry """
126+
clearRegistry()
127+
128+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(), ['singleSymbol'])
129+
130+
# add some renderers
131+
r1 = TestRenderer('test1', QgsRendererV2AbstractMetadata.PointLayer)
132+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r1))
133+
r2 = TestRenderer('test2', QgsRendererV2AbstractMetadata.LineLayer)
134+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r2))
135+
r3 = TestRenderer('test3', QgsRendererV2AbstractMetadata.PolygonLayer)
136+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r3))
137+
r4 = TestRenderer('test4', QgsRendererV2AbstractMetadata.PointLayer | QgsRendererV2AbstractMetadata.LineLayer)
138+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r4))
139+
140+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(), ['singleSymbol', 'test1', 'test2', 'test3', 'test4'])
141+
142+
# test subsets
143+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(QgsRendererV2AbstractMetadata.PointLayer), ['singleSymbol', 'test1', 'test4'])
144+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(QgsRendererV2AbstractMetadata.LineLayer), ['singleSymbol', 'test2', 'test4'])
145+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(QgsRendererV2AbstractMetadata.PolygonLayer), ['singleSymbol', 'test3'])
146+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(QgsRendererV2AbstractMetadata.LineLayer | QgsRendererV2AbstractMetadata.PolygonLayer), ['singleSymbol', 'test2', 'test3', 'test4'])
147+
148+
def testRenderersByLayerType(self):
149+
""" test retrieving compatible renderers by layer type """
150+
clearRegistry()
151+
152+
# add some renderers
153+
r1 = TestRenderer('test1', QgsRendererV2AbstractMetadata.PointLayer)
154+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r1))
155+
r2 = TestRenderer('test2', QgsRendererV2AbstractMetadata.LineLayer)
156+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r2))
157+
r3 = TestRenderer('test3', QgsRendererV2AbstractMetadata.PolygonLayer)
158+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r3))
159+
r4 = TestRenderer('test4', QgsRendererV2AbstractMetadata.PointLayer | QgsRendererV2AbstractMetadata.LineLayer)
160+
self.assertTrue(QgsRendererV2Registry.instance().addRenderer(r4))
161+
162+
# make some layers
163+
point_layer = QgsVectorLayer("Point?field=fldtxt:string",
164+
"pointlayer", "memory")
165+
line_layer = QgsVectorLayer("LineString?field=fldtxt:string",
166+
"linelayer", "memory")
167+
polygon_layer = QgsVectorLayer("Polygon?field=fldtxt:string",
168+
"polylayer", "memory")
169+
170+
# test subsets
171+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(point_layer), ['singleSymbol', 'test1', 'test4'])
172+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(line_layer), ['singleSymbol', 'test2', 'test4'])
173+
self.assertEqual(QgsRendererV2Registry.instance().renderersList(polygon_layer), ['singleSymbol', 'test3'])
174+
175+
if __name__ == '__main__':
176+
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.