Skip to content

Commit

Permalink
[bugfix] Fix symbol tags with cyrillic names
Browse files Browse the repository at this point in the history
... and other non-ascii as well

Fixes #18282 - Style Manager - Impossible to work with non-Latin characters (tag or symbol names)
  • Loading branch information
elpaso committed Jun 13, 2018
1 parent 3f938e4 commit b3c31d3
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 19 deletions.
37 changes: 21 additions & 16 deletions src/core/symbology/qgsstyle.cpp
Expand Up @@ -870,29 +870,21 @@ bool QgsStyle::tagSymbol( StyleEntity type, const QString &symbol, const QString
if ( !tag.isEmpty() )
{
// sql: gets the id of the tag if present or insert the tag and get the id of the tag
auto query = QgsSqlite3Mprintf( "SELECT id FROM tag WHERE LOWER(name)='%q'", tag.toUtf8().toLower().constData() );

sqlite3_statement_unique_ptr statement;
int nErr; statement = mCurrentDB.prepare( query, nErr );

int tagid;
if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
{
tagid = sqlite3_column_int( statement.get(), 0 );
}
else
int tagid( tagId( tag ) );
if ( ! tagid )
{
tagid = addTag( tag );
}

// Now map the tag to the symbol if it's not already tagged
if ( !symbolHasTag( type, symbol, tag ) )
{
query = type == SymbolEntity
? QgsSqlite3Mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid )
: QgsSqlite3Mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid );
auto query = type == SymbolEntity
? QgsSqlite3Mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid )
: QgsSqlite3Mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid );

char *zErr = nullptr;
int nErr;
nErr = sqlite3_exec( mCurrentDB.get(), query.toUtf8().constData(), nullptr, nullptr, &zErr );
if ( nErr )
{
Expand Down Expand Up @@ -963,7 +955,7 @@ bool QgsStyle::detagSymbol( StyleEntity type, const QString &symbol )
{
if ( !mCurrentDB )
{
QgsDebugMsg( "Sorry! Cannot open database for detgging." );
QgsDebugMsg( "Sorry! Cannot open database for detagging." );
return false;
}

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

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

sqlite3_statement_unique_ptr statement;
int nErr; statement = mCurrentDB.prepare( query, nErr );
Expand All @@ -1095,6 +1088,18 @@ int QgsStyle::getId( const QString &table, const QString &name )
{
id = sqlite3_column_int( statement.get(), 0 );
}
else
{
// Try the name without lowercase conversion
auto query = QgsSqlite3Mprintf( "SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(), name.toUtf8().constData() );

sqlite3_statement_unique_ptr statement;
int nErr; statement = mCurrentDB.prepare( query, nErr );
if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
{
id = sqlite3_column_int( statement.get(), 0 );
}
}

return id;
}
Expand Down
31 changes: 28 additions & 3 deletions tests/src/core/testqgsstyle.cpp
Expand Up @@ -291,28 +291,35 @@ void TestStyle::testTags()
QCOMPARE( id, mStyle->tagId( "purple" ) );
QCOMPARE( QStringLiteral( "purple" ), mStyle->tag( id ) );

// Cyrillic
id = mStyle->addTag( QStringLiteral( "МЕТЕОР" ) );
QCOMPARE( id, mStyle->tagId( "МЕТЕОР" ) );

QStringList tags = mStyle->tags();
QCOMPARE( tags.count(), 5 );
QCOMPARE( tags.count(), 6 );
QVERIFY( tags.contains( "red" ) );
QVERIFY( tags.contains( "starry" ) );
QVERIFY( tags.contains( "circle" ) );
QVERIFY( tags.contains( "blue" ) );
QVERIFY( tags.contains( "purple" ) );
QVERIFY( tags.contains( "МЕТЕОР" ) );

//remove tag
mStyle->remove( QgsStyle::TagEntity, mStyle->tagId( QStringLiteral( "purple" ) ) );
mStyle->remove( QgsStyle::TagEntity, -999 ); //bad id
tags = mStyle->tags();
QCOMPARE( tags.count(), 4 );
QCOMPARE( tags.count(), 5 );
QVERIFY( !tags.contains( "purple" ) );

//add some symbols
std::unique_ptr< QgsMarkerSymbol> sym1( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
std::unique_ptr< QgsMarkerSymbol> sym2( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
std::unique_ptr< QgsMarkerSymbol> sym3( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
std::unique_ptr< QgsMarkerSymbol> sym4( QgsMarkerSymbol::createSimple( QgsStringMap() ) );
QVERIFY( mStyle->saveSymbol( "symbol1", sym1.get(), false, QStringList() << "red" << "starry" ) );
mStyle->addSymbol( QStringLiteral( "blue starry" ), sym2.release(), true );
mStyle->addSymbol( QStringLiteral( "red circle" ), sym3.release(), true );
mStyle->addSymbol( QStringLiteral( "МЕТЕОР" ), sym4.release(), true );

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

// Cyrillic
// Add twice (see issue #18281)
QVERIFY( mStyle->tagSymbol( QgsStyle::SymbolEntity, "МЕТЕОР", QStringList() << "МЕТЕОР" ) );
tags = mStyle->tags();
QVERIFY( tags.contains( "МЕТЕОР" ) );
QCOMPARE( tags.filter( "МЕТЕОР" ).count(), 1 );

//check that tags have been applied
tags = mStyle->tagsOfSymbol( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ) );
QCOMPARE( tags.count(), 2 );
Expand All @@ -339,8 +353,13 @@ void TestStyle::testTags()
QVERIFY( tags.contains( "red" ) );
QVERIFY( tags.contains( "starry" ) );

tags = mStyle->tagsOfSymbol( QgsStyle::SymbolEntity, QStringLiteral( "МЕТЕОР" ) );
QCOMPARE( tags.count(), 1 );
QVERIFY( tags.contains( "МЕТЕОР" ) );

//check that a given tag is attached to a symbol
QVERIFY( mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ), QStringLiteral( "blue" ) ) );
QVERIFY( mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "МЕТЕОР" ), QStringLiteral( "МЕТЕОР" ) ) );

//check that a given tag is not attached to a symbol
QCOMPARE( false, mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ), QStringLiteral( "notblue" ) ) );
Expand Down Expand Up @@ -368,7 +387,9 @@ void TestStyle::testTags()
QVERIFY( symbols.contains( "red circle" ) );
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "round" ) ) );
QCOMPARE( symbols.count(), 1 );
QVERIFY( symbols.contains( "red circle" ) );
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "МЕТЕОР" ) ) );
QCOMPARE( symbols.count(), 1 );
QVERIFY( symbols.contains( "МЕТЕОР" ) );
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "blue" ) ) );
QVERIFY( symbols.isEmpty() );
symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( QStringLiteral( "no tag" ) ) );
Expand All @@ -392,6 +413,10 @@ void TestStyle::testTags()
symbols = mStyle->findSymbols( QgsStyle::SymbolEntity, QStringLiteral( "round" ) );
QCOMPARE( symbols.count(), 1 );
QVERIFY( symbols.contains( "red circle" ) );
symbols = mStyle->findSymbols( QgsStyle::SymbolEntity, QStringLiteral( "МЕТЕОР" ) );
QCOMPARE( symbols.count(), 1 );
QVERIFY( symbols.contains( "МЕТЕОР" ) );

}

QGSTEST_MAIN( TestStyle )
Expand Down

0 comments on commit b3c31d3

Please sign in to comment.