diff --git a/python/core/qgsrelation.sip b/python/core/qgsrelation.sip index 9fbf998d816..394cf21d395 100644 --- a/python/core/qgsrelation.sip +++ b/python/core/qgsrelation.sip @@ -118,13 +118,22 @@ class QgsRelation */ QgsFeatureRequest getRelatedFeaturesRequest( const QgsFeature& feature ) const; - const QString name() const; + QgsFeatureRequest getReferencedFeatureRequest( const QgsFeature& feature ) const; + + QgsFeature getReferencedFeature( const QgsFeature& child ) const; /** * The id * @return */ - const QString& id() const; + QString name() const; + + /** + * A (project-wide) unique id for this relation + * + * @return The id + */ + QString id() const; /** * Access the referencing (child) layer's id @@ -182,5 +191,4 @@ class QgsRelation protected: void updateRelationStatus(); - void runChecks(); }; diff --git a/src/core/qgsrelation.cpp b/src/core/qgsrelation.cpp index ecad538c5ee..4268dfcb67e 100644 --- a/src/core/qgsrelation.cpp +++ b/src/core/qgsrelation.cpp @@ -97,7 +97,7 @@ void QgsRelation::writeXML( QDomNode &node, QDomDocument &doc ) const elem.setAttribute( "referencingLayer", mReferencingLayerId ); elem.setAttribute( "referencedLayer", mReferencedLayerId ); - foreach ( FieldPair fields, mFieldPairs ) + Q_FOREACH ( FieldPair fields, mFieldPairs ) { QDomElement referenceElem = doc.createElement( "fieldRef" ); referenceElem.setAttribute( "referencingField", fields.first ); @@ -153,22 +153,20 @@ QgsFeatureRequest QgsRelation::getRelatedFeaturesRequest( const QgsFeature& feat { QStringList conditions; - foreach ( const QgsRelation::FieldPair& fieldPair, mFieldPairs ) + Q_FOREACH ( const QgsRelation::FieldPair& fieldPair, mFieldPairs ) { int referencingIdx = referencingLayer()->pendingFields().indexFromName( fieldPair.referencingField() ); QgsField referencingField = referencingLayer()->pendingFields().at( referencingIdx ); - switch ( referencingField.type() ) + if ( referencingField.type() == QVariant::String ) { - case QVariant::String: - // Use quotes - conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() ); - break; - - default: - // No quotes - conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() ); - break; + // Use quotes + conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() ); + } + else + { + // No quotes + conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() ); } } @@ -181,12 +179,58 @@ QgsFeatureRequest QgsRelation::getRelatedFeaturesRequest( const QgsFeature& feat return myRequest; } -const QString QgsRelation::name() const +QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsAttributes& attributes ) const +{ + QStringList conditions; + + Q_FOREACH ( const QgsRelation::FieldPair& fieldPair, mFieldPairs ) + { + int referencedIdx = referencedLayer()->pendingFields().indexFromName( fieldPair.referencedField() ); + int referencingIdx = referencingLayer()->pendingFields().indexFromName( fieldPair.referencingField() ); + + QgsField referencedField = referencedLayer()->pendingFields().at( referencedIdx ); + + if ( referencedField.type() == QVariant::String ) + { + // Use quotes + conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencedField(), attributes[referencingIdx].toString() ); + } + else + { + // No quotes + conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencedField(), attributes[referencingIdx].toString() ); + } + } + + QgsFeatureRequest myRequest; + + QgsDebugMsg( QString( "Filter conditions: '%1'" ).arg( conditions.join( " AND " ) ) ); + + myRequest.setFilterExpression( conditions.join( " AND " ) ); + + return myRequest; +} + +QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsFeature& feature ) const +{ + return getReferencedFeatureRequest( feature.attributes() ); +} + +QgsFeature QgsRelation::getReferencedFeature( const QgsFeature& child ) const +{ + QgsFeatureRequest request = getReferencedFeatureRequest( child ); + + QgsFeature f; + mReferencedLayer->getFeatures( request ).nextFeature( f ); + return f; +} + +QString QgsRelation::name() const { return mRelationName; } -const QString& QgsRelation::id() const +QString QgsRelation::id() const { return mRelationId; } @@ -251,8 +295,3 @@ void QgsRelation::updateRelationStatus() } } } - -void QgsRelation::runChecks() -{ - -} diff --git a/src/core/qgsrelation.h b/src/core/qgsrelation.h index 247c51fd59c..64e43624a0c 100644 --- a/src/core/qgsrelation.h +++ b/src/core/qgsrelation.h @@ -138,17 +138,55 @@ class CORE_EXPORT QgsRelation * * @param feature A feature from the referenced (parent) layer * - * @return An request for all the referenced features + * @return A request for all the referencing features */ QgsFeatureRequest getRelatedFeaturesRequest( const QgsFeature& feature ) const; - const QString name() const; + /** + * Creates a request to return the feature on the referenced (parent) layer + * which is referenced by the provided feature. + * + * @param attributes An attribute vector containing the foreign key + * + * @return A request the referenced feature + */ + QgsFeatureRequest getReferencedFeatureRequest( const QgsAttributes& attributes ) const; /** - * The id - * @return + * Creates a request to return the feature on the referenced (parent) layer + * which is referenced by the provided feature. + * + * @param feature A feature from the referencing (child) layer + * + * @return A request the referenced feature */ - const QString& id() const; + QgsFeatureRequest getReferencedFeatureRequest( const QgsFeature& feature ) const; + + /** + * Creates a request to return the feature on the referenced (parent) layer + * which is referenced by the provided feature. + * + * @param feature A feature from the referencing (child) layer + * + * @return A request the referenced feature + */ + QgsFeature getReferencedFeature( const QgsFeature& child ) const; + + /** + * Returns a human readable name for this relation. Mostly used as title for the children. + * + * @see id() + * + * @return A name + */ + QString name() const; + + /** + * A (project-wide) unique id for this relation + * + * @return The id + */ + QString id() const; /** * Access the referencing (child) layer's id @@ -198,7 +236,6 @@ class CORE_EXPORT QgsRelation protected: void updateRelationStatus(); - void runChecks(); private: /** Unique Id */ diff --git a/tests/src/python/test_qgsrelation.py b/tests/src/python/test_qgsrelation.py index 212292c3606..c6809d4b7dc 100644 --- a/tests/src/python/test_qgsrelation.py +++ b/tests/src/python/test_qgsrelation.py @@ -25,110 +25,122 @@ from utilities import (getQgisTestApp, TestCase, unittest ) + QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp() + def createReferencingLayer(): layer = QgsVectorLayer("Point?field=fldtxt:string&field=foreignkey:integer", "referencinglayer", "memory") pr = layer.dataProvider() f1 = QgsFeature() - f1.setFields( layer.pendingFields() ) + f1.setFields(layer.pendingFields()) f1.setAttributes(["test1", 123]) - f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(100,200))) + f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200))) f2 = QgsFeature() - f2.setFields( layer.pendingFields() ) + f2.setFields(layer.pendingFields()) f2.setAttributes(["test2", 123]) - f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(101,201))) - assert pr.addFeatures([f1,f2]) + f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(101, 201))) + assert pr.addFeatures([f1, f2]) return layer + def createReferencedLayer(): layer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", "referencedlayer", "memory") pr = layer.dataProvider() f1 = QgsFeature() - f1.setFields( layer.pendingFields() ) + f1.setFields(layer.pendingFields()) f1.setAttributes(["foo", 123, 321]) - f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(1,1))) + f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(1, 1))) f2 = QgsFeature() - f2.setFields( layer.pendingFields() ) + f2.setFields(layer.pendingFields()) f2.setAttributes(["bar", 456, 654]) - f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(2,2))) + f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 2))) f3 = QgsFeature() - f3.setFields( layer.pendingFields() ) + f3.setFields(layer.pendingFields()) f3.setAttributes(["foobar", 789, 554]) - f3.setGeometry(QgsGeometry.fromPoint(QgsPoint(2,3))) + f3.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 3))) assert pr.addFeatures([f1, f2, f3]) return layer -def formatAttributes(attrs): - return repr([ unicode(a) for a in attrs ]) -class TestQgsRelation( TestCase ): +def formatAttributes(attrs): + return repr([unicode(a) for a in attrs]) + + +class TestQgsRelation(TestCase): + def setUp(self): + self.referencedLayer = createReferencedLayer() + self.referencingLayer = createReferencingLayer() + QgsMapLayerRegistry.instance().addMapLayers([self.referencedLayer, self.referencingLayer]) + + def tearDown(self): + QgsMapLayerRegistry.instance().removeAllMapLayers() def test_isValid(self): - referencedLayer = createReferencedLayer() - referencingLayer = createReferencingLayer() - QgsMapLayerRegistry.instance().addMapLayers([referencedLayer,referencingLayer]) rel = QgsRelation() assert not rel.isValid() - rel.setRelationId( 'rel1' ) + rel.setRelationId('rel1') assert not rel.isValid() - rel.setRelationName( 'Relation Number One' ) + rel.setRelationName('Relation Number One') assert not rel.isValid() - rel.setReferencingLayer( referencingLayer.id() ) + rel.setReferencingLayer(self.referencingLayer.id()) assert not rel.isValid() - rel.setReferencedLayer( referencedLayer.id() ) + rel.setReferencedLayer(self.referencedLayer.id()) assert not rel.isValid() - rel.addFieldPair( 'foreignkey', 'y' ) + rel.addFieldPair('foreignkey', 'y') assert rel.isValid() - QgsMapLayerRegistry.instance().removeAllMapLayers() def test_getRelatedFeatures(self): - referencedLayer = createReferencedLayer() - referencingLayer = createReferencingLayer() - QgsMapLayerRegistry.instance().addMapLayers([referencedLayer,referencingLayer]) - rel = QgsRelation() - rel.setRelationId( 'rel1' ) - rel.setRelationName( 'Relation Number One' ) - rel.setReferencingLayer( referencingLayer.id() ) - rel.setReferencedLayer( referencedLayer.id() ) - rel.addFieldPair( 'foreignkey', 'y' ) + rel.setRelationId('rel1') + rel.setRelationName('Relation Number One') + rel.setReferencingLayer(self.referencingLayer.id()) + rel.setReferencedLayer(self.referencedLayer.id()) + rel.addFieldPair('foreignkey', 'y') - feat = referencedLayer.getFeatures().next() + feat = self.referencedLayer.getFeatures().next() - it = rel.getRelatedFeatures( feat ) + it = rel.getRelatedFeatures(feat) - [ a.attributes() for a in it ] == [[u'test1', 123], [u'test2', 123]] + assert [a.attributes() for a in it] == [[u'test1', 123], [u'test2', 123]] + + def test_getReferencedFeature(self): + rel = QgsRelation() + rel.setRelationId('rel1') + rel.setRelationName('Relation Number One') + rel.setReferencingLayer(self.referencingLayer.id()) + rel.setReferencedLayer(self.referencedLayer.id()) + rel.addFieldPair('foreignkey', 'y') + + feat = self.referencingLayer.getFeatures().next() + + f = rel.getReferencedFeature(feat) + + assert f.isValid() + assert f[0] == 'foo' - QgsMapLayerRegistry.instance().removeAllMapLayers() def test_fieldPairs(self): - referencedLayer = createReferencedLayer() - referencingLayer = createReferencingLayer() - QgsMapLayerRegistry.instance().addMapLayers([referencedLayer,referencingLayer]) - rel = QgsRelation() - rel.setRelationId( 'rel1' ) - rel.setRelationName( 'Relation Number One' ) - rel.setReferencingLayer( referencingLayer.id() ) - rel.setReferencedLayer( referencedLayer.id() ) - rel.addFieldPair( 'foreignkey', 'y' ) + rel.setRelationId('rel1') + rel.setRelationName('Relation Number One') + rel.setReferencingLayer(self.referencingLayer.id()) + rel.setReferencedLayer(self.referencedLayer.id()) + rel.addFieldPair('foreignkey', 'y') - assert( rel.fieldPairs() == { 'foreignkey': 'y'} ) - - QgsMapLayerRegistry.instance().removeAllMapLayers() + assert (rel.fieldPairs() == {'foreignkey': 'y'}) if __name__ == '__main__':