Skip to content

Commit b38a16f

Browse files
committedMay 12, 2016
Implement representValue() for Relation Reference widget
1 parent 583eaef commit b38a16f

File tree

3 files changed

+198
-1
lines changed

3 files changed

+198
-1
lines changed
 

‎src/gui/editorwidgets/qgsrelationreferencefactory.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* *
1414
***************************************************************************/
1515

16+
#include "qgsproject.h"
1617
#include "qgsrelationreferencefactory.h"
1718

1819
#include "qgsrelationreferencewidgetwrapper.h"
@@ -103,3 +104,64 @@ QMap<const char*, int> QgsRelationReferenceFactory::supportedWidgetTypes()
103104
map.insert( QgsRelationReferenceWidget::staticMetaObject.className(), 10 );
104105
return map;
105106
}
107+
108+
QString QgsRelationReferenceFactory::representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const
109+
{
110+
Q_UNUSED( cache );
111+
112+
// Some sanity checks
113+
if ( !config.contains( "Relation" ) )
114+
{
115+
QgsDebugMsg( "Missing Relation in configuration" );
116+
return value.toString();
117+
}
118+
QgsRelation relation = QgsProject::instance()->relationManager()->relation( config["Relation"].toString() );
119+
if ( !relation.isValid() )
120+
{
121+
QgsDebugMsg( "Invalid relation" );
122+
return value.toString();
123+
}
124+
QgsVectorLayer* referencingLayer = relation.referencingLayer();
125+
if ( vl != referencingLayer )
126+
{
127+
QgsDebugMsg( "representValue() with inconsistant vl parameter w.r.t relation referencingLayer" );
128+
return value.toString();
129+
}
130+
int referencingFieldIdx = referencingLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).first );
131+
if ( referencingFieldIdx != fieldIdx )
132+
{
133+
QgsDebugMsg( "representValue() with inconsistant fieldIdx parameter w.r.t relation referencingFieldIdx" );
134+
return value.toString();
135+
}
136+
QgsVectorLayer* referencedLayer = relation.referencedLayer();
137+
if ( !referencedLayer )
138+
{
139+
QgsDebugMsg( "Cannot find referenced layer" );
140+
return value.toString();
141+
}
142+
143+
// Attributes from the referencing layer
144+
QgsAttributes attrs = QgsAttributes( vl->fields().count() );
145+
// Set the value on the foreign key field of the referencing record
146+
attrs[ referencingFieldIdx ] = value;
147+
148+
QgsFeatureRequest request = relation.getReferencedFeatureRequest( attrs );
149+
QgsFeature feature;
150+
referencedLayer->getFeatures( request ).nextFeature( feature );
151+
if ( !feature.isValid() )
152+
return value.toString();
153+
154+
QgsExpression expr( referencedLayer->displayExpression() );
155+
QgsExpressionContext context;
156+
context << QgsExpressionContextUtils::globalScope()
157+
<< QgsExpressionContextUtils::projectScope()
158+
<< QgsExpressionContextUtils::layerScope( referencedLayer );
159+
context.setFeature( feature );
160+
QString title = expr.evaluate( &context ).toString();
161+
if ( expr.hasEvalError() )
162+
{
163+
int referencedFieldIdx = referencedLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).second );
164+
title = feature.attribute( referencedFieldIdx ).toString();
165+
}
166+
return title;
167+
}

‎src/gui/editorwidgets/qgsrelationreferencefactory.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class GUI_EXPORT QgsRelationReferenceFactory : public QgsEditorWidgetFactory
7979
*/
8080
virtual void writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx ) override;
8181

82+
QString representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const override;
83+
8284
virtual QMap<const char*, int> supportedWidgetTypes() override;
8385

8486
private:

‎tests/src/python/test_qgseditwidgets.py

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import qgis # NOQA
1616

17-
from qgis.core import QgsFeature, QgsGeometry, QgsPoint, QgsVectorLayer, NULL
17+
from qgis.core import QgsMapLayerRegistry, QgsFeature, QgsGeometry, QgsPoint, QgsProject, QgsRelation, QgsVectorLayer, NULL
1818
from qgis.gui import QgsEditorWidgetRegistry
1919

2020
from qgis.testing import start_app, unittest
@@ -63,6 +63,139 @@ def test_SetValue(self):
6363
self.doAttributeTest(0, ['value', '123', NULL, NULL])
6464
self.doAttributeTest(1, [NULL, 123, NULL, NULL])
6565

66+
def test_ValueRelation_representValue(self):
67+
68+
first_layer = QgsVectorLayer("none?field=foreign_key:integer",
69+
"first_layer", "memory")
70+
assert first_layer.isValid()
71+
second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string",
72+
"second_layer", "memory")
73+
assert second_layer.isValid()
74+
QgsMapLayerRegistry.instance().addMapLayer(second_layer)
75+
f = QgsFeature()
76+
f.setAttributes([123])
77+
assert first_layer.dataProvider().addFeatures([f])
78+
f = QgsFeature()
79+
f.setAttributes([123, 'decoded_val'])
80+
assert second_layer.dataProvider().addFeatures([f])
81+
82+
reg = QgsEditorWidgetRegistry.instance()
83+
factory = reg.factory("ValueRelation")
84+
self.assertIsNotNone(factory)
85+
86+
# Everything valid
87+
config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'}
88+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), 'decoded_val')
89+
90+
# Code not find match in foreign layer
91+
config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded'}
92+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)')
93+
94+
# Missing Layer
95+
config = {'Key': 'pkid', 'Value': 'decoded'}
96+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)')
97+
98+
# Invalid Layer
99+
config = {'Layer': 'invalid', 'Key': 'pkid', 'Value': 'decoded'}
100+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)')
101+
102+
# Invalid Key
103+
config = {'Layer': second_layer.id(), 'Key': 'invalid', 'Value': 'decoded'}
104+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)')
105+
106+
# Invalid Value
107+
config = {'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'invalid'}
108+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '(456)')
109+
110+
QgsMapLayerRegistry.instance().removeMapLayer(second_layer.id())
111+
112+
def test_RelationReference_representValue(self):
113+
114+
first_layer = QgsVectorLayer("none?field=foreign_key:integer",
115+
"first_layer", "memory")
116+
assert first_layer.isValid()
117+
second_layer = QgsVectorLayer("none?field=pkid:integer&field=decoded:string",
118+
"second_layer", "memory")
119+
assert second_layer.isValid()
120+
QgsMapLayerRegistry.instance().addMapLayers([first_layer, second_layer])
121+
f = QgsFeature()
122+
f.setAttributes([123])
123+
assert first_layer.dataProvider().addFeatures([f])
124+
f = QgsFeature()
125+
f.setAttributes([123, 'decoded_val'])
126+
assert second_layer.dataProvider().addFeatures([f])
127+
128+
relMgr = QgsProject.instance().relationManager()
129+
130+
reg = QgsEditorWidgetRegistry.instance()
131+
factory = reg.factory("RelationReference")
132+
self.assertIsNotNone(factory)
133+
134+
rel = QgsRelation()
135+
rel.setRelationId('rel1')
136+
rel.setRelationName('Relation Number One')
137+
rel.setReferencingLayer(first_layer.id())
138+
rel.setReferencedLayer(second_layer.id())
139+
rel.addFieldPair('foreign_key', 'pkid')
140+
assert(rel.isValid())
141+
142+
relMgr.addRelation(rel)
143+
144+
# Everything valid
145+
config = {'Relation': rel.id()}
146+
second_layer.setDisplayExpression('decoded')
147+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), 'decoded_val')
148+
149+
# Code not find match in foreign layer
150+
config = {'Relation': rel.id()}
151+
second_layer.setDisplayExpression('decoded')
152+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '456'), '456')
153+
154+
# Invalid relation id
155+
config = {'Relation': 'invalid'}
156+
second_layer.setDisplayExpression('decoded')
157+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123')
158+
159+
# No display expression
160+
config = {'Relation': rel.id()}
161+
second_layer.setDisplayExpression(None)
162+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123')
163+
164+
# Invalid display expression
165+
config = {'Relation': rel.id()}
166+
second_layer.setDisplayExpression('invalid +')
167+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123')
168+
169+
# Missing relation
170+
config = {}
171+
second_layer.setDisplayExpression('decoded')
172+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123')
173+
174+
# Inconsistent layer provided to representValue()
175+
config = {'Relation': rel.id()}
176+
second_layer.setDisplayExpression('decoded')
177+
self.assertEqual(factory.representValue(second_layer, 0, config, None, '123'), '123')
178+
179+
# Inconsistent idx provided to representValue()
180+
config = {'Relation': rel.id()}
181+
second_layer.setDisplayExpression('decoded')
182+
self.assertEqual(factory.representValue(first_layer, 1, config, None, '123'), '123')
183+
184+
# Invalid relation
185+
rel = QgsRelation()
186+
rel.setRelationId('rel2')
187+
rel.setRelationName('Relation Number Two')
188+
rel.setReferencingLayer(first_layer.id())
189+
rel.addFieldPair('foreign_key', 'pkid')
190+
self.assertFalse(rel.isValid())
191+
192+
relMgr.addRelation(rel)
193+
194+
config = {'Relation': rel.id()}
195+
second_layer.setDisplayExpression('decoded')
196+
self.assertEqual(factory.representValue(first_layer, 0, config, None, '123'), '123')
197+
198+
QgsMapLayerRegistry.instance().removeAllMapLayers()
66199

67200
if __name__ == '__main__':
68201
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.