Skip to content

Commit

Permalink
Fixes qgis#37702 : move Forms style import/export under the right cat…
Browse files Browse the repository at this point in the history
…egory
  • Loading branch information
troopa81 committed Sep 23, 2020
1 parent 3119eb7 commit 94596dc
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 38 deletions.
94 changes: 56 additions & 38 deletions src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2312,29 +2312,6 @@ bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMes

updateFields();

// Load editor widget configuration
QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
{
const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();

QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );
mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), QgsField::ConfigurationFlag::None );

const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
if ( widgetType == QStringLiteral( "ValueRelation" ) )
{
optionsMap[ QStringLiteral( "Value" ) ] = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuerelationvalue" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text(), fieldName ), optionsMap[ QStringLiteral( "Value" ) ].toString() );
}
QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
mFieldWidgetSetups[fieldName] = setup;
}

// Legacy reading for QGIS 3.14 and older projects
// Attributes excluded from WMS and WFS
const QList<QPair<QString, QgsField::ConfigurationFlag>> legacyConfig
Expand All @@ -2358,6 +2335,38 @@ bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMes
}
}

// load field configuration
if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
{
QDomElement widgetsElem = layerNode.namedItem( QStringLiteral( "fieldConfiguration" ) ).toElement();
QDomNodeList fieldConfigurationElementList = widgetsElem.elementsByTagName( QStringLiteral( "field" ) );
for ( int i = 0; i < fieldConfigurationElementList.size(); ++i )
{
const QDomElement fieldConfigElement = fieldConfigurationElementList.at( i ).toElement();
const QDomElement fieldWidgetElement = fieldConfigElement.elementsByTagName( QStringLiteral( "editWidget" ) ).at( 0 ).toElement();

QString fieldName = fieldConfigElement.attribute( QStringLiteral( "name" ) );

if ( categories.testFlag( Fields ) )
mFieldConfigurationFlags[fieldName] = qgsFlagKeysToValue( fieldConfigElement.attribute( QStringLiteral( "configurationFlags" ) ), QgsField::ConfigurationFlag::None );

// Load editor widget configuration
if ( categories.testFlag( Forms ) )
{
const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
const QDomElement cfgElem = fieldConfigElement.elementsByTagName( QStringLiteral( "config" ) ).at( 0 ).toElement();
const QDomElement optionsElem = cfgElem.childNodes().at( 0 ).toElement();
QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
if ( widgetType == QStringLiteral( "ValueRelation" ) )
{
optionsMap[ QStringLiteral( "Value" ) ] = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuerelationvalue" ).arg( layerNode.namedItem( QStringLiteral( "id" ) ).toElement().text(), fieldName ), optionsMap[ QStringLiteral( "Value" ) ].toString() );
}
QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( widgetType, optionsMap );
mFieldWidgetSetups[fieldName] = setup;
}
}
}

if ( categories.testFlag( GeometryOptions ) )
mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );

Expand Down Expand Up @@ -2642,35 +2651,44 @@ bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString

}

if ( categories.testFlag( Fields ) )
// write field configurations
if ( categories.testFlag( Fields ) || categories.testFlag( Forms ) )
{
QDomElement fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
QDomElement fieldConfigurationElement;
// field configuration flag
fieldConfigurationElement = doc.createElement( QStringLiteral( "fieldConfiguration" ) );
node.appendChild( fieldConfigurationElement );

int index = 0;
for ( const QgsField &field : qgis::as_const( mFields ) )
{
QDomElement fieldElement = doc.createElement( QStringLiteral( "field" ) );
fieldElement.setAttribute( QStringLiteral( "name" ), field.name() );
fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );

fieldConfigurationElement.appendChild( fieldElement );

QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
if ( categories.testFlag( Fields ) )
{
fieldElement.setAttribute( QStringLiteral( "configurationFlags" ), qgsFlagValueToKeys( field.configurationFlags() ) );
}

// TODO : wrap this part in an if to only save if it was user-modified
QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
fieldElement.appendChild( editWidgetElement );
editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
if ( categories.testFlag( Forms ) )
{
QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();

editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
editWidgetElement.appendChild( editWidgetConfigElement );
// END TODO : wrap this part in an if to only save if it was user-modified
// TODO : wrap this part in an if to only save if it was user-modified
QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
fieldElement.appendChild( editWidgetElement );
editWidgetElement.setAttribute( QStringLiteral( "type" ), field.editorWidgetSetup().type() );
QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );

++index;
editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
editWidgetElement.appendChild( editWidgetConfigElement );
// END TODO : wrap this part in an if to only save if it was user-modified
}
}
}

if ( categories.testFlag( Fields ) )
{
//attribute aliases
QDomElement aliasElem = doc.createElement( QStringLiteral( "aliases" ) );
for ( const QgsField &field : qgis::as_const( mFields ) )
Expand Down
59 changes: 59 additions & 0 deletions tests/src/core/testqgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class TestQgsVectorLayer : public QObject
void maximumValue();
void isSpatial();
void testAddTopologicalPoints();
void testCopyPasteFieldConfiguration();
void testCopyPasteFieldConfiguration_data();
};

void TestQgsVectorLayer::initTestCase()
Expand Down Expand Up @@ -380,5 +382,62 @@ void TestQgsVectorLayer::testAddTopologicalPoints()
delete layerLine;
}

void TestQgsVectorLayer::testCopyPasteFieldConfiguration_data()
{
QTest::addColumn<QgsMapLayer::StyleCategories>( "categories" );
// QTest::addColumn<double>( "flagExpected" );
// QTest::addColumn<double>( "widgetExpected" );

QTest::newRow( "forms_and_fields" ) << ( QgsMapLayer::Fields | QgsMapLayer::Forms );
QTest::newRow( "forms" ) << QgsMapLayer::StyleCategories( QgsMapLayer::Forms );
QTest::newRow( "fields" ) << QgsMapLayer::StyleCategories( QgsMapLayer::Fields );
QTest::newRow( "none" ) << QgsMapLayer::StyleCategories( QgsMapLayer::StyleCategories() );
}

void TestQgsVectorLayer::testCopyPasteFieldConfiguration()
{
QFETCH( QgsMapLayer::StyleCategories, categories );

QgsVectorLayer layer1( QStringLiteral( "Point?field=name:string" ), QStringLiteral( "layer1" ), QStringLiteral( "memory" ) );
QVERIFY( layer1.isValid() );
QVERIFY( layer1.editorWidgetSetup( 0 ).type().isEmpty() );
QCOMPARE( layer1.fieldConfigurationFlags( 0 ), QgsField::ConfigurationFlags() );

layer1.setEditorWidgetSetup( 0, QgsEditorWidgetSetup( "ValueMap", QVariantMap() ) );
QCOMPARE( layer1.editorWidgetSetup( 0 ).type(), QStringLiteral( "ValueMap" ) );
layer1.setFieldConfigurationFlags( 0, QgsField::ConfigurationFlag::NotSearchable );
QCOMPARE( layer1.fieldConfigurationFlags( 0 ), QgsField::ConfigurationFlag::NotSearchable );

// export given categories, import all
QString errorMsg;
QDomDocument doc( QStringLiteral( "qgis" ) );
QgsReadWriteContext context;
layer1.exportNamedStyle( doc, errorMsg, context, categories );
QVERIFY( errorMsg.isEmpty() );

QgsVectorLayer layer2( QStringLiteral( "Point?field=name:string" ), QStringLiteral( "layer2" ), QStringLiteral( "memory" ) );
QVERIFY( layer2.isValid() );
QVERIFY( layer2.editorWidgetSetup( 0 ).type().isEmpty() );
QCOMPARE( layer2.fieldConfigurationFlags( 0 ), QgsField::ConfigurationFlags() );

QVERIFY( layer2.importNamedStyle( doc, errorMsg ) );
QCOMPARE( layer2.editorWidgetSetup( 0 ).type(), categories.testFlag( QgsMapLayer::Forms ) ? QStringLiteral( "ValueMap" ) : QString( "" ) );
QCOMPARE( layer2.fieldConfigurationFlags( 0 ), categories.testFlag( QgsMapLayer::Fields ) ? QgsField::ConfigurationFlag::NotSearchable : QgsField::ConfigurationFlags() );

// export all, import given categories
QDomDocument doc2( QStringLiteral( "qgis" ) );
layer1.exportNamedStyle( doc2, errorMsg, context );
QVERIFY( errorMsg.isEmpty() );

QgsVectorLayer layer3( QStringLiteral( "Point?field=name:string" ), QStringLiteral( "layer3" ), QStringLiteral( "memory" ) );
QVERIFY( layer3.isValid() );
QVERIFY( layer3.editorWidgetSetup( 0 ).type().isEmpty() );
QCOMPARE( layer3.fieldConfigurationFlags( 0 ), QgsField::ConfigurationFlags() );

QVERIFY( layer3.importNamedStyle( doc2, errorMsg, categories ) );
QCOMPARE( layer3.editorWidgetSetup( 0 ).type(), categories.testFlag( QgsMapLayer::Forms ) ? QStringLiteral( "ValueMap" ) : QString( "" ) );
QCOMPARE( layer3.fieldConfigurationFlags( 0 ), categories.testFlag( QgsMapLayer::Fields ) ? QgsField::ConfigurationFlag::NotSearchable : QgsField::ConfigurationFlags() );
}

QGSTEST_MAIN( TestQgsVectorLayer )
#include "testqgsvectorlayer.moc"

0 comments on commit 94596dc

Please sign in to comment.