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"
9
10#include <QDebug>
11#include <QList>
12#include <QTextDocument>
13
14namespace KPIMTextEdit
15{
16class TextHTMLBuilderPrivate
17{
18public:
19 TextHTMLBuilderPrivate(TextHTMLBuilder *b)
20 : q_ptr(b)
21 {
22 }
23
24 QList<QTextListFormat::Style> currentListItemStyles;
25 QString mText;
26
27 TextHTMLBuilder *const q_ptr;
28
29 Q_DECLARE_PUBLIC(TextHTMLBuilder)
30};
31}
32
33using namespace KPIMTextEdit;
34TextHTMLBuilder::TextHTMLBuilder()
36 , d_ptr(new TextHTMLBuilderPrivate(this))
37{
38}
39
40TextHTMLBuilder::~TextHTMLBuilder()
41{
42 delete d_ptr;
43}
44
46{
48 d->mText.append(QStringLiteral("<strong>"));
49}
50
52{
54 d->mText.append(QStringLiteral("</strong>"));
55}
56
58{
60 d->mText.append(QStringLiteral("<em>"));
61}
62
64{
66 d->mText.append(QStringLiteral("</em>"));
67}
68
70{
72 d->mText.append(QStringLiteral("<u>"));
73}
74
76{
78 d->mText.append(QStringLiteral("</u>"));
79}
80
82{
84 d->mText.append(QStringLiteral("<s>"));
85}
86
88{
90 d->mText.append(QStringLiteral("</s>"));
91}
92
94{
96 d->mText.append(QStringLiteral("<span style=\"color:%1;\">").arg(brush.color().name()));
97}
98
100{
102 d->mText.append(QStringLiteral("</span>"));
103}
104
106{
108 d->mText.append(QStringLiteral("<span style=\"background-color:%1;\">").arg(brush.color().name()));
109}
110
112{
114 d->mText.append(QStringLiteral("</span>"));
115}
116
117void TextHTMLBuilder::beginAnchor(const QString &href, const QString &name)
118{
120 if (!href.isEmpty()) {
121 if (!name.isEmpty()) {
122 d->mText.append(QStringLiteral("<a href=\"%1\" name=\"%2\">").arg(href, name));
123 } else {
124 d->mText.append(QStringLiteral("<a href=\"%1\">").arg(href));
125 }
126 } else {
127 if (!name.isEmpty()) {
128 d->mText.append(QStringLiteral("<a name=\"%1\">").arg(name));
129 }
130 }
131}
132
134{
136 d->mText.append(QStringLiteral("</a>"));
137}
138
140{
142 d->mText.append(QStringLiteral("<span style=\"font-family:%1;\">").arg(family));
143}
144
146{
148 d->mText.append(QStringLiteral("</span>"));
149}
150
152{
154 d->mText.append(QStringLiteral("<span style=\"font-size:%1pt;\">").arg(QString::number(size)));
155}
156
158{
160 d->mText.append(QStringLiteral("</span>"));
161}
162
163void TextHTMLBuilder::beginParagraph(Qt::Alignment al, qreal topMargin, qreal bottomMargin, qreal leftMargin, qreal rightMargin, bool leftToRightText)
164{
166 // Don't put paragraph tags inside li tags. Qt bug reported.
167 // if (currentListItemStyles.size() != 0)
168 // {
169 QString styleString;
170 styleString.append(QStringLiteral("margin-top:%1;").arg(topMargin));
171 styleString.append(QStringLiteral("margin-bottom:%1;").arg(bottomMargin));
172 styleString.append(QStringLiteral("margin-left:%1;").arg(leftMargin));
173 styleString.append(QStringLiteral("margin-right:%1;").arg(rightMargin));
174
175 // Using == doesn't work here.
176 // Using bitwise comparison because an alignment can contain a vertical and
177 // a
178 // horizontal part.
179 if (al & Qt::AlignRight) {
180 d->mText.append(QStringLiteral("<p align=\"right\" "));
181 } else if (al & Qt::AlignHCenter) {
182 d->mText.append(QStringLiteral("<p align=\"center\" "));
183 } else if (al & Qt::AlignJustify) {
184 d->mText.append(QStringLiteral("<p align=\"justify\" "));
185 } else if (al & Qt::AlignLeft) {
186 d->mText.append(QStringLiteral("<p"));
187 } else {
188 d->mText.append(QStringLiteral("<p"));
189 }
190 // Bug in grantlee => style is not defined
191 if (!styleString.isEmpty()) {
192 d->mText.append(QStringLiteral(" style=\"") + styleString + QLatin1Char('"'));
193 }
194 if (leftToRightText) {
195 d->mText.append(QStringLiteral(" dir='rtl'"));
196 }
197 d->mText.append(QLatin1Char('>'));
198 // }
199}
200
202{
204 switch (level) {
205 case 1:
206 d->mText.append(QStringLiteral("<h1>"));
207 break;
208 case 2:
209 d->mText.append(QStringLiteral("<h2>"));
210 break;
211 case 3:
212 d->mText.append(QStringLiteral("<h3>"));
213 break;
214 case 4:
215 d->mText.append(QStringLiteral("<h4>"));
216 break;
217 case 5:
218 d->mText.append(QStringLiteral("<h5>"));
219 break;
220 case 6:
221 d->mText.append(QStringLiteral("<h6>"));
222 break;
223 default:
224 break;
225 }
226}
227
229{
231 switch (level) {
232 case 1:
233 d->mText.append(QStringLiteral("</h1>"));
234 break;
235 case 2:
236 d->mText.append(QStringLiteral("</h2>"));
237 break;
238 case 3:
239 d->mText.append(QStringLiteral("</h3>"));
240 break;
241 case 4:
242 d->mText.append(QStringLiteral("</h4>"));
243 break;
244 case 5:
245 d->mText.append(QStringLiteral("</h5>"));
246 break;
247 case 6:
248 d->mText.append(QStringLiteral("</h6>"));
249 break;
250 default:
251 break;
252 }
253}
254
256{
258 d->mText.append(QStringLiteral("</p>\n"));
259}
260
262{
264 d->mText.append(QStringLiteral("<p>&nbsp;"));
265}
266
268{
270 if (width != -1) {
271 d->mText.append(QStringLiteral("<hr width=\"%1\" />\n").arg(width));
272 }
273 d->mText.append(QStringLiteral("<hr />\n"));
274}
275
276void TextHTMLBuilder::insertImage(const QString &src, qreal width, qreal height)
277{
279 d->mText.append(QStringLiteral("<img src=\"%1\" ").arg(src));
280 if (width != 0) {
281 d->mText.append(QStringLiteral("width=\"%2\" ").arg(width));
282 }
283 if (height != 0) {
284 d->mText.append(QStringLiteral("height=\"%2\" ").arg(height));
285 }
286 d->mText.append(QStringLiteral("/>"));
287}
288
290{
292 d->currentListItemStyles.append(type);
293 switch (type) {
295 d->mText.append(QStringLiteral("<ul type=\"disc\">\n"));
296 break;
298 d->mText.append(QStringLiteral("\n<ul type=\"circle\">\n"));
299 break;
301 d->mText.append(QStringLiteral("\n<ul type=\"square\">\n"));
302 break;
304 d->mText.append(QStringLiteral("\n<ol type=\"1\">\n"));
305 break;
307 d->mText.append(QStringLiteral("\n<ol type=\"a\">\n"));
308 break;
310 d->mText.append(QStringLiteral("\n<ol type=\"A\">\n"));
311 break;
313 d->mText.append(QStringLiteral("\n<ol type=\"i\">\n"));
314 break;
316 d->mText.append(QStringLiteral("\n<ol type=\"I\">\n"));
317 break;
318 default:
319 break;
320 }
321}
323{
325 switch (d->currentListItemStyles.last()) {
329 d->mText.append(QStringLiteral("</ul>\n"));
330 break;
336 d->mText.append(QStringLiteral("</ol>\n"));
337 break;
338 default:
339 break;
340 }
341 d->currentListItemStyles.removeLast();
342}
344{
346 d->mText.append(QStringLiteral("<li>"));
347}
348
350{
352 d->mText.append(QStringLiteral("</li>\n"));
353}
354
356{
358 d->mText.append(QStringLiteral("<sup>"));
359}
360
362{
364 d->mText.append(QStringLiteral("</sup>"));
365}
366
368{
370 d->mText.append(QStringLiteral("<sub>"));
371}
372
374{
376 d->mText.append(QStringLiteral("</sub>"));
377}
378
379void TextHTMLBuilder::beginTable(qreal cellpadding, qreal cellspacing, const QString &width)
380{
382 d->mText.append(QStringLiteral("<table cellpadding=\"%1\" cellspacing=\"%2\" "
383 "width=\"%3\" border=\"1\">")
384 .arg(cellpadding)
385 .arg(cellspacing)
386 .arg(width));
387}
388
390{
392 d->mText.append(QStringLiteral("<tr>"));
393}
394
395void TextHTMLBuilder::beginTableHeaderCell(const QString &width, int colspan, int rowspan)
396{
398 d->mText.append(QStringLiteral("<th width=\"%1\" colspan=\"%2\" rowspan=\"%3\">").arg(width).arg(colspan).arg(rowspan));
399}
400
401void TextHTMLBuilder::beginTableCell(const QString &width, int colspan, int rowspan)
402{
404 d->mText.append(QStringLiteral("<td width=\"%1\" colspan=\"%2\" rowspan=\"%3\">").arg(width).arg(colspan).arg(rowspan));
405}
406
408{
410 d->mText.append(QStringLiteral("</table>"));
411}
412
414{
416 d->mText.append(QStringLiteral("</tr>"));
417}
418
420{
422 d->mText.append(QStringLiteral("</th>"));
423}
424
426{
428 d->mText.append(QStringLiteral("</td>"));
429}
430
432{
434 const QString textEscaped = text.toHtmlEscaped();
435 QString textEscapedResult;
436 for (int i = 0, total = textEscaped.length(); i < total; ++i) {
437 const QChar c = textEscaped.at(i);
438
439 if (c == QLatin1Char(' ')) {
440 if (i == 0) {
441 textEscapedResult += QStringLiteral("&nbsp;");
442 } else {
443 if (i + 1 < textEscaped.length() && (textEscaped.at(i + 1) == QLatin1Char(' '))) {
444 textEscapedResult += QStringLiteral("&nbsp;");
445 } else {
446 textEscapedResult += c;
447 }
448 }
449 } else if (c == QLatin1Char('\t')) {
450 textEscapedResult += QStringLiteral("&nbsp;&nbsp;&nbsp; ");
451 } else {
452 textEscapedResult += c;
453 }
454 }
455 d->mText.append(textEscapedResult);
456}
457
459{
461 d->mText.append(text);
462}
463
465{
467 auto ret = d->mText;
468 d->mText.clear();
469 return ret;
470}
471
472void KPIMTextEdit::TextHTMLBuilder::addSingleBreakLine()
473{
475 d->mText.append(QLatin1StringView("<br />"));
476}
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 Tue Mar 26 2024 11:20:45 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.