Skip to content

Commit f5d68ff

Browse files
committedMay 12, 2020
Adapt QgsPalLabeling.splitToLines to account for HTML formatting
1 parent 87296f2 commit f5d68ff

File tree

5 files changed

+51
-23
lines changed

5 files changed

+51
-23
lines changed
 

‎python/core/auto_generated/labeling/qgspallabeling.sip.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ Checks whether a geometry requires preparation before registration with PAL
783783
.. versionadded:: 2.9
784784
%End
785785

786-
static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true );
786+
static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true, bool allowHtmlFormatting = false );
787787
%Docstring
788788
Splits a ``text`` string to a list of separate lines, using a specified wrap character (``wrapCharacter``).
789789
The text string will be split on either newline characters or the wrap character.

‎src/core/labeling/qgspallabeling.cpp

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,8 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt
13931393
}
13941394
QgsRenderContext *rc = context ? context : scopedRc.get();
13951395

1396+
const bool htmlFormatting = mFormat.allowHtmlFormatting();
1397+
13961398
QString wrapchr = wrapChar;
13971399
int evalAutoWrapLength = autoWrapLength;
13981400
double multilineH = mFormat.lineHeight();
@@ -1531,7 +1533,7 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt
15311533

15321534
double w = 0.0, h = 0.0, rw = 0.0, rh = 0.0;
15331535
double labelHeight = fm->ascent() + fm->descent(); // ignore +1 for baseline
1534-
const QStringList multiLineSplit = QgsPalLabeling::splitToLines( textCopy, wrapchr, evalAutoWrapLength, useMaxLineLengthForAutoWrap );
1536+
const QStringList multiLineSplit = QgsPalLabeling::splitToLines( textCopy, wrapchr, evalAutoWrapLength, useMaxLineLengthForAutoWrap, htmlFormatting );
15351537
int lines = multiLineSplit.size();
15361538

15371539
switch ( orientation )
@@ -3548,33 +3550,49 @@ bool QgsPalLabeling::geometryRequiresPreparation( const QgsGeometry &geometry, Q
35483550
return false;
35493551
}
35503552

3551-
QStringList QgsPalLabeling::splitToLines( const QString &text, const QString &wrapCharacter, const int autoWrapLength, const bool useMaxLineLengthWhenAutoWrapping )
3553+
QStringList QgsPalLabeling::splitToLines( const QString &text, const QString &wrapCharacter, const int autoWrapLength, const bool useMaxLineLengthWhenAutoWrapping, const bool allowHtmlFormatting )
35523554
{
35533555
QStringList multiLineSplit;
3554-
if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String( "\n" ) )
3556+
auto splitLine = [ & ]( const QString & input )
35553557
{
3556-
//wrap on both the wrapchr and new line characters
3557-
const QStringList lines = text.split( wrapCharacter );
3558-
for ( const QString &line : lines )
3558+
QStringList thisParts;
3559+
if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String( "\n" ) )
35593560
{
3560-
multiLineSplit.append( line.split( '\n' ) );
3561+
//wrap on both the wrapchr and new line characters
3562+
const QStringList lines = input.split( wrapCharacter );
3563+
for ( const QString &line : lines )
3564+
{
3565+
thisParts.append( line.split( '\n' ) );
3566+
}
3567+
}
3568+
else
3569+
{
3570+
thisParts = input.split( '\n' );
35613571
}
3562-
}
3563-
else
3564-
{
3565-
multiLineSplit = text.split( '\n' );
3566-
}
35673572

3568-
// apply auto wrapping to each manually created line
3569-
if ( autoWrapLength != 0 )
3570-
{
3571-
QStringList autoWrappedLines;
3572-
autoWrappedLines.reserve( multiLineSplit.count() );
3573-
for ( const QString &line : qgis::as_const( multiLineSplit ) )
3573+
// apply auto wrapping to each manually created line
3574+
if ( autoWrapLength != 0 )
35743575
{
3575-
autoWrappedLines.append( QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split( '\n' ) );
3576+
QStringList autoWrappedLines;
3577+
autoWrappedLines.reserve( thisParts.count() );
3578+
for ( const QString &line : qgis::as_const( thisParts ) )
3579+
{
3580+
autoWrappedLines.append( QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split( '\n' ) );
3581+
}
3582+
thisParts = autoWrappedLines;
35763583
}
3577-
multiLineSplit = autoWrappedLines;
3584+
multiLineSplit.append( thisParts );
3585+
};
3586+
3587+
if ( allowHtmlFormatting )
3588+
{
3589+
const QStringList htmlBlocks = QgsTextRenderer::extractTextBlocksFromHtml( text );
3590+
for ( const QString &block : htmlBlocks )
3591+
splitLine( block );
3592+
}
3593+
else
3594+
{
3595+
splitLine( text );
35783596
}
35793597
return multiLineSplit;
35803598
}

‎src/core/labeling/qgspallabeling.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,7 @@ class CORE_EXPORT QgsPalLabeling
13011301
*
13021302
* \since QGIS 2.9
13031303
*/
1304-
static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true );
1304+
static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true, bool allowHtmlFormatting = false );
13051305

13061306
/**
13071307
* Splits a text string to a list of graphemes, which are the smallest allowable character

‎src/core/labeling/qgsvectorlayerlabelprovider.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition *label, Q
611611
}
612612

613613
//QgsDebugMsgLevel( "drawLabel " + txt, 4 );
614-
QStringList multiLineList = QgsPalLabeling::splitToLines( txt, tmpLyr.wrapChar, tmpLyr.autoWrapLength, tmpLyr.useMaxLineLengthForAutoWrap );
614+
QStringList multiLineList = QgsPalLabeling::splitToLines( txt, tmpLyr.wrapChar, tmpLyr.autoWrapLength, tmpLyr.useMaxLineLengthForAutoWrap, tmpLyr.format().allowHtmlFormatting() );
615615

616616
QgsTextRenderer::HAlignment hAlign = QgsTextRenderer::AlignLeft;
617617
if ( tmpLyr.multilineAlign == QgsPalLayerSettings::MultiCenter )

‎tests/src/python/test_qgspallabeling_base.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,16 @@ def checkTest(self, **kwargs):
356356
"""Intended to be overridden in subclasses"""
357357
pass
358358

359+
def testSplitToLines(self):
360+
self.assertEqual(QgsPalLabeling.splitToLines('', ''), [''])
361+
self.assertEqual(QgsPalLabeling.splitToLines('abc def', ''), ['abc def'])
362+
self.assertEqual(QgsPalLabeling.splitToLines('abc def', ' '), ['abc', 'def'])
363+
self.assertEqual(QgsPalLabeling.splitToLines('abc\ndef', ' '), ['abc', 'def'])
364+
self.assertEqual(QgsPalLabeling.splitToLines('abc def', ' ', allowHtmlFormatting=True), ['abc', 'def'])
365+
self.assertEqual(QgsPalLabeling.splitToLines('<span style="color: red">R_ED</span> not <div>red</div>', ' ', allowHtmlFormatting=True), ['R_ED', 'not', '', 'red'])
366+
self.assertEqual(QgsPalLabeling.splitToLines('<span style="color: red">R_ED</span> not <div>red</div>', '_',
367+
allowHtmlFormatting=True), ['R', 'ED not ', 'red'])
368+
359369

360370
class TestPALConfig(TestQgsPalLabeling):
361371

0 commit comments

Comments
 (0)
Please sign in to comment.