[gui] Fix value map editor widget configuration's load from CSV parsing

This commit is contained in:
nirvn 2022-02-13 12:43:47 +07:00 committed by Nyall Dawson
parent 4e035e686b
commit 4131eb265c
5 changed files with 119 additions and 39 deletions

View File

@ -301,14 +301,18 @@ void QgsValueMapConfigDlg::loadFromCSVButtonPushed()
const QString fileName = QFileDialog::getOpenFileName( nullptr, tr( "Load Value Map from File" ), QDir::homePath() );
if ( fileName.isNull() )
return;
loadMapFromCSV( fileName );
}
QFile f( fileName );
void QgsValueMapConfigDlg::loadMapFromCSV( const QString &filePath )
{
QFile f( filePath );
if ( !f.open( QIODevice::ReadOnly ) )
{
QMessageBox::information( nullptr,
tr( "Load Value Map from File" ),
tr( "Could not open file %1\nError was: %2" ).arg( fileName, f.errorString() ),
tr( "Could not open file %1\nError was: %2" ).arg( filePath, f.errorString() ),
QMessageBox::Cancel );
return;
}
@ -316,53 +320,26 @@ void QgsValueMapConfigDlg::loadFromCSVButtonPushed()
QTextStream s( &f );
s.setAutoDetectUnicode( true );
const thread_local QRegularExpression re0( "^([^;]*?);(.*?)$" );
const thread_local QRegularExpression re1( "^([^,]*?),(.*?)$" );
const thread_local QRegularExpression re( "(?:^\"|[;,]\")(\"\"|[\\w\\W]*?)(?=\"[;,]|\"$)|(?:^(?!\")|[;,](?!\"))([^;,]*?)(?=$|[;,])|(\\r\\n|\\n)" );
QList<QPair<QString, QVariant>> map;
while ( !s.atEnd() )
{
const QString l = s.readLine().trimmed();
QString key;
QString val;
const QRegularExpressionMatch re0match = re0.match( l );
if ( re0match.hasMatch() )
QRegularExpressionMatchIterator matches = re.globalMatch( l );
QStringList ceils;
while ( matches.hasNext() && ceils.size() < 2 )
{
key = re0match.captured( 1 ).trimmed();
val = re0match.captured( 2 ).trimmed();
}
else
{
const QRegularExpressionMatch re1match = re1.match( l );
if ( re1match.hasMatch() )
{
key = re1match.captured( 1 ).trimmed();
val = re1match.captured( 2 ).trimmed();
}
else
{
continue;
}
const QRegularExpressionMatch match = matches.next();
ceils << match.capturedTexts().last().trimmed().replace( QLatin1String( "\"\"" ), QLatin1String( "\"" ) );
}
if ( ( key.startsWith( '\"' ) && key.endsWith( '\"' ) ) ||
( key.startsWith( '\'' ) && key.endsWith( '\'' ) ) )
{
key = key.mid( 1, key.length() - 2 );
}
if ( ( val.startsWith( '\"' ) && val.endsWith( '\"' ) ) ||
( val.startsWith( '\'' ) && val.endsWith( '\'' ) ) )
{
val = val.mid( 1, val.length() - 2 );
}
if ( ceils.size() != 2 )
continue;
QString key = ceils[0];
QString val = ceils[1];
if ( key == QgsApplication::nullRepresentation() )
key = QgsValueMapFieldFormatter::NULL_VALUE;
map.append( qMakePair( key, val ) );
}

View File

@ -58,6 +58,13 @@ class GUI_EXPORT QgsValueMapConfigDlg : public QgsEditorConfigWidget, private Ui
*/
void updateMap( const QList<QPair<QString, QVariant>> &list, bool insertNull );
/**
* Updates the displayed table with the values from a CSV file.
* \param filePath the absolute file path of the CSV file.
* \since QGIS 3.24
*/
void loadMapFromCSV( const QString &filePath );
/**
* Populates a \a comboBox with the appropriate entries based on a value map \a configuration.
*

View File

@ -58,6 +58,7 @@ set(TESTS
testqgslayoutgui.cpp
testqgslayoutview.cpp
testqgsvaluemapwidgetwrapper.cpp
testqgsvaluemapconfigdlg.cpp
testqgsvaluerelationwidgetwrapper.cpp
testqgsrelationeditorwidget.cpp
testqgsrelationreferencewidget.cpp

View File

@ -0,0 +1,90 @@
/***************************************************************************
testqgsvaluemapconfigdlg.cpp
--------------------------------------
Date : 14 02 2021
Copyright : (C) 2019 Stephen Knox
Email : stephenknox73 at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgstest.h"
#include "editorwidgets/qgsvaluemapconfigdlg.h"
#include "qgsgui.h"
#include "qgseditorwidgetregistry.h"
#include "qgsapplication.h"
#include "qgsproject.h"
#include "qgsvectorlayer.h"
class TestQgsValueMapConfigDlg : public QObject
{
Q_OBJECT
public:
TestQgsValueMapConfigDlg() = default;
private slots:
void initTestCase(); // will be called before the first testfunction is executed.
void cleanupTestCase(); // will be called after the last testfunction was executed.
void init(); // will be called before each testfunction is executed.
void cleanup(); // will be called after every testfunction.
void testLoadFromCSV();
};
void TestQgsValueMapConfigDlg::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();
QgsGui::editorWidgetRegistry()->initEditors();
}
void TestQgsValueMapConfigDlg::cleanupTestCase()
{
QgsApplication::exitQgis();
}
void TestQgsValueMapConfigDlg::init()
{
}
void TestQgsValueMapConfigDlg::cleanup()
{
}
void TestQgsValueMapConfigDlg::testLoadFromCSV()
{
const QString dataDir( TEST_DATA_DIR );
QgsVectorLayer vl( QStringLiteral( "LineString?crs=epsg:3111&field=pk:int&field=name:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
QList<QVariant> valueList;
QVariantMap value;
value.insert( QStringLiteral( "Basic unquoted record" ), QString( "1" ) );
valueList << value;
value.clear();
value.insert( QStringLiteral( "Forest type" ), QString( "2" ) );
valueList << value;
value.clear();
value.insert( QStringLiteral( "So-called \"data\"" ), QString( "three" ) );
valueList << value;
value.clear();
value.insert( QStringLiteral( "444" ), QString( "4" ) );
valueList << value;
value.clear();
value.insert( QStringLiteral( "five" ), QString( "5" ) );
valueList << value;
QgsValueMapConfigDlg *valueMapConfig = static_cast<QgsValueMapConfigDlg *>( QgsGui::editorWidgetRegistry()->createConfigWidget( QStringLiteral( "ValueMap" ), &vl, 1, nullptr ) );
valueMapConfig->loadMapFromCSV( dataDir + QStringLiteral( "/valuemapsample.csv" ) );
QCOMPARE( valueMapConfig->config().value( QStringLiteral( "map" ) ).toList(), valueList );
delete valueMapConfig;
}
QGSTEST_MAIN( TestQgsValueMapConfigDlg )
#include "testqgsvaluemapconfigdlg.moc"

5
tests/testdata/valuemapsample.csv vendored Normal file
View File

@ -0,0 +1,5 @@
1,Basic unquoted record,Some description
2,Forest type,"Quoted data"
three,"So-called ""data""",Unquoted remark
4,"444",No comment
5,five
Can't render this file because it has a wrong number of fields in line 5.