Skip to content

Commit

Permalink
[expression] make wordwrap work with complex scripts (Indic, Arabic, …
Browse files Browse the repository at this point in the history
…etc)
  • Loading branch information
nirvn committed Sep 30, 2016
1 parent a5b83e4 commit 8703920
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 13 deletions.
29 changes: 21 additions & 8 deletions src/core/qgsexpression.cpp
Expand Up @@ -1125,10 +1125,23 @@ static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionCont
if ( !str.isEmpty() && wrap != 0 )
{
QString newstr;
QString delimiterstr;
if ( values.length() == 3 ) delimiterstr = getStringValue( values.at( 2 ), parent );
if ( delimiterstr.isEmpty() ) delimiterstr = ' ';
int delimiterlength = delimiterstr.length();
QRegExp rx;
QString customdelimiter = getStringValue( values.at( 2 ), parent );
int delimiterlength;

if ( customdelimiter.length() > 0 )
{
rx.setPatternSyntax( QRegExp::FixedString );
rx.setPattern( customdelimiter );
delimiterlength = customdelimiter.length();
}
else
{
// \x200B is a ZERO-WIDTH SPACE, needed for worwrap to support a number of complex scripts (Indic, Arabic, etc.)
rx.setPattern( "[\\s\\x200B]" );
delimiterlength = 1;
}


QStringList lines = str.split( '\n' );
int strlength, strcurrent, strhit, lasthit;
Expand All @@ -1147,17 +1160,17 @@ static QVariant fcnWordwrap( const QVariantList& values, const QgsExpressionCont
if ( wrap > 0 )
{
//first try to locate delimiter backwards
strhit = lines[i].lastIndexOf( delimiterstr, strcurrent + wrap );
strhit = lines[i].lastIndexOf( rx, strcurrent + wrap );
if ( strhit == lasthit || strhit == -1 )
{
//if no new backward delimiter found, try to locate forward
strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
strhit = lines[i].indexOf( rx, strcurrent + qAbs( wrap ) );
}
lasthit = strhit;
}
else
{
strhit = lines[i].indexOf( delimiterstr, strcurrent + qAbs( wrap ) );
strhit = lines[i].indexOf( rx, strcurrent + qAbs( wrap ) );
}
if ( strhit > -1 )
{
Expand Down Expand Up @@ -3469,7 +3482,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
<< new StaticFunction( "hamming_distance", 2, fcnHamming, "Fuzzy Matching" )
<< new StaticFunction( "soundex", 1, fcnSoundex, "Fuzzy Matching" )
<< new StaticFunction( "char", 1, fcnChar, "String" )
<< new StaticFunction( "wordwrap", ParameterList() << Parameter( "text" ) << Parameter( "length" ) << Parameter( "delimiter", true, " " ), fcnWordwrap, "String" )
<< new StaticFunction( "wordwrap", ParameterList() << Parameter( "text" ) << Parameter( "length" ) << Parameter( "delimiter", true, "" ), fcnWordwrap, "String" )
<< new StaticFunction( "length", 1, fcnLength, "String" )
<< new StaticFunction( "replace", 3, fcnReplace, "String" )
<< new StaticFunction( "regexp_replace", 3, fcnRegexpReplace, "String" )
Expand Down
11 changes: 6 additions & 5 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -329,7 +329,7 @@ class TestQgsExpression: public QObject
QTest::newRow( "named params non optional omitted" ) << "clamp( min:=1, max:=2)" << true << "" << QVariant();
QTest::newRow( "optional parameters specified" ) << "wordwrap( 'testxstring', 5, 'x')" << false << "wordwrap('testxstring', 5, 'x')" << QVariant( "test\nstring" );
QTest::newRow( "optional parameters specified named" ) << "wordwrap( text:='testxstring', length:=5, delimiter:='x')" << false << "wordwrap('testxstring', 5, 'x')" << QVariant( "test\nstring" );
QTest::newRow( "optional parameters unspecified" ) << "wordwrap( text:='test string', length:=5 )" << false << "wordwrap('test string', 5, ' ')" << QVariant( "test\nstring" );
QTest::newRow( "optional parameters unspecified" ) << "wordwrap( text:='test string', length:=5 )" << false << "wordwrap('test string', 5, '')" << QVariant( "test\nstring" );
QTest::newRow( "named params dupe explicit 3" ) << "wordwrap( 'test string', 5, length:=6 )" << true << "" << QVariant();
QTest::newRow( "named params dupe explicit 4" ) << "wordwrap( text:='test string', length:=5, length:=6 )" << true << "" << QVariant();
}
Expand Down Expand Up @@ -837,10 +837,11 @@ class TestQgsExpression: public QObject
QTest::newRow( "trim empty string" ) << "trim('')" << false << QVariant( "" );
QTest::newRow( "char" ) << "char(81)" << false << QVariant( "Q" );
QTest::newRow( "wordwrap" ) << "wordwrap('university of qgis',13)" << false << QVariant( "university of\nqgis" );
QTest::newRow( "wordwrap" ) << "wordwrap('university of qgis',13,' ')" << false << QVariant( "university of\nqgis" );
QTest::newRow( "wordwrap" ) << "wordwrap('university of qgis',-3)" << false << QVariant( "university\nof qgis" );
QTest::newRow( "wordwrap" ) << "wordwrap('university of qgis',-3,' ')" << false << QVariant( "university\nof qgis" );
QTest::newRow( "wordwrap" ) << "wordwrap('university of qgis\nsupports many multiline',-5,' ')" << false << QVariant( "university\nof qgis\nsupports\nmany multiline" );
QTest::newRow( "wordwrap with custom delimiter" ) << "wordwrap('university of qgis',13,' ')" << false << QVariant( "university of\nqgis" );
QTest::newRow( "wordwrap with negative length" ) << "wordwrap('university of qgis',-3)" << false << QVariant( "university\nof qgis" );
QTest::newRow( "wordwrap with negative length, custom delimiter" ) << "wordwrap('university of qgis',-3,' ')" << false << QVariant( "university\nof qgis" );
QTest::newRow( "wordwrap on multi line" ) << "wordwrap('university of qgis\nsupports many multiline',-5,' ')" << false << QVariant( "university\nof qgis\nsupports\nmany multiline" );
QTest::newRow( "wordwrap on zero-space width" ) << "wordwrap('test\u200Bzero-width space',4)" << false << QVariant( "test\nzero-width\nspace" );
QTest::newRow( "format" ) << "format('%1 %2 %3 %1', 'One', 'Two', 'Three')" << false << QVariant( "One Two Three One" );
QTest::newRow( "concat" ) << "concat('a', 'b', 'c', 'd')" << false << QVariant( "abcd" );
QTest::newRow( "concat function single" ) << "concat('a')" << false << QVariant( "a" );
Expand Down

0 comments on commit 8703920

Please sign in to comment.