Skip to content
Permalink
Browse files

Adapt QgsPalLabeling.splitToLines to account for HTML formatting

  • Loading branch information
nyalldawson committed May 8, 2020
1 parent 87296f2 commit f5d68ff4233b0793b7bc6fd21f1d2f45ff85652c
@@ -783,7 +783,7 @@ Checks whether a geometry requires preparation before registration with PAL
.. versionadded:: 2.9
%End

static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true );
static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true, bool allowHtmlFormatting = false );
%Docstring
Splits a ``text`` string to a list of separate lines, using a specified wrap character (``wrapCharacter``).
The text string will be split on either newline characters or the wrap character.
@@ -1393,6 +1393,8 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt
}
QgsRenderContext *rc = context ? context : scopedRc.get();

const bool htmlFormatting = mFormat.allowHtmlFormatting();

QString wrapchr = wrapChar;
int evalAutoWrapLength = autoWrapLength;
double multilineH = mFormat.lineHeight();
@@ -1531,7 +1533,7 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt

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

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

QStringList QgsPalLabeling::splitToLines( const QString &text, const QString &wrapCharacter, const int autoWrapLength, const bool useMaxLineLengthWhenAutoWrapping )
QStringList QgsPalLabeling::splitToLines( const QString &text, const QString &wrapCharacter, const int autoWrapLength, const bool useMaxLineLengthWhenAutoWrapping, const bool allowHtmlFormatting )
{
QStringList multiLineSplit;
if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String( "\n" ) )
auto splitLine = [ & ]( const QString & input )
{
//wrap on both the wrapchr and new line characters
const QStringList lines = text.split( wrapCharacter );
for ( const QString &line : lines )
QStringList thisParts;
if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String( "\n" ) )
{
multiLineSplit.append( line.split( '\n' ) );
//wrap on both the wrapchr and new line characters
const QStringList lines = input.split( wrapCharacter );
for ( const QString &line : lines )
{
thisParts.append( line.split( '\n' ) );
}
}
else
{
thisParts = input.split( '\n' );
}
}
else
{
multiLineSplit = text.split( '\n' );
}

// apply auto wrapping to each manually created line
if ( autoWrapLength != 0 )
{
QStringList autoWrappedLines;
autoWrappedLines.reserve( multiLineSplit.count() );
for ( const QString &line : qgis::as_const( multiLineSplit ) )
// apply auto wrapping to each manually created line
if ( autoWrapLength != 0 )
{
autoWrappedLines.append( QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split( '\n' ) );
QStringList autoWrappedLines;
autoWrappedLines.reserve( thisParts.count() );
for ( const QString &line : qgis::as_const( thisParts ) )
{
autoWrappedLines.append( QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split( '\n' ) );
}
thisParts = autoWrappedLines;
}
multiLineSplit = autoWrappedLines;
multiLineSplit.append( thisParts );
};

if ( allowHtmlFormatting )
{
const QStringList htmlBlocks = QgsTextRenderer::extractTextBlocksFromHtml( text );
for ( const QString &block : htmlBlocks )
splitLine( block );
}
else
{
splitLine( text );
}
return multiLineSplit;
}
@@ -1301,7 +1301,7 @@ class CORE_EXPORT QgsPalLabeling
*
* \since QGIS 2.9
*/
static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true );
static QStringList splitToLines( const QString &text, const QString &wrapCharacter, int autoWrapLength = 0, bool useMaxLineLengthWhenAutoWrapping = true, bool allowHtmlFormatting = false );

/**
* Splits a text string to a list of graphemes, which are the smallest allowable character
@@ -611,7 +611,7 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition *label, Q
}

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

QgsTextRenderer::HAlignment hAlign = QgsTextRenderer::AlignLeft;
if ( tmpLyr.multilineAlign == QgsPalLayerSettings::MultiCenter )
@@ -356,6 +356,16 @@ def checkTest(self, **kwargs):
"""Intended to be overridden in subclasses"""
pass

def testSplitToLines(self):
self.assertEqual(QgsPalLabeling.splitToLines('', ''), [''])
self.assertEqual(QgsPalLabeling.splitToLines('abc def', ''), ['abc def'])
self.assertEqual(QgsPalLabeling.splitToLines('abc def', ' '), ['abc', 'def'])
self.assertEqual(QgsPalLabeling.splitToLines('abc\ndef', ' '), ['abc', 'def'])
self.assertEqual(QgsPalLabeling.splitToLines('abc def', ' ', allowHtmlFormatting=True), ['abc', 'def'])
self.assertEqual(QgsPalLabeling.splitToLines('<span style="color: red">R_ED</span> not <div>red</div>', ' ', allowHtmlFormatting=True), ['R_ED', 'not', '', 'red'])
self.assertEqual(QgsPalLabeling.splitToLines('<span style="color: red">R_ED</span> not <div>red</div>', '_',
allowHtmlFormatting=True), ['R', 'ED not ', 'red'])


class TestPALConfig(TestQgsPalLabeling):

0 comments on commit f5d68ff

Please sign in to comment.
You can’t perform that action at this time.