KPimTextEdit

texthtmlbuilder.cpp
1/*
2 SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org>
3 based on code from Stephen Kelly <steveire@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "texthtmlbuilder.h"
9using namespace Qt::Literals::StringLiterals;
10
11#include <QDebug>
12#include <QList>
13#include <QTextDocument>
14
15namespace KPIMTextEdit
16{
17class TextHTMLBuilderPrivate
18{
19public:
20 TextHTMLBuilderPrivate(TextHTMLBuilder *b)
21 : q_ptr(b)
22 {
23 }
24
25 QList<QTextListFormat::Style> currentListItemStyles;
26 QString mText;
27
28 TextHTMLBuilder *const q_ptr;
29
30 Q_DECLARE_PUBLIC(TextHTMLBuilder)
31};
32}
33
34using namespace KPIMTextEdit;
35TextHTMLBuilder::TextHTMLBuilder()
37 , d_ptr(new TextHTMLBuilderPrivate(this))
38{
39}
40
41TextHTMLBuilder::~TextHTMLBuilder()
42{
43 delete d_ptr;
44}
45
47{
49 d->mText.append(QStringLiteral("<strong>"));
50}
51
53{
55 d->mText.append(QStringLiteral("</strong>"));
56}
57
59{
61 d->mText.append(QStringLiteral("<em>"));
62}
63
65{
67 d->mText.append(QStringLiteral("</em>"));
68}
69
71{
73 d->mText.append(QStringLiteral("<u>"));
74}
75
77{
79 d->mText.append(QStringLiteral("</u>"));
80}
81
83{
85 d->mText.append(QStringLiteral("<s>"));
86}
87
89{
91 d->mText.append(QStringLiteral("</s>"));
92}
93
95{
97 d->mText.append(QStringLiteral("<span style=\"color:%1;\">").arg(brush.color().name()));
98}
99
101{
103 d->mText.append(QStringLiteral("</span>"));
104}
105
107{
109 d->mText.append(QStringLiteral("<span style=\"background-color:%1;\">").arg(brush.color().name()));
110}
111
113{
115 d->mText.append(QStringLiteral("</span>"));
116}
117
118void TextHTMLBuilder::beginAnchor(const QString &href, const QString &name)
119{
121 if (!href.isEmpty()) {
122 if (!name.isEmpty()) {
123 d->mText.append(QStringLiteral("<a href=\"%1\" name=\"%2\">").arg(href, name));
124 } else {
125 d->mText.append(QStringLiteral("<a href=\"%1\">").arg(href));
126 }
127 } else {
128 if (!name.isEmpty()) {
129 d->mText.append(QStringLiteral("<a name=\"%1\">").arg(name));
130 }
131 }
132}
133
135{
137 d->mText.append(QStringLiteral("</a>"));
138}
139
141{
143 d->mText.append(QStringLiteral("<span style=\"font-family:%1;\">").arg(family));
144}
145
147{
149 d->mText.append(QStringLiteral("</span>"));
150}
151
153{
155 d->mText.append(QStringLiteral("<span style=\"font-size:%1pt;\">").arg(QString::number(size)));
156}
157
159{
161 d->mText.append(QStringLiteral("</span>"));
162}
163
164void TextHTMLBuilder::beginParagraph(Qt::Alignment al, qreal topMargin, qreal bottomMargin, qreal leftMargin, qreal rightMargin, bool leftToRightText)
165{
167 // Don't put paragraph tags inside li tags. Qt bug reported.
168 // if (currentListItemStyles.size() != 0)
169 // {
170 QString styleString;
171 styleString.append(QStringLiteral("margin-top:%1;").arg(topMargin));
172 styleString.append(QStringLiteral("margin-bottom:%1;").arg(bottomMargin));
173 styleString.append(QStringLiteral("margin-left:%1;").arg(leftMargin));
174 styleString.append(QStringLiteral("margin-right:%1;").arg(rightMargin));
175
176 // Using == doesn't work here.
177 // Using bitwise comparison because an alignment can contain a vertical and
178 // a
179 // horizontal part.
180 if (al & Qt::AlignRight) {
181 d->mText.append(QStringLiteral("<p align=\"right\" "));
182 } else if (al & Qt::AlignHCenter) {
183 d->mText.append(QStringLiteral("<p align=\"center\" "));
184 } else if (al & Qt::AlignJustify) {
185 d->mText.append(QStringLiteral("<p align=\"justify\" "));
186 } else if (al & Qt::AlignLeft) {
187 d->mText.append(QStringLiteral("<p"));
188 } else {
189 d->mText.append(QStringLiteral("<p"));
190 }
191 // Bug in grantlee => style is not defined
192 if (!styleString.isEmpty()) {
193 d->mText.append(QStringLiteral(" style=\"") + styleString + QLatin1Char('"'));
194 }
195 if (leftToRightText) {
196 d->mText.append(QStringLiteral(" dir='rtl'"));
197 }
198 d->mText.append(QLatin1Char('>'));
199 // }
200}
201
203{
205 switch (level) {
206 case 1:
207 d->mText.append(QStringLiteral("<h1>"));
208 break;
209 case 2:
210 d->mText.append(QStringLiteral("<h2>"));
211 break;
212 case 3:
213 d->mText.append(QStringLiteral("<h3>"));
214 break;
215 case 4:
216 d->mText.append(QStringLiteral("<h4>"));
217 break;
218 case 5:
219 d->mText.append(QStringLiteral("<h5>"));
220 break;
221 case 6:
222 d->mText.append(QStringLiteral("<h6>"));
223 break;
224 default:
225 break;
226 }
227}
228
230{
232 switch (level) {
233 case 1:
234 d->mText.append(QStringLiteral("</h1>"));
235 break;
236 case 2:
237 d->mText.append(QStringLiteral("</h2>"));
238 break;
239 case 3:
240 d->mText.append(QStringLiteral("</h3>"));
241 break;
242 case 4:
243 d->mText.append(QStringLiteral("</h4>"));
244 break;
245 case 5:
246 d->mText.append(QStringLiteral("</h5>"));
247 break;
248 case 6:
249 d->mText.append(QStringLiteral("</h6>"));
250 break;
251 default:
252 break;
253 }
254}
255
257{
259 d->mText.append(QStringLiteral("</p>\n"));
260}
261
263{
265 d->mText.append(QStringLiteral("<p>&nbsp;"));
266}
267
269{
271 if (width != -1) {
272 d->mText.append(QStringLiteral("<hr width=\"%1\" />\n").arg(width));
273 }
274 d->mText.append(QStringLiteral("<hr />\n"));
275}
276
277void TextHTMLBuilder::insertImage(const QString &src, qreal width, qreal height)
278{
280 d->mText.append(QStringLiteral("<img src=\"%1\" ").arg(src));
281 if (width != 0) {
282 d->mText.append(QStringLiteral("width=\"%2\" ").arg(width));
283 }
284 if (height != 0) {
285 d->mText.append(QStringLiteral("height=\"%2\" ").arg(height));
286 }
287 d->mText.append(QStringLiteral("/>"));
288}
289
291{
293 d->currentListItemStyles.append(type);
294 switch (type) {
296 d->mText.append(QStringLiteral("<ul type=\"disc\">\n"));
297 break;
299 d->mText.append(QStringLiteral("\n<ul type=\"circle\">\n"));
300 break;
302 d->mText.append(QStringLiteral("\n<ul type=\"square\">\n"));
303 break;
305 d->mText.append(QStringLiteral("\n<ol type=\"1\">\n"));
306 break;
308 d->mText.append(QStringLiteral("\n<ol type=\"a\">\n"));
309 break;
311 d->mText.append(QStringLiteral("\n<ol type=\"A\">\n"));
312 break;
314 d->mText.append(QStringLiteral("\n<ol type=\"i\">\n"));
315 break;
317 d->mText.append(QStringLiteral("\n<ol type=\"I\">\n"));
318 break;
319 default:
320 break;
321 }
322}
324{
326 switch (d->currentListItemStyles.last()) {
330 d->mText.append(QStringLiteral("</ul>\n"));
331 break;
337 d->mText.append(QStringLiteral("</ol>\n"));
338 break;
339 default:
340 break;
341 }
342 d->currentListItemStyles.removeLast();
343}
345{
347 d->mText.append(QStringLiteral("<li>"));
348}
349
351{
353 d->mText.append(QStringLiteral("</li>\n"));
354}
355
357{
359 d->mText.append(QStringLiteral("<sup>"));
360}
361
363{
365 d->mText.append(QStringLiteral("</sup>"));
366}
367
369{
371 d->mText.append(QStringLiteral("<sub>"));
372}
373
375{
377 d->mText.append(QStringLiteral("</sub>"));
378}
379
380void TextHTMLBuilder::beginTable(qreal cellpadding, qreal cellspacing, const QString &width)
381{
383 d->mText.append(QStringLiteral("<table cellpadding=\"%1\" cellspacing=\"%2\" "
384 "width=\"%3\" border=\"1\">")
385 .arg(cellpadding)
386 .arg(cellspacing)
387 .arg(width));
388}
389
391{
393 d->mText.append(QStringLiteral("<tr>"));
394}
395
396void TextHTMLBuilder::beginTableHeaderCell(const QString &width, int colspan, int rowspan)
397{
399 d->mText.append(QStringLiteral("<th width=\"%1\" colspan=\"%2\" rowspan=\"%3\">").arg(width).arg(colspan).arg(rowspan));
400}
401
402void TextHTMLBuilder::beginTableCell(const QString &width, int colspan, int rowspan)
403{
405 d->mText.append(QStringLiteral("<td width=\"%1\" colspan=\"%2\" rowspan=\"%3\">").arg(width).arg(colspan).arg(rowspan));
406}
407
409{
411 d->mText.append(QStringLiteral("</table>"));
412}
413
415{
417 d->mText.append(QStringLiteral("</tr>"));
418}
419
421{
423 d->mText.append(QStringLiteral("</th>"));
424}
425
427{
429 d->mText.append(QStringLiteral("</td>"));
430}
431
433{
435 const QString textEscaped = text.toHtmlEscaped();
436 QString textEscapedResult;
437 for (int i = 0, total = textEscaped.length(); i < total; ++i) {
438 const QChar c = textEscaped.at(i);
439
440 if (c == QLatin1Char(' ')) {
441 if (i == 0) {
442 textEscapedResult += QStringLiteral("&nbsp;");
443 } else {
444 if (i + 1 < textEscaped.length() && (textEscaped.at(i + 1) == QLatin1Char(' '))) {
445 textEscapedResult += QStringLiteral("&nbsp;");
446 } else {
447 textEscapedResult += c;
448 }
449 }
450 } else if (c == QLatin1Char('\t')) {
451 textEscapedResult += QStringLiteral("&nbsp;&nbsp;&nbsp; ");
452 } else {
453 textEscapedResult += c;
454 }
455 }
456 d->mText.append(textEscapedResult);
457}
458
460{
462 d->mText.append(text);
463}
464
466{
468 auto ret = d->mText;
469 d->mText.clear();
470 return ret;
471}
472
473void KPIMTextEdit::TextHTMLBuilder::addSingleBreakLine()
474{
476 d->mText.append("<br />"_L1);
477}
Interface for creating marked-up text output.
The TextHTMLBuilder creates a clean html markup output.
void beginTableCell(const QString &width, int colspan, int rowspan) override
Begin a new table cell.
void beginEmph() override
Begin an emphasised element in the markup.
void beginTable(qreal cellpadding, qreal cellspacing, const QString &width) override
Begin a table element.
void appendRawText(const QString &text) override
Append text without escaping.
void beginSubscript() override
Begin a subscript element.
void beginSuperscript() override
Begin a superscript element.
void beginTableRow() override
Begin a new table row.
void endParagraph() override
Close the paragraph in the markup.
void endSuperscript() override
End superscript element.
QString getResult() override
Return the fully marked up result of the building process.
void beginAnchor(const QString &href={}, const QString &name={}) override
Begin a url anchor element in the markup.
void endStrong() override
Close the bold element in the markup.
void endList() override
Close the list.
void endAnchor() override
Close the anchor element.
void beginListItem() override
Begin a new list item in the markup.
void endTable() override
End a table element.
void beginForeground(const QBrush &brush) override
Begin a decorarated foreground element in the markup (A text color) using brush.
void endBackground() override
Close the decorarated background element in the markup.
void beginBackground(const QBrush &brush) override
Begin a decorarated background element in the markup (A text background color) using brush.
void appendLiteralText(const QString &text) override
Reimplemented from AbstractMarkupBuilder.
void beginStrikeout() override
Begin a struck out element in the markup.
void beginHeader(int level) override
Begin a new header element.
void endHeader(int level) override
End a header element.
void beginParagraph(Qt::Alignment al=Qt::AlignLeft, qreal topMargin=0.0, qreal bottomMargin=0.0, qreal leftMargin=0.0, qreal rightMargin=0.0, bool leftToRightText=false) override
Begin a new paragraph.
void endTableHeaderCell() override
End a table header cell.
void beginTableHeaderCell(const QString &width, int colspan, int rowspan) override
Begin a new table header cell.
void endFontFamily() override
End font family element.
void endStrikeout() override
Close the struck out element in the markup.
void endFontPointSize() override
End font point size element.
void insertHorizontalRule(int width=-1) override
Insert a horizontal rule into the markup.
void endTableCell() override
End a table cell.
void endForeground() override
Close the decorarated foreground element in the markup.
void insertImage(const QString &src, qreal width, qreal height) override
Insert a new image element into the markup.
void beginStrong() override
Begin a bold element in the markup.
void beginUnderline() override
Begin an underlined element in the markup.
void beginList(QTextListFormat::Style type) override
Begin a new list element in the markup.
void beginFontFamily(const QString &family) override
Begin a new font family element in the markup.
void endUnderline() override
Close the underlined element in the markup.
void beginFontPointSize(int size) override
Begin a new font point size.
void endTableRow() override
End a table row.
void endEmph() override
Close the emphasised element in the markup.
void addNewline() override
Add a newline to the markup.
void endSubscript() override
End subscript element.
void endListItem() override
End the list item.
const QColor & color() const const
QString name(NameFormat format) const const
QString & append(QChar ch)
const QChar at(qsizetype position) const const
bool isEmpty() const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString toHtmlEscaped() const const
typedef Alignment
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:35:46 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.