Skip to content

Commit

Permalink
Merge pull request #1617 from lutraconsulting/1568-discover-relations
Browse files Browse the repository at this point in the history
Discover relations in autogenerated config
  • Loading branch information
tomasMizera authored Aug 31, 2021
2 parents 06b316f + 910c0e4 commit 71b9236
Show file tree
Hide file tree
Showing 9 changed files with 1,723 additions and 374 deletions.
57 changes: 57 additions & 0 deletions app/attributes/attributecontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ void AttributeController::updateOnLayerChange()
// Auto-Generated Layout
// We create fake root tab
QgsAttributeEditorContainer *tab = autoLayoutTabContainer();

// We need to look for relations and include them into form,
// in auto-generated layout they are not included in form config
discoverRelations( tab );

createTab( tab );
}

Expand Down Expand Up @@ -987,6 +992,58 @@ void AttributeController::setFieldValuesValid( bool valid )
}
}

void AttributeController::discoverRelations( QgsAttributeEditorContainer *container )
{
QgsRelationManager *rManager = QgsProject::instance()->relationManager();

if ( !rManager || !mFeatureLayerPair.layer() )
return;

// find relation references (add relation reference widgets)
const QList<QgsRelation> childRelations = rManager->referencingRelations( mFeatureLayerPair.layer() );

for ( const QgsRelation &relation : childRelations )
{
for ( QgsAttributeEditorElement *child : container->children() )
{
if ( child->name() == relation.fieldPairs().at( 0 ).first )
{
CoreUtils::log( QStringLiteral( "DiscoverRelations" ), QStringLiteral( "Changing field %1 to RelationReference" ) );
QgsAttributeEditorField *editorField = static_cast<QgsAttributeEditorField *>( child );

if ( editorField )
{
int fieldIdx = editorField->idx();
QgsField field = mFeatureLayerPair.layer()->fields().at( fieldIdx );
QVariantMap additionalArgs = { { "ReferencedLayerId", relation.referencedLayerId() } };

// relation reference fields in autogenerated fields have empty config, we need to set needed properties here
if ( mFeatureLayerPair.layer()->editorWidgetSetup( fieldIdx ).config().isEmpty() )
{
const QgsEditorWidgetSetup newWidgetSetup = InputUtils::getEditorWidgetSetup( field, QStringLiteral( "RelationReference" ), additionalArgs );
mFeatureLayerPair.layer()->setEditorWidgetSetup( fieldIdx, newWidgetSetup );
}
}
}
}
}

// find relations (add relation widgets)
const QList<QgsRelation> referencingRelations = rManager->referencedRelations( mFeatureLayerPair.layer() );

for ( const QgsRelation &relation : referencingRelations )
{
std::unique_ptr<QgsAttributeEditorRelation> relationEditor = std::unique_ptr<QgsAttributeEditorRelation>( new QgsAttributeEditorRelation( relation, container ) );
if ( relationEditor->label().isEmpty() && relation.name().isEmpty() )
{
// relation does not have a name nor field have label, set label based on child layer
QString label = relation.referencingLayer()->name();
relationEditor->setLabel( label );
}
container->addChildElement( relationEditor.release() );
}
}

bool AttributeController::isValidFormId( const QUuid &id ) const
{
return mFormItems.contains( id );
Expand Down
1 change: 1 addition & 0 deletions app/attributes/attributecontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class AttributeController : public QObject
void setHasAnyChanges( bool hasChanges );
void updateFieldValuesValidity();
void setFieldValuesValid( bool valid );
void discoverRelations( QgsAttributeEditorContainer *container );

bool isValidTabId( int id ) const;
bool isValidFormId( const QUuid &id ) const;
Expand Down
8 changes: 7 additions & 1 deletion app/inpututils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ const QgsEditorWidgetSetup InputUtils::getEditorWidgetSetup( const QgsField &fie
return getEditorWidgetSetup( field, QStringLiteral( "TextEdit" ) );
}

const QgsEditorWidgetSetup InputUtils::getEditorWidgetSetup( const QgsField &field, const QString &widgetType )
const QgsEditorWidgetSetup InputUtils::getEditorWidgetSetup( const QgsField &field, const QString &widgetType, const QVariantMap &additionalArgs )
{
if ( field.name() == QStringLiteral( "fid" ) )
return QgsEditorWidgetSetup( QStringLiteral( "Hidden" ), QVariantMap() );
Expand All @@ -816,6 +816,8 @@ const QgsEditorWidgetSetup InputUtils::getEditorWidgetSetup( const QgsField &fie
else
{
QVariantMap config;
config = config.unite( additionalArgs );

if ( widgetType == QStringLiteral( "TextEdit" ) )
{
config.insert( QStringLiteral( "isMultiline" ), false );
Expand All @@ -842,6 +844,10 @@ const QgsEditorWidgetSetup InputUtils::getEditorWidgetSetup( const QgsField &fie
QgsPropertyCollection collection;
config.insert( QStringLiteral( "PropertyCollection" ), collection.toVariant( QgsPropertiesDefinition() ) );
}
else if ( widgetType == QStringLiteral( "RelationReference" ) )
{
config.insert( QStringLiteral( "AllowNULL" ), true );
}

return QgsEditorWidgetSetup( widgetType, config );
}
Expand Down
2 changes: 1 addition & 1 deletion app/inpututils.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ class InputUtils: public QObject
* @return QgsEditorWidgetSetup for given field.
*/
static const QgsEditorWidgetSetup getEditorWidgetSetup( const QgsField &field );
static const QgsEditorWidgetSetup getEditorWidgetSetup( const QgsField &field, const QString &widgetType );
static const QgsEditorWidgetSetup getEditorWidgetSetup( const QgsField &field, const QString &widgetType, const QVariantMap &additionalArgs = QVariantMap() );

// Returns geometry type in form that qml understands
Q_INVOKABLE static QString geometryFromLayer( QgsVectorLayer *layer );
Expand Down
74 changes: 74 additions & 0 deletions app/test/testformeditors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <memory>

#include "qgsvectorlayer.h"
#include "qgsrelationmanager.h"

void TestFormEditors::init()
{
Expand Down Expand Up @@ -156,3 +157,76 @@ void TestFormEditors::testNumericFields()
// field "Cabin Crew" stayed with invalid input, check controller flag of values validity
QCOMPARE( controller.fieldValuesValid(), false );
}

void TestFormEditors::testRelationsWidgetPresence()
{
QString projectDir = TestUtils::testDataDir() + "/planes";
QString projectName = "quickapp_project.qgs";

QString layersDb = projectDir + "/geo-layers.gpkg";

QSignalSpy spy( QgsProject::instance()->relationManager(), &QgsRelationManager::relationsLoaded );
QVERIFY( QgsProject::instance()->read( projectDir + "/" + projectName ) );
QCOMPARE( spy.count(), 1 );


QgsMapLayer *airportsLayer = QgsProject::instance()->mapLayersByName( QStringLiteral( "airports" ) ).at( 0 );
QgsVectorLayer *airportsVLayer = static_cast<QgsVectorLayer *>( airportsLayer );

QgsMapLayer *airportTowersLayer = QgsProject::instance()->mapLayersByName( QStringLiteral( "airport-towers" ) ).at( 0 );
QgsVectorLayer *airportTowersVLayer = static_cast<QgsVectorLayer *>( airportTowersLayer );

QVERIFY( airportsVLayer && airportsVLayer->isValid() );
QVERIFY( airportTowersVLayer && airportTowersVLayer->isValid() );

// check if we added exactly one relation widget when project has autogenerated layout

QgsFeature f = airportsVLayer->getFeature( 1 );
FeatureLayerPair pair( f, airportsVLayer );

AttributeController controller;
controller.setFeatureLayerPair( pair );

const TabItem *tabItem = controller.tabItem( 0 );
QVector<QUuid> formItems = tabItem->formItems();

int relationsCount = 0;
int relationReferencesCount = 0;

for ( const auto &itemId : formItems )
{
const FormItem *item = controller.formItem( itemId );
if ( item->editorWidgetType() == QStringLiteral( "relation" ) )
relationsCount++;
else if ( item->editorWidgetType() == QStringLiteral( "RelationReference" ) )
relationReferencesCount++;
}

QVERIFY( relationsCount == 1 );
QVERIFY( relationReferencesCount == 0 );

// check if we added exactly one relation reference widget when project has autogenerated layout

QgsFeature ft = airportTowersVLayer->getFeature( 1 );
FeatureLayerPair pairTower( ft, airportTowersVLayer );

controller.setFeatureLayerPair( pairTower );

const TabItem *tabItemTower = controller.tabItem( 0 );
formItems = tabItemTower->formItems();

relationsCount = 0;
relationReferencesCount = 0;

for ( const auto &itemId : formItems )
{
const FormItem *item = controller.formItem( itemId );
if ( item->editorWidgetType() == QStringLiteral( "relation" ) )
relationsCount++;
else if ( item->editorWidgetType() == QStringLiteral( "RelationReference" ) )
relationReferencesCount++;
}

QVERIFY( relationsCount == 0 );
QVERIFY( relationReferencesCount == 1 );
}
1 change: 1 addition & 0 deletions app/test/testformeditors.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class TestFormEditors : public QObject
void cleanup(); // will be called after every testfunction.

void testNumericFields();
void testRelationsWidgetPresence();
};

#endif // TESTFORMEDITORS_H
4 changes: 0 additions & 4 deletions core/merginprojectmetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,6 @@ MerginConfig MerginConfig::fromFile( const QString &filePath )
QByteArray data = file.readAll();
config = MerginConfig::fromJson( data );
}
else
{
CoreUtils::log( QStringLiteral( "MerginConfig" ), QStringLiteral( "Project does not contain a config file on path: %1" ).arg( filePath ) );
}

return config;
}
Binary file added test/test_data/planes/geo-layers.gpkg
Binary file not shown.
Loading

3 comments on commit 71b9236

@inputapp-bot
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signed apk: armeabi-v7a (SDK: android-22)

@inputapp-bot
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signed apk: arm64-v8a (SDK: android-22)

@inputapp-bot
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ios-2.15.210831192434 (SDK: ios-15)

Please sign in to comment.