Skip to content

Commit 365fbed

Browse files
authoredJun 14, 2018
Merge pull request #7231 from elpaso/bugfix-18282-non-ascii-tags
[bugfix] Style Manager - non ascii tags in symbols
2 parents 22ce708 + b3c31d3 commit 365fbed

File tree

4 files changed

+145
-19
lines changed

4 files changed

+145
-19
lines changed
 

‎src/core/symbology/qgsstyle.cpp

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -870,29 +870,21 @@ bool QgsStyle::tagSymbol( StyleEntity type, const QString &symbol, const QString
870870
if ( !tag.isEmpty() )
871871
{
872872
// sql: gets the id of the tag if present or insert the tag and get the id of the tag
873-
auto query = QgsSqlite3Mprintf( "SELECT id FROM tag WHERE LOWER(name)='%q'", tag.toUtf8().toLower().constData() );
874-
875-
sqlite3_statement_unique_ptr statement;
876-
int nErr; statement = mCurrentDB.prepare( query, nErr );
877-
878-
int tagid;
879-
if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
880-
{
881-
tagid = sqlite3_column_int( statement.get(), 0 );
882-
}
883-
else
873+
int tagid( tagId( tag ) );
874+
if ( ! tagid )
884875
{
885876
tagid = addTag( tag );
886877
}
887878

888879
// Now map the tag to the symbol if it's not already tagged
889880
if ( !symbolHasTag( type, symbol, tag ) )
890881
{
891-
query = type == SymbolEntity
892-
? QgsSqlite3Mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid )
893-
: QgsSqlite3Mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid );
882+
auto query = type == SymbolEntity
883+
? QgsSqlite3Mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid )
884+
: QgsSqlite3Mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid );
894885

895886
char *zErr = nullptr;
887+
int nErr;
896888
nErr = sqlite3_exec( mCurrentDB.get(), query.toUtf8().constData(), nullptr, nullptr, &zErr );
897889
if ( nErr )
898890
{
@@ -963,7 +955,7 @@ bool QgsStyle::detagSymbol( StyleEntity type, const QString &symbol )
963955
{
964956
if ( !mCurrentDB )
965957
{
966-
QgsDebugMsg( "Sorry! Cannot open database for detgging." );
958+
QgsDebugMsg( "Sorry! Cannot open database for detagging." );
967959
return false;
968960
}
969961

@@ -1085,7 +1077,8 @@ QString QgsStyle::tag( int id ) const
10851077

10861078
int QgsStyle::getId( const QString &table, const QString &name )
10871079
{
1088-
auto query = QgsSqlite3Mprintf( "SELECT id FROM %q WHERE LOWER(name)='%q'", table.toUtf8().constData(), name.toUtf8().toLower().constData() );
1080+
QString lowerName( name.toLower() );
1081+
auto query = QgsSqlite3Mprintf( "SELECT id FROM %q WHERE LOWER(name)='%q'", table.toUtf8().constData(), lowerName.toUtf8().constData() );
10891082

10901083
sqlite3_statement_unique_ptr statement;
10911084
int nErr; statement = mCurrentDB.prepare( query, nErr );
@@ -1095,6 +1088,18 @@ int QgsStyle::getId( const QString &table, const QString &name )
10951088
{
10961089
id = sqlite3_column_int( statement.get(), 0 );
10971090
}
1091+
else
1092+
{
1093+
// Try the name without lowercase conversion
1094+
auto query = QgsSqlite3Mprintf( "SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(), name.toUtf8().constData() );
1095+
1096+
sqlite3_statement_unique_ptr statement;
1097+
int nErr; statement = mCurrentDB.prepare( query, nErr );
1098+
if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1099+
{
1100+
id = sqlite3_column_int( statement.get(), 0 );
1101+
}
1102+
}
10981103

10991104
return id;
11001105
}

‎tests/src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ SET(TESTS
192192
testqgsmeshlayer.cpp
193193
testqgsmeshlayerrenderer.cpp
194194
testqgslayerdefinition.cpp
195+
testqgssqliteutils.cpp
195196
)
196197

197198
IF(WITH_QTWEBKIT)

‎tests/src/core/testqgssqliteutils.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/***************************************************************************
2+
testqgssqliteutils.cpp
3+
--------------------------------------
4+
Date : 2018-06-13
5+
Copyright : (C) 2018 Alessandro Pasotti
6+
Email : elpaso at itopen dot it
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#include "qgstest.h"
16+
#include <QObject>
17+
#include <QStringList>
18+
#include <QApplication>
19+
#include <QFileInfo>
20+
21+
//qgis includes...
22+
#include "qgssqliteutils.h"
23+
24+
25+
/**
26+
* \ingroup UnitTests
27+
* This is a unit test to verify that QgsSqliteUtils are working correctly
28+
*/
29+
class TestQgsSqliteUtils : public QObject
30+
{
31+
Q_OBJECT
32+
33+
public:
34+
35+
TestQgsSqliteUtils() = default;
36+
37+
38+
private slots:
39+
40+
// init / cleanup
41+
void initTestCase();// will be called before the first testfunction is executed.
42+
void cleanupTestCase();// will be called after the last testfunction was executed.
43+
void init() {}// will be called before each testfunction is executed.
44+
void cleanup() {}// will be called after every testfunction.
45+
// void initStyles();
46+
47+
void testPrintfAscii();
48+
void testPrintfUtf8();
49+
};
50+
51+
52+
// slots
53+
void TestQgsSqliteUtils::initTestCase()
54+
{
55+
// initialize with test settings directory so we don't mess with user's stuff
56+
QgsApplication::init( QDir::tempPath() + "/dot-qgis" );
57+
QgsApplication::initQgis();
58+
QgsApplication::createDatabase();
59+
60+
// output test environment
61+
QgsApplication::showSettings();
62+
63+
// Set up the QgsSettings environment
64+
QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
65+
QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
66+
QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) );
67+
68+
69+
}
70+
71+
void TestQgsSqliteUtils::cleanupTestCase()
72+
{
73+
QgsApplication::exitQgis();
74+
}
75+
76+
void TestQgsSqliteUtils::testPrintfAscii()
77+
{
78+
QString tag( "Meteor" );
79+
QString query( QgsSqlite3Mprintf( "SELECT id FROM tag WHERE LOWER(name)='%q'", tag.toUtf8().toLower().constData() ) );
80+
QCOMPARE( query, QString( "SELECT id FROM tag WHERE LOWER(name)='%1'" ).arg( tag.toLower() ) );
81+
}
82+
83+
84+
void TestQgsSqliteUtils::testPrintfUtf8()
85+
{
86+
QString tag( "МЕТЕОР" );
87+
QCOMPARE( tag.toLower(), QString( "метеор" ) );
88+
QString lowerTag( tag.toLower() );
89+
QString query( QgsSqlite3Mprintf( "SELECT id FROM tag WHERE LOWER(name)='%q'", lowerTag.toUtf8().constData() ) );
90+
QCOMPARE( query, QString( "SELECT id FROM tag WHERE LOWER(name)='%1'" ).arg( lowerTag ) );
91+
}
92+
93+
94+
QGSTEST_MAIN( TestQgsSqliteUtils )
95+
#include "testqgssqliteutils.moc"

‎tests/src/core/testqgsstyle.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,28 +291,35 @@ void TestStyle::testTags()
291291
QCOMPARE( id, mStyle->tagId( "purple" ) );
292292
QCOMPARE( QStringLiteral( "purple" ), mStyle->tag( id ) );
293293

294+
// Cyrillic
295+
id = mStyle->addTag( QStringLiteral( "МЕТЕОР" ) );
296+
QCOMPARE( id, mStyle->tagId( "МЕТЕОР" ) );
297+
294298
QStringList tags = mStyle->tags();
295-
QCOMPARE( tags.count(), 5 );
299+
QCOMPARE( tags.count(), 6 );
296300
QVERIFY( tags.contains( "red" ) );
297301
QVERIFY( tags.contains( "starry" ) );
298302
QVERIFY( tags.contains( "circle" ) );
299303
QVERIFY( tags.contains( "blue" ) );
300304
QVERIFY( tags.contains( "purple" ) );
305+
QVERIFY( tags.contains( "МЕТЕОР" ) );
301306

302307
//remove tag
303308
mStyle->remove( QgsStyle::TagEntity, mStyle->tagId( QStringLiteral( "purple" ) ) );
304309
mStyle->remove( QgsStyle::TagEntity, -999 ); //bad id
305310
tags = mStyle->tags();
306-
QCOMPARE( tags.count(), 4 );
311+
QCOMPARE( tags.count(), 5 );
307312
QVERIFY( !tags.contains( "purple" ) );
308313

309314
//add some symbols
310315
std::unique_ptr< QgsMarkerSymbol> sym1( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
311316
std::unique_ptr< QgsMarkerSymbol> sym2( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
312317
std::unique_ptr< QgsMarkerSymbol> sym3( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
318+
std::unique_ptr< QgsMarkerSymbol> sym4( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
313319
QVERIFY( mStyle->saveSymbol( "symbol1", sym1.get(), false, QStringList() << "red" << "starry" ) );
314320
mStyle->addSymbol( QStringLiteral( "blue starry" ), sym2.release(), true );
315321
mStyle->addSymbol( QStringLiteral( "red circle" ), sym3.release(), true );
322+
mStyle->addSymbol( QStringLiteral( "МЕТЕОР" ), sym4.release(), true );
316323

317324
//tag them
318325
QVERIFY( mStyle->tagSymbol( QgsStyle::SymbolEntity, "blue starry", QStringList() << "blue" << "starry" ) );
@@ -324,6 +331,13 @@ void TestStyle::testTags()
324331
tags = mStyle->tags();
325332
QVERIFY( tags.contains( "round" ) );
326333

334+
// Cyrillic
335+
// Add twice (see issue #18281)
336+
QVERIFY( mStyle->tagSymbol( QgsStyle::SymbolEntity, "МЕТЕОР", QStringList() << "МЕТЕОР" ) );
337+
tags = mStyle->tags();
338+
QVERIFY( tags.contains( "МЕТЕОР" ) );
339+
QCOMPARE( tags.filter( "МЕТЕОР" ).count(), 1 );
340+
327341
//check that tags have been applied
328342
tags = mStyle->tagsOfSymbol( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ) );
329343
QCOMPARE( tags.count(), 2 );
@@ -339,8 +353,13 @@ void TestStyle::testTags()
339353
QVERIFY( tags.contains( "red" ) );
340354
QVERIFY( tags.contains( "starry" ) );
341355

356+
tags = mStyle->tagsOfSymbol( QgsStyle::SymbolEntity, QStringLiteral( "МЕТЕОР" ) );
357+
QCOMPARE( tags.count(), 1 );
358+
QVERIFY( tags.contains( "МЕТЕОР" ) );
359+
342360
//check that a given tag is attached to a symbol
343361
QVERIFY( mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ), QStringLiteral( "blue" ) ) );
362+
QVERIFY( mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "МЕТЕОР" ), QStringLiteral( "МЕТЕОР" ) ) );
344363

345364
//check that a given tag is not attached to a symbol
346365
QCOMPARE( false, mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ), QStringLiteral( "notblue" ) ) );
@@ -368,7 +387,9 @@ void TestStyle::testTags()
368387
QVERIFY( symbols.contains( "red circle" ) );
369388
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "round" ) ) );
370389
QCOMPARE( symbols.count(), 1 );
371-
QVERIFY( symbols.contains( "red circle" ) );
390+
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "МЕТЕОР" ) ) );
391+
QCOMPARE( symbols.count(), 1 );
392+
QVERIFY( symbols.contains( "МЕТЕОР" ) );
372393
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "blue" ) ) );
373394
QVERIFY( symbols.isEmpty() );
374395
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "no tag" ) ) );
@@ -392,6 +413,10 @@ void TestStyle::testTags()
392413
symbols = mStyle->findSymbols( QgsStyle::SymbolEntity, QStringLiteral( "round" ) );
393414
QCOMPARE( symbols.count(), 1 );
394415
QVERIFY( symbols.contains( "red circle" ) );
416+
symbols = mStyle->findSymbols( QgsStyle::SymbolEntity, QStringLiteral( "МЕТЕОР" ) );
417+
QCOMPARE( symbols.count(), 1 );
418+
QVERIFY( symbols.contains( "МЕТЕОР" ) );
419+
395420
}
396421

397422
QGSTEST_MAIN( TestStyle )

0 commit comments

Comments
 (0)
Please sign in to comment.