Commit 1577eaf4 authored by Laurent Montel's avatar Laurent Montel 😁
Browse files

Reduce duplicate code

parent 9bcc3b03
......@@ -24,161 +24,49 @@
#include <QTextDocument>
#include <QDebug>
namespace KPIMTextEdit {
class TextHTMLBuilderPrivate
{
public:
TextHTMLBuilderPrivate(TextHTMLBuilder *b) : q_ptr(b) {}
QList<QTextListFormat::Style> currentListItemStyles;
QString m_text;
TextHTMLBuilder *q_ptr;
Q_DECLARE_PUBLIC(TextHTMLBuilder)
};
}
using namespace KPIMTextEdit;
TextHTMLBuilder::TextHTMLBuilder()
: AbstractMarkupBuilder(), d_ptr(new TextHTMLBuilderPrivate(this))
: Grantlee::TextHTMLBuilder()
{
}
TextHTMLBuilder::~TextHTMLBuilder()
{
delete d_ptr;
}
void TextHTMLBuilder::beginStrong()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<strong>"));
}
void TextHTMLBuilder::endStrong()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</strong>"));
}
void TextHTMLBuilder::beginEmph()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<em>"));
}
void TextHTMLBuilder::endEmph()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</em>"));
}
void TextHTMLBuilder::beginUnderline()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<u>"));
}
void TextHTMLBuilder::endUnderline()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</u>"));
}
void TextHTMLBuilder::beginStrikeout()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<s>"));
}
void TextHTMLBuilder::endStrikeout()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</s>"));
}
void TextHTMLBuilder::beginForeground(const QBrush &brush)
{
Q_D(TextHTMLBuilder);
d->m_text.append(
QStringLiteral("<span style=\"color:%1;\">").arg(brush.color().name()));
}
void TextHTMLBuilder::endForeground()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</span>"));
}
void TextHTMLBuilder::beginBackground(const QBrush &brush)
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<span style=\"background-color:%1;\">")
.arg(brush.color().name()));
}
void TextHTMLBuilder::endBackground()
//Add &nbsp for avoiding to remove space in html
void TextHTMLBuilder::appendLiteralText(const QString &text)
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</span>"));
}
const QString textEscaped = text.toHtmlEscaped();
QString textEscapedResult;
for (int i = 0, total = textEscaped.count(); i < total; ++i) {
const QChar c = textEscaped.at(i);
void TextHTMLBuilder::beginAnchor(const QString &href, const QString &name)
{
Q_D(TextHTMLBuilder);
if (!href.isEmpty()) {
if (!name.isEmpty()) {
d->m_text.append(
QStringLiteral("<a href=\"%1\" name=\"%2\">").arg(href, name));
if (c == QLatin1Char(' ')) {
if (i == 0) {
textEscapedResult += QStringLiteral("&nbsp;");
} else {
if (i + 1 < textEscaped.count() && (textEscaped.at(i + 1) == QLatin1Char(' '))) {
textEscapedResult += QStringLiteral("&nbsp;");
} else {
textEscapedResult += c;
}
}
} else if (c == QLatin1Char('\t')) {
textEscapedResult += QStringLiteral("&nbsp;&nbsp;&nbsp; ");
} else {
d->m_text.append(QStringLiteral("<a href=\"%1\">").arg(href));
}
} else {
if (!name.isEmpty()) {
d->m_text.append(QStringLiteral("<a name=\"%1\">").arg(name));
textEscapedResult += c;
}
}
appendRawText(textEscapedResult);
}
void TextHTMLBuilder::endAnchor()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</a>"));
}
void TextHTMLBuilder::beginFontFamily(const QString &family)
{
Q_D(TextHTMLBuilder);
d->m_text.append(
QStringLiteral("<span style=\"font-family:%1;\">").arg(family));
}
void TextHTMLBuilder::endFontFamily()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</span>"));
}
void TextHTMLBuilder::beginFontPointSize(int size)
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<span style=\"font-size:%1pt;\">")
.arg(QString::number(size)));
}
void TextHTMLBuilder::endFontPointSize()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</span>"));
}
void TextHTMLBuilder::beginParagraph(Qt::Alignment al, qreal topMargin,
qreal bottomMargin, qreal leftMargin,
qreal rightMargin)
qreal bottomMargin, qreal leftMargin,
qreal rightMargin)
{
Q_D(TextHTMLBuilder);
// Don't put paragraph tags inside li tags. Qt bug reported.
// if (currentListItemStyles.size() != 0)
// {
......@@ -193,302 +81,22 @@ void TextHTMLBuilder::beginParagraph(Qt::Alignment al, qreal topMargin,
// a
// horizontal part.
if (al & Qt::AlignRight) {
d->m_text.append(QStringLiteral("<p align=\"right\" "));
appendRawText(QStringLiteral("<p align=\"right\" "));
} else if (al & Qt::AlignHCenter) {
d->m_text.append(QStringLiteral("<p align=\"center\" "));
appendRawText(QStringLiteral("<p align=\"center\" "));
} else if (al & Qt::AlignJustify) {
d->m_text.append(QStringLiteral("<p align=\"justify\" "));
appendRawText(QStringLiteral("<p align=\"justify\" "));
} else if (al & Qt::AlignLeft) {
d->m_text.append(QStringLiteral("<p"));
appendRawText(QStringLiteral("<p"));
} else {
d->m_text.append(QStringLiteral("<p"));
appendRawText(QStringLiteral("<p"));
}
//Bug in grantlee => style is not defined
if (!styleString.isEmpty()) {
d->m_text.append(QStringLiteral(" style=\"") + styleString + QLatin1Char('"'));
appendRawText(QStringLiteral(" style=\"") + styleString + QLatin1Char('"'));
}
d->m_text.append(QLatin1Char('>'));
appendRawText(QStringLiteral(">"));
// }
}
void TextHTMLBuilder::beginHeader(int level)
{
Q_D(TextHTMLBuilder);
switch (level) {
case 1:
d->m_text.append(QStringLiteral("<h1>"));
break;
case 2:
d->m_text.append(QStringLiteral("<h2>"));
break;
case 3:
d->m_text.append(QStringLiteral("<h3>"));
break;
case 4:
d->m_text.append(QStringLiteral("<h4>"));
break;
case 5:
d->m_text.append(QStringLiteral("<h5>"));
break;
case 6:
d->m_text.append(QStringLiteral("<h6>"));
break;
default:
break;
}
}
void TextHTMLBuilder::endHeader(int level)
{
Q_D(TextHTMLBuilder);
switch (level) {
case 1:
d->m_text.append(QStringLiteral("</h1>"));
break;
case 2:
d->m_text.append(QStringLiteral("</h2>"));
break;
case 3:
d->m_text.append(QStringLiteral("</h3>"));
break;
case 4:
d->m_text.append(QStringLiteral("</h4>"));
break;
case 5:
d->m_text.append(QStringLiteral("</h5>"));
break;
case 6:
d->m_text.append(QStringLiteral("</h6>"));
break;
default:
break;
}
}
void TextHTMLBuilder::endParagraph()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</p>\n"));
}
void TextHTMLBuilder::addNewline()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<p>&nbsp;"));
}
void TextHTMLBuilder::insertHorizontalRule(int width)
{
Q_D(TextHTMLBuilder);
if (width != -1) {
d->m_text.append(QStringLiteral("<hr width=\"%1\" />\n").arg(width));
}
d->m_text.append(QStringLiteral("<hr />\n"));
}
void TextHTMLBuilder::insertImage(const QString &src, qreal width, qreal height)
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<img src=\"%1\" ").arg(src));
if (width != 0)
d->m_text.append(QStringLiteral("width=\"%2\" ").arg(width));
if (height != 0)
d->m_text.append(QStringLiteral("height=\"%2\" ").arg(height));
d->m_text.append(QStringLiteral("/>"));
}
void TextHTMLBuilder::beginList(QTextListFormat::Style type)
{
Q_D(TextHTMLBuilder);
d->currentListItemStyles.append(type);
switch (type) {
case QTextListFormat::ListDisc:
d->m_text.append(QStringLiteral("<ul type=\"disc\">\n"));
break;
case QTextListFormat::ListCircle:
d->m_text.append(QStringLiteral("\n<ul type=\"circle\">\n"));
break;
case QTextListFormat::ListSquare:
d->m_text.append(QStringLiteral("\n<ul type=\"square\">\n"));
break;
case QTextListFormat::ListDecimal:
d->m_text.append(QStringLiteral("\n<ol type=\"1\">\n"));
break;
case QTextListFormat::ListLowerAlpha:
d->m_text.append(QStringLiteral("\n<ol type=\"a\">\n"));
break;
case QTextListFormat::ListUpperAlpha:
d->m_text.append(QStringLiteral("\n<ol type=\"A\">\n"));
break;
case QTextListFormat::ListLowerRoman:
d->m_text.append(QStringLiteral("\n<ol type=\"i\">\n"));
break;
case QTextListFormat::ListUpperRoman:
d->m_text.append(QStringLiteral("\n<ol type=\"I\">\n"));
break;
default:
break;
}
}
void TextHTMLBuilder::endList()
{
Q_D(TextHTMLBuilder);
switch (d->currentListItemStyles.last()) {
case QTextListFormat::ListDisc:
case QTextListFormat::ListCircle:
case QTextListFormat::ListSquare:
d->m_text.append(QStringLiteral("</ul>\n"));
break;
case QTextListFormat::ListDecimal:
case QTextListFormat::ListLowerAlpha:
case QTextListFormat::ListUpperAlpha:
case QTextListFormat::ListLowerRoman:
case QTextListFormat::ListUpperRoman:
d->m_text.append(QStringLiteral("</ol>\n"));
break;
default:
break;
}
d->currentListItemStyles.removeLast();
}
void TextHTMLBuilder::beginListItem()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<li>"));
}
void TextHTMLBuilder::endListItem()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</li>\n"));
}
void TextHTMLBuilder::beginSuperscript()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<sup>"));
}
void TextHTMLBuilder::endSuperscript()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</sup>"));
}
void TextHTMLBuilder::beginSubscript()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<sub>"));
}
void TextHTMLBuilder::endSubscript()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</sub>"));
}
void TextHTMLBuilder::beginTable(qreal cellpadding, qreal cellspacing,
const QString &width)
{
Q_D(TextHTMLBuilder);
d->m_text.append(
QStringLiteral("<table cellpadding=\"%1\" cellspacing=\"%2\" "
"width=\"%3\" border=\"1\">")
.arg(cellpadding)
.arg(cellspacing)
.arg(width));
}
void TextHTMLBuilder::beginTableRow()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("<tr>"));
}
void TextHTMLBuilder::beginTableHeaderCell(const QString &width, int colspan,
int rowspan)
{
Q_D(TextHTMLBuilder);
d->m_text.append(
QStringLiteral("<th width=\"%1\" colspan=\"%2\" rowspan=\"%3\">")
.arg(width)
.arg(colspan)
.arg(rowspan));
}
void TextHTMLBuilder::beginTableCell(const QString &width, int colspan,
int rowspan)
{
Q_D(TextHTMLBuilder);
d->m_text.append(
QStringLiteral("<td width=\"%1\" colspan=\"%2\" rowspan=\"%3\">")
.arg(width)
.arg(colspan)
.arg(rowspan));
}
void TextHTMLBuilder::endTable()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</table>"));
}
void TextHTMLBuilder::endTableRow()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</tr>"));
}
void TextHTMLBuilder::endTableHeaderCell()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</th>"));
}
void TextHTMLBuilder::endTableCell()
{
Q_D(TextHTMLBuilder);
d->m_text.append(QStringLiteral("</td>"));
}
void TextHTMLBuilder::appendLiteralText(const QString &text)
{
Q_D(TextHTMLBuilder);
const QString textEscaped = text.toHtmlEscaped();
QString textEscapedResult;
for (int i = 0, total = textEscaped.count(); i < total; ++i) {
const QChar c = textEscaped.at(i);
if (c == QLatin1Char(' ')) {
if (i == 0) {
textEscapedResult += QStringLiteral("&nbsp;");
} else {
if (i + 1 < textEscaped.count() && (textEscaped.at(i + 1) == QLatin1Char(' '))) {
textEscapedResult += QStringLiteral("&nbsp;");
} else {
textEscapedResult += c;
}
}
} else if (c == QLatin1Char('\t')) {
//TODO fixme ?
textEscapedResult += QStringLiteral("&nbsp;&nbsp;&nbsp; ");
} else {
textEscapedResult += c;
}
}
d->m_text.append(textEscapedResult);
}
void TextHTMLBuilder::appendRawText(const QString &text)
{
Q_D(TextHTMLBuilder);
d->m_text.append(text);
}
QString TextHTMLBuilder::getResult()
{
Q_D(TextHTMLBuilder);
auto ret = d->m_text;
d->m_text.clear();
return ret;
}
......@@ -22,211 +22,19 @@
#include "kpimtextedit_export.h"
#include <grantlee/texthtmlbuilder.h>
#include <grantlee/abstractmarkupbuilder.h>
namespace KPIMTextEdit
{
class TextHTMLBuilderPrivate;
/// @headerfile texthtmlbuilder.h grantlee/texthtmlbuilder.h
/**
@brief The TextHTMLBuilder creates a clean html markup output.
This class creates html output which is as minimal as possible and restricted
to the rich text features supported in %Qt.
(https://doc.qt.io/qt-5/richtext-html-subset.html)
The output contains only the body content, not the head element or other
metadata.
eg:
@code
<p>
This is some <strong>formatted content</strong> in a paragraph.
</p>
@endcode
instead of the content produced by %Qt:
@code
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><meta
http-equiv="Content-Type" content="text/html; charset=UTF-8" /><style
type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'Sans Serif'; font-size:10pt;
font-weight:400; font-style:normal;">
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px;
margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is some <span
style=" font-weight:600;">formatted content</span> in a paragraph.
</p></body></html>
@endcode
Such tags should be created separately. For example:
@code
auto b = new TextHTMLBuilder();
auto md = new MarkupDirector(b);
md->constructContent();
QString cleanHtml(
"<head>\n<title>%1</title>\n</head>\n<body>%2</body>\n</html>")
.arg(document.metaInformation(QTextDocument::DocumentTitle))
.arg(b->getOutput());
file.write(cleanHtml);
@endcode
Font formatting information on elements is represented by individual span
elements.
eg:
@code
<span style"color:blue;">
<span style="background-color:red;">
Blue text on red background
</span>
</span>
@endcode
instead of
@code
<span style="color:blue;background-color:red;">
Blue text on red background
</span>
@endcode
It my be possible to change this if necessary.
@author Stephen Kelly <steveire@gmail.com>
*/
class KPIMTEXTEDIT_EXPORT TextHTMLBuilder
: virtual public Grantlee::AbstractMarkupBuilder
: virtual public Grantlee::TextHTMLBuilder
{
public:
TextHTMLBuilder();
~TextHTMLBuilder() override;
void beginStrong() override;
void endStrong() override;
void beginEmph() override;
void endEmph() override;
void beginUnderline() override;
void endUnderline() override;
void beginStrikeout() override;
void endStrikeout() override;
void beginForeground(const QBrush &brush) override;
void endForeground() override;
void beginBackground(const QBrush &brush) override;
void endBackground() override;
void beginAnchor(const QString &href = {}, const QString &name = {}) override;
void endAnchor() override;
// Maybe this stuff should just be added to a list, and then when I add
// literal text,
// add some kind of style attribute in one span instead of many.
void beginFontFamily(const QString &family)