Skip to content

Commit

Permalink
[gui] Fix value map editor widget configuration's load from CSV parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn authored and nyalldawson committed Feb 14, 2022
1 parent 4e035e6 commit 4131eb2
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 39 deletions.
55 changes: 16 additions & 39 deletions src/gui/editorwidgets/qgsvaluemapconfigdlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,68 +301,45 @@ 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;
}

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() )
{
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;
}
}

if ( ( key.startsWith( '\"' ) && key.endsWith( '\"' ) ) ||
( key.startsWith( '\'' ) && key.endsWith( '\'' ) ) )
QRegularExpressionMatchIterator matches = re.globalMatch( l );
QStringList ceils;
while ( matches.hasNext() && ceils.size() < 2 )
{
key = key.mid( 1, key.length() - 2 );
const QRegularExpressionMatch match = matches.next();
ceils << match.capturedTexts().last().trimmed().replace( QLatin1String( "\"\"" ), QLatin1String( "\"" ) );
}

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 ) );
}

Expand Down
7 changes: 7 additions & 0 deletions src/gui/editorwidgets/qgsvaluemapconfigdlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
1 change: 1 addition & 0 deletions tests/src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ set(TESTS
testqgslayoutgui.cpp
testqgslayoutview.cpp
testqgsvaluemapwidgetwrapper.cpp
testqgsvaluemapconfigdlg.cpp
testqgsvaluerelationwidgetwrapper.cpp
testqgsrelationeditorwidget.cpp
testqgsrelationreferencewidget.cpp
Expand Down
90 changes: 90 additions & 0 deletions tests/src/gui/testqgsvaluemapconfigdlg.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions tests/testdata/valuemapsample.csv
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 4131eb2

Please sign in to comment.