KPimTextEdit

plaintextmarkupbuilder.cpp
1/*
2 SPDX-FileCopyrightText: 2019-2020 Montel Laurent <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5
6*/
7
8#include "plaintextmarkupbuilder.h"
9#include <QDebug>
10namespace KPIMTextEdit
11{
12class PlainTextMarkupBuilderPrivate
13{
14public:
15 PlainTextMarkupBuilderPrivate(PlainTextMarkupBuilder *b)
16 : q_ptr(b)
17 {
18 }
19
20 /**
21 Get a letter string to represent a number.
22
23 The numbers 1-26 are represented by a-z, and 27-52 by aa-az, 53-79 by
24 ba-bz
25 etc.
26
27 @param The number to convert
28 @return The letter string representation of the number.
29 */
30 [[nodiscard]] QString getLetterString(int itemNumber);
31
32 [[nodiscard]] QString getRomanString(int itemNumber);
33
34 /**
35 Gets a block of references in the body of the text.
36 This is an ordered list of links and images in the text.
37 */
38 [[nodiscard]] QString getReferences();
39
40 QStringList mUrls;
41 QList<QTextListFormat::Style> currentListItemStyles;
42 QList<int> currentListItemNumbers;
43
44 QString activeLink;
45
46 QString mText;
47
48 QString mQuoteprefix;
49
50 PlainTextMarkupBuilder *const q_ptr;
51
52 Q_DECLARE_PUBLIC(PlainTextMarkupBuilder)
53};
54}
55
56using namespace KPIMTextEdit;
57PlainTextMarkupBuilder::PlainTextMarkupBuilder()
58 : d_ptr(new PlainTextMarkupBuilderPrivate(this))
59{
60}
61
62QString PlainTextMarkupBuilderPrivate::getRomanString(int item)
63{
64 QString result;
65 // Code based to gui/text/qtextlist.cpp
66 if (item < 5000) {
67 QString romanNumeral;
68
69 // works for up to 4999 items
70 auto romanSymbols = QStringLiteral("iiivixxxlxcccdcmmmm");
71 int c[] = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000};
72 auto n = item;
73 for (auto i = 12; i >= 0; n %= c[i], i--) {
74 auto q = n / c[i];
75 if (q > 0) {
76 auto startDigit = i + (i + 3) / 4;
77 int numDigits;
78 if (i % 4) {
79 // c[i] == 4|5|9|40|50|90|400|500|900
80 if ((i - 2) % 4) {
81 // c[i] == 4|9|40|90|400|900 => with subtraction (IV,
82 // IX, XL, XC,
83 // ...)
84 numDigits = 2;
85 } else {
86 // c[i] == 5|50|500 (V, L, D)
87 numDigits = 1;
88 }
89 } else {
90 // c[i] == 1|10|100|1000 (I, II, III, X, XX, ...)
91 numDigits = q;
92 }
93
94 romanNumeral.append(QStringView(romanSymbols).mid(startDigit, numDigits).toString());
95 }
96 }
97 result = romanNumeral;
98 } else {
99 result = QStringLiteral("?");
100 }
101 return result;
102}
103
104QString PlainTextMarkupBuilderPrivate::getLetterString(int itemNumber)
105{
106 QString letterString;
107 while (true) {
108 // Create the letter string by prepending one char at a time.
109 // The itemNumber is converted to a number in the base 36 (number of
110 // letters
111 // in the
112 // alphabet plus 10) after being increased by 10 (to pass out the digits
113 // 0
114 // to 9).
115 letterString.prepend(QStringLiteral("%1").arg((itemNumber % LETTERSINALPHABET) + DIGITSOFFSET,
116 0, // no padding while building this string.
117 LETTERSINALPHABET + DIGITSOFFSET));
118 if ((itemNumber >= LETTERSINALPHABET)) {
119 itemNumber = itemNumber / LETTERSINALPHABET;
120 itemNumber--;
121 } else {
122 break;
123 }
124 }
125 return letterString;
126}
127
128QString PlainTextMarkupBuilderPrivate::getReferences()
129{
130 QString refs;
131 if (!mUrls.isEmpty()) {
132 refs.append(QStringLiteral("\n--------\n"));
133
134 int index = 1;
135 while (!mUrls.isEmpty()) {
136 refs.append(QStringLiteral("[%1] %2\n").arg(index++).arg(mUrls.takeFirst()));
137 }
138 }
139 return refs;
140}
141
142PlainTextMarkupBuilder::~PlainTextMarkupBuilder()
143{
144 delete d_ptr;
145}
146
147void PlainTextMarkupBuilder::setQuotePrefix(const QString &prefix)
148{
149 Q_D(PlainTextMarkupBuilder);
150 d->mQuoteprefix = prefix;
151}
152
153void PlainTextMarkupBuilder::beginStrong()
154{
155 Q_D(PlainTextMarkupBuilder);
156 d->mText.append(QLatin1Char('*'));
157}
158
159void PlainTextMarkupBuilder::endStrong()
160{
161 Q_D(PlainTextMarkupBuilder);
162 d->mText.append(QLatin1Char('*'));
163}
164
165void PlainTextMarkupBuilder::beginEmph()
166{
167 Q_D(PlainTextMarkupBuilder);
168 d->mText.append(QLatin1Char('/'));
169}
170
171void PlainTextMarkupBuilder::endEmph()
172{
173 Q_D(PlainTextMarkupBuilder);
174 d->mText.append(QLatin1Char('/'));
175}
176
177void PlainTextMarkupBuilder::beginUnderline()
178{
179 Q_D(PlainTextMarkupBuilder);
180 d->mText.append(QLatin1Char('_'));
181}
182
183void PlainTextMarkupBuilder::endUnderline()
184{
185 Q_D(PlainTextMarkupBuilder);
186 d->mText.append(QLatin1Char('_'));
187}
188
189void PlainTextMarkupBuilder::beginStrikeout()
190{
191 Q_D(PlainTextMarkupBuilder);
192 d->mText.append(QLatin1Char('-'));
193}
194
195void PlainTextMarkupBuilder::endStrikeout()
196{
197 Q_D(PlainTextMarkupBuilder);
198 d->mText.append(QLatin1Char('-'));
199}
200
201void PlainTextMarkupBuilder::beginAnchor(const QString &href, const QString &name)
202{
203 Q_D(PlainTextMarkupBuilder);
204 Q_UNUSED(name)
205 if (!d->mUrls.contains(href)) {
206 d->mUrls.append(href);
207 }
208 d->activeLink = href;
209}
210
211void PlainTextMarkupBuilder::endAnchor()
212{
213 Q_D(PlainTextMarkupBuilder);
214 d->mText.append(QStringLiteral("[%1]").arg(d->mUrls.indexOf(d->activeLink) + 1));
215}
216
217void PlainTextMarkupBuilder::endParagraph()
218{
219 Q_D(PlainTextMarkupBuilder);
220 d->mText.append(QLatin1Char('\n'));
221}
222
223void PlainTextMarkupBuilder::addNewline()
224{
225 Q_D(PlainTextMarkupBuilder);
226 d->mText.append(QLatin1Char('\n'));
227}
228
229void PlainTextMarkupBuilder::insertHorizontalRule(int width)
230{
231 Q_UNUSED(width)
232 Q_D(PlainTextMarkupBuilder);
233
234 d->mText.append(QStringLiteral("--------------------\n"));
235}
236
237int PlainTextMarkupBuilder::addReference(const QString &reference)
238{
239 Q_D(PlainTextMarkupBuilder);
240
241 if (!d->mUrls.contains(reference)) {
242 d->mUrls.append(reference);
243 }
244 return d->mUrls.indexOf(reference) + 1;
245}
246
247void PlainTextMarkupBuilder::insertImage(const QString &src, qreal width, qreal height)
248{
249 Q_D(PlainTextMarkupBuilder);
250 Q_UNUSED(width)
251 Q_UNUSED(height)
252
253 const auto ref = addReference(src);
254
255 d->mText.append(QStringLiteral("[%1]").arg(ref));
256}
257
258void PlainTextMarkupBuilder::beginList(QTextListFormat::Style style)
259{
260 Q_D(PlainTextMarkupBuilder);
261 d->currentListItemStyles.append(style);
262 d->currentListItemNumbers.append(0);
263}
264
265void PlainTextMarkupBuilder::endList()
266{
267 Q_D(PlainTextMarkupBuilder);
268 if (!d->currentListItemNumbers.isEmpty()) {
269 d->currentListItemStyles.removeLast();
270 d->currentListItemNumbers.removeLast();
271 }
272}
273
274void PlainTextMarkupBuilder::beginListItem()
275{
276 Q_D(PlainTextMarkupBuilder);
277 for (int i = 0, total = d->currentListItemNumbers.size(); i < total; ++i) {
278 d->mText.append(QStringLiteral(" "));
279 }
280
281 auto itemNumber = d->currentListItemNumbers.last();
282
283 switch (d->currentListItemStyles.last()) {
285 d->mText.append(QStringLiteral(" * "));
286 break;
288 d->mText.append(QStringLiteral(" o "));
289 break;
291 d->mText.append(QStringLiteral(" - "));
292 break;
294 d->mText.append(QStringLiteral(" %1. ").arg(itemNumber + 1));
295 break;
297 d->mText.append(QStringLiteral(" %1. ").arg(d->getLetterString(itemNumber)));
298 break;
300 d->mText.append(QStringLiteral(" %1. ").arg(d->getLetterString(itemNumber).toUpper()));
301 break;
303 d->mText.append(QStringLiteral(" %1. ").arg(d->getRomanString(itemNumber + 1)));
304 break;
306 d->mText.append(QStringLiteral(" %1. ").arg(d->getRomanString(itemNumber + 1).toUpper()));
307 break;
308 default:
309 break;
310 }
311}
312
313void PlainTextMarkupBuilder::endListItem()
314{
315 Q_D(PlainTextMarkupBuilder);
316 d->currentListItemNumbers.last() = d->currentListItemNumbers.last() + 1;
317 d->mText.append(QLatin1Char('\n'));
318}
319
320void PlainTextMarkupBuilder::beginSuperscript()
321{
322 Q_D(PlainTextMarkupBuilder);
323 d->mText.append(QStringLiteral("^{"));
324}
325
326void PlainTextMarkupBuilder::endSuperscript()
327{
328 Q_D(PlainTextMarkupBuilder);
329 d->mText.append(QLatin1Char('}'));
330}
331
332void PlainTextMarkupBuilder::beginSubscript()
333{
334 Q_D(PlainTextMarkupBuilder);
335 d->mText.append(QStringLiteral("_{"));
336}
337
338void PlainTextMarkupBuilder::endSubscript()
339{
340 Q_D(PlainTextMarkupBuilder);
341 d->mText.append(QLatin1Char('}'));
342}
343
344void PlainTextMarkupBuilder::appendLiteralText(const QString &text)
345{
346 Q_D(PlainTextMarkupBuilder);
347 d->mText.append(text);
348}
349
350void PlainTextMarkupBuilder::appendRawText(const QString &text)
351{
352 Q_D(PlainTextMarkupBuilder);
353 d->mText.append(text);
354}
355
356QString PlainTextMarkupBuilder::getResult()
357{
358 Q_D(PlainTextMarkupBuilder);
359 auto ret = d->mText;
360 ret.append(d->getReferences());
361 d->mText.clear();
362 return ret;
363}
364
365void PlainTextMarkupBuilder::beginParagraph(Qt::Alignment a, qreal top, qreal bottom, qreal left, qreal right, bool leftToRightText)
366{
367 Q_UNUSED(a)
368 Q_UNUSED(leftToRightText)
369 Q_D(PlainTextMarkupBuilder);
370 if (isQuoteBlock(top, bottom, left, right)) {
371 d->mText.append(d->mQuoteprefix);
372 }
373}
374
375bool PlainTextMarkupBuilder::isQuoteBlock(qreal top, qreal bottom, qreal left, qreal right) const
376{
377 Q_UNUSED(top)
378 Q_UNUSED(bottom)
379 return /*(top == 12) && (bottom == 12) &&*/ (left == 40) && (right == 40);
380}
381
382void PlainTextMarkupBuilder::beginBackground(const QBrush &brush)
383{
384 Q_UNUSED(brush)
385}
386
387void PlainTextMarkupBuilder::beginFontFamily(const QString &family)
388{
389 Q_UNUSED(family)
390}
391
392void PlainTextMarkupBuilder::beginFontPointSize(int size)
393{
394 Q_UNUSED(size)
395}
396
397void PlainTextMarkupBuilder::beginForeground(const QBrush &brush)
398{
399 Q_UNUSED(brush)
400}
401
402void PlainTextMarkupBuilder::beginHeader(int level)
403{
404 Q_D(PlainTextMarkupBuilder);
405 switch (level) {
406 case 1:
407 d->mText.append(QStringLiteral("# "));
408 break;
409 case 2:
410 d->mText.append(QStringLiteral("## "));
411 break;
412 case 3:
413 d->mText.append(QStringLiteral("### "));
414 break;
415 case 4:
416 d->mText.append(QStringLiteral("#### "));
417 break;
418 case 5:
419 d->mText.append(QStringLiteral("##### "));
420 break;
421 case 6:
422 d->mText.append(QStringLiteral("###### "));
423 break;
424 default:
425 break;
426 }
427}
428
429void PlainTextMarkupBuilder::beginTable(qreal cellpadding, qreal cellspacing, const QString &width)
430{
431 Q_UNUSED(cellpadding)
432 Q_UNUSED(cellspacing)
433 Q_UNUSED(width)
434}
435
436void PlainTextMarkupBuilder::beginTableCell(const QString &width, int colSpan, int rowSpan)
437{
438 Q_UNUSED(width)
439 Q_UNUSED(colSpan)
440 Q_UNUSED(rowSpan)
441}
442
443void PlainTextMarkupBuilder::beginTableHeaderCell(const QString &width, int colSpan, int rowSpan)
444{
445 Q_UNUSED(width)
446 Q_UNUSED(colSpan)
447 Q_UNUSED(rowSpan)
448}
449
450void PlainTextMarkupBuilder::beginTableRow()
451{
452}
453
454void PlainTextMarkupBuilder::endBackground()
455{
456}
457
458void PlainTextMarkupBuilder::endFontFamily()
459{
460}
461
462void PlainTextMarkupBuilder::endFontPointSize()
463{
464}
465
466void PlainTextMarkupBuilder::endForeground()
467{
468}
469
470void PlainTextMarkupBuilder::endHeader(int level)
471{
472 Q_D(PlainTextMarkupBuilder);
473 qDebug() << " void PlainTextMarkupBuilder::endHeader(int level)" << level;
474 switch (level) {
475 case 1:
476 d->mText.append(QStringLiteral(" #\n"));
477 break;
478 case 2:
479 d->mText.append(QStringLiteral(" ##\n"));
480 break;
481 case 3:
482 d->mText.append(QStringLiteral(" ###\n"));
483 break;
484 case 4:
485 d->mText.append(QStringLiteral(" ####\n"));
486 break;
487 case 5:
488 d->mText.append(QStringLiteral(" #####\n"));
489 break;
490 case 6:
491 d->mText.append(QStringLiteral(" ######\n"));
492 break;
493 default:
494 break;
495 }
496}
497
498void PlainTextMarkupBuilder::endTable()
499{
500}
501
502void PlainTextMarkupBuilder::endTableCell()
503{
504}
505
506void PlainTextMarkupBuilder::endTableHeaderCell()
507{
508}
509
510void PlainTextMarkupBuilder::endTableRow()
511{
512}
513
514void PlainTextMarkupBuilder::addSingleBreakLine()
515{
516 Q_D(PlainTextMarkupBuilder);
517 d->mText.append(QLatin1Char('\n'));
518}
QStringView level(QStringView ifopt)
bool isEmpty() const const
value_type takeFirst()
QString & append(QChar ch)
QString & prepend(QChar ch)
QStringView mid(qsizetype start, qsizetype length) const const
QString toString() const const
typedef Alignment
QTextStream & left(QTextStream &stream)
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.