Write out the HTML correctly for nested lists

When we are having nested lists then we need to ensure that the HTML is
outputted correctly so that the closing list and item tags are placed
in the right order.

[ChangeLog][QtGui][QTextDocument] The output of toHtml() now handles
nested lists correctly.

Fixes: QTBUG-88374
Change-Id: I88afba0f897aeef78d4835a3124097fe6fd4d55e
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
(cherry picked from commit 72a5151403f107c445e20cf548ca2e7309c88ce7)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Andy Shaw 2020-11-27 14:39:46 +01:00 committed by Qt Cherry-pick Bot
parent 7bba5a5fc5
commit 4f5c8fecac
3 changed files with 85 additions and 3 deletions

View File

@ -3063,10 +3063,12 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
if (fragmentMarkers && block.position() + block.length() == QTextDocumentPrivate::get(doc)->length())
html += QLatin1String("<!--EndFragment-->");
QString closeTags;
if (pre)
html += QLatin1String("</pre>");
else if (list)
html += QLatin1String("</li>");
closeTags += QLatin1String("</li>");
else {
int headingLevel = blockFormat.headingLevel();
if (headingLevel > 0 && headingLevel <= 6)
@ -3078,9 +3080,30 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
if (list) {
if (list->itemNumber(block) == list->count() - 1) { // last item? close list
if (isOrderedList(list->format().style()))
html += QLatin1String("</ol>");
closeTags += QLatin1String("</ol>");
else
html += QLatin1String("</ul>");
closeTags += QLatin1String("</ul>");
}
const QTextBlock nextBlock = block.next();
// If the next block is the beginning of a new deeper nested list, then we don't
// want to close the current list item just yet. This should be closed when this
// item is fully finished
if (nextBlock.isValid() && nextBlock.textList() &&
nextBlock.textList()->itemNumber(nextBlock) == 0 &&
nextBlock.textList()->format().indent() > list->format().indent()) {
QString lastTag;
if (!closingTags.isEmpty() && list->itemNumber(block) == list->count() - 1)
lastTag = closingTags.takeLast();
lastTag.prepend(closeTags);
closingTags << lastTag;
} else if (list->itemNumber(block) == list->count() - 1) {
// If we are at the end of the list now then we can add in the closing tags for that
// current block
html += closeTags;
if (!closingTags.isEmpty())
html += closingTags.takeLast();
} else {
html += closeTags;
}
}

View File

@ -438,6 +438,7 @@ private:
QTextCharFormat defaultCharFormat;
const QTextDocument *doc;
bool fragmentMarkers;
QStringList closingTags;
};
QT_END_NAMESPACE

View File

@ -1716,6 +1716,59 @@ void tst_QTextDocument::toHtml_data()
<< QString("EMPTYBLOCK") +
QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>");
}
{
CREATE_DOC_AND_CURSOR();
const QString listHtml = "<ul><li>item-1</li><li>item-2<ul><li>item-2.1</li><li>item-2.2"
"<ul><li>item-2.2.1</li></ul></li><li>item-2.3<ul><li>item-2.3.1"
"</li></ul></li></ul></li><li>item-3</li></ul>";
cursor.insertHtml(listHtml);
QTest::newRow("nested-lists-one") << QTextDocumentFragment(&doc)
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
"item-1</li>\n<li DEFAULTBLOCKSTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li "
"DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2\n<ul "
"DEFAULTULSTYLE 3;\"><li DEFAULTBLOCKSTYLE>item-2.2.1</li></ul></li>\n"
"<li DEFAULTBLOCKSTYLE>item-2.3\n<ul DEFAULTULSTYLE 3;\"><li DEFAULTBLOCKSTYLE>"
"item-2.3.1</li></ul></li></ul></li>\n<li DEFAULTLASTLISTYLE>item-3</li></ul>");
}
{
CREATE_DOC_AND_CURSOR();
const QString listHtml = "<ul><li>item-1</li><li>item-2<ul><li>item-2.1</li></ul></li></ul>";
cursor.insertHtml(listHtml);
QTest::newRow("nested-lists-two") << QTextDocumentFragment(&doc)
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
"item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li "
"DEFAULTBLOCKSTYLE>item-2.1</li></ul></li></ul>");
}
{
CREATE_DOC_AND_CURSOR();
const QString listHtml = "<ul><li>item-1</li><li>item-2<ul><li>item-2.1</li><li>item-2.2"
"</li></ul></li></ul>";
cursor.insertHtml(listHtml);
QTest::newRow("nested-lists-three") << QTextDocumentFragment(&doc)
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
"item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li "
"DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2</li></ul>"
"</li></ul>");
}
{
CREATE_DOC_AND_CURSOR();
const QString listHtml = "<ul><li>item-1.1</li><li>item-1.2<li></ul>"
"<ul><li>item-2.1</li></ul>";
cursor.insertHtml(listHtml);
QTest::newRow("not-nested-list") << QTextDocumentFragment(&doc)
<< QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; "
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
"item-1.1</li>\n<li DEFAULTBLOCKSTYLE>item-1.2</li></ul>\n<ul DEFAULTULSTYLE 1;\">"
"<li style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; "
"margin-right:0px; -qt-block-indent:0; text-indent:0px;\">item-2.1</li></ul>");
}
}
void tst_QTextDocument::toHtml()
@ -1730,6 +1783,11 @@ void tst_QTextDocument::toHtml()
expectedOutput.replace("OPENDEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;");
expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"");
expectedOutput.replace("EMPTYBLOCK", "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p>\n");
expectedOutput.replace("DEFAULTULSTYLE", "style=\"margin-top: 0px; margin-bottom: 0px; "
"margin-left: 0px; margin-right: 0px; -qt-list-indent:");
expectedOutput.replace("DEFAULTLASTLISTYLE", "style=\" margin-top:0px; margin-bottom:12px; "
"margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"");
if (expectedOutput.endsWith(QLatin1Char('\n')))
expectedOutput.chop(1);
expectedOutput.append(htmlTail);