diff --git a/src/grantleebuilder/plaintextmarkupbuilder.cpp b/src/grantleebuilder/plaintextmarkupbuilder.cpp index f3c4c36..5665884 100644 --- a/src/grantleebuilder/plaintextmarkupbuilder.cpp +++ b/src/grantleebuilder/plaintextmarkupbuilder.cpp @@ -1,54 +1,459 @@ /* Copyright (c) 2019 Montel Laurent This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "plaintextmarkupbuilder.h" #include +namespace KPIMTextEdit { +class PlainTextMarkupBuilderPrivate +{ +public: + PlainTextMarkupBuilderPrivate(PlainTextMarkupBuilder *b) : q_ptr(b) {} + + /** + Get a letter string to represent a number. + + The numbers 1-26 are represented by a-z, and 27-52 by aa-az, 53-79 by + ba-bz + etc. + + @param The number to convert + @return The letter string representation of the number. + */ + QString getLetterString(int itemNumber); + + QString getRomanString(int itemNumber); + + /** + Gets a block of references in the body of the text. + This is an ordered list of links and images in the text. + */ + QString getReferences(); + + QStringList m_urls; + QList currentListItemStyles; + QList currentListItemNumbers; + + QString activeLink; + + QString m_text; + + PlainTextMarkupBuilder *q_ptr; + + Q_DECLARE_PUBLIC(PlainTextMarkupBuilder) +}; +} + using namespace KPIMTextEdit; PlainTextMarkupBuilder::PlainTextMarkupBuilder() + : d_ptr(new PlainTextMarkupBuilderPrivate(this)) +{ +} + +QString PlainTextMarkupBuilderPrivate::getRomanString(int item) +{ + QString result; + // Code based to gui/text/qtextlist.cpp + if (item < 5000) { + QString romanNumeral; + + // works for up to 4999 items + auto romanSymbols = QStringLiteral("iiivixxxlxcccdcmmmm"); + int c[] = {1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000}; + auto n = item; + for (auto i = 12; i >= 0; n %= c[i], i--) { + auto q = n / c[i]; + if (q > 0) { + auto startDigit = i + (i + 3) / 4; + int numDigits; + if (i % 4) { + // c[i] == 4|5|9|40|50|90|400|500|900 + if ((i - 2) % 4) { + // c[i] == 4|9|40|90|400|900 => with subtraction (IV, + // IX, XL, XC, + // ...) + numDigits = 2; + } else { + // c[i] == 5|50|500 (V, L, D) + numDigits = 1; + } + } else { + // c[i] == 1|10|100|1000 (I, II, III, X, XX, ...) + numDigits = q; + } + + romanNumeral.append(romanSymbols.mid(startDigit, numDigits)); + } + } + result = romanNumeral; + } else { + result = QStringLiteral("?"); + } + return result; +} + +QString PlainTextMarkupBuilderPrivate::getLetterString(int itemNumber) +{ + QString letterString; + while (true) { + // Create the letter string by prepending one char at a time. + // The itemNumber is converted to a number in the base 36 (number of + // letters + // in the + // alphabet plus 10) after being increased by 10 (to pass out the digits + // 0 + // to 9). + letterString.prepend(QStringLiteral("%1").arg( + (itemNumber % LETTERSINALPHABET) + DIGITSOFFSET, + 0, // no padding while building this string. + LETTERSINALPHABET + DIGITSOFFSET)); + if ((itemNumber >= LETTERSINALPHABET)) { + itemNumber = itemNumber / LETTERSINALPHABET; + itemNumber--; + } else { + break; + } + } + return letterString; +} + +QString PlainTextMarkupBuilderPrivate::getReferences() +{ + QString refs; + if (!m_urls.isEmpty()) { + refs.append(QStringLiteral("\n--------\n")); + + auto index = 1; + while (!m_urls.isEmpty()) { + refs.append( + QStringLiteral("[%1] %2\n").arg(index++).arg(m_urls.takeFirst())); + } + } + return refs; +} + + +PlainTextMarkupBuilder::~PlainTextMarkupBuilder() { delete d_ptr; } + +void PlainTextMarkupBuilder::beginStrong() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('*')); +} + +void PlainTextMarkupBuilder::endStrong() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('*')); +} + +void PlainTextMarkupBuilder::beginEmph() { + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('/')); +} + +void PlainTextMarkupBuilder::endEmph() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('/')); +} + +void PlainTextMarkupBuilder::beginUnderline() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('_')); +} + +void PlainTextMarkupBuilder::endUnderline() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('_')); +} + +void PlainTextMarkupBuilder::beginStrikeout() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('-')); +} + +void PlainTextMarkupBuilder::endStrikeout() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('-')); +} + +void PlainTextMarkupBuilder::beginAnchor(const QString &href, + const QString &name) +{ + Q_D(PlainTextMarkupBuilder); + Q_UNUSED(name); + if (!d->m_urls.contains(href)) { + d->m_urls.append(href); + } + d->activeLink = href; } +void PlainTextMarkupBuilder::endAnchor() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append( + QStringLiteral("[%1]").arg(d->m_urls.indexOf(d->activeLink) + 1)); +} + +void PlainTextMarkupBuilder::endParagraph() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('\n')); +} + +void PlainTextMarkupBuilder::addNewline() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('\n')); +} + +void PlainTextMarkupBuilder::insertHorizontalRule(int width) +{ + Q_UNUSED(width) + Q_D(PlainTextMarkupBuilder); + + d->m_text.append(QStringLiteral("--------------------\n")); +} -void PlainTextMarkupBuilder::beginParagraph(Qt::Alignment a, qreal top, qreal bottom, qreal left, qreal right) +int PlainTextMarkupBuilder::addReference(const QString &reference) +{ + Q_D(PlainTextMarkupBuilder); + + if (!d->m_urls.contains(reference)) + d->m_urls.append(reference); + return d->m_urls.indexOf(reference) + 1; +} + +void PlainTextMarkupBuilder::insertImage(const QString &src, qreal width, + qreal height) +{ + Q_D(PlainTextMarkupBuilder); + Q_UNUSED(width) + Q_UNUSED(height) + + auto ref = addReference(src); + + d->m_text.append(QStringLiteral("[%1]").arg(ref)); +} + +void PlainTextMarkupBuilder::beginList(QTextListFormat::Style style) +{ + Q_D(PlainTextMarkupBuilder); + d->currentListItemStyles.append(style); + d->currentListItemNumbers.append(0); +} + +void PlainTextMarkupBuilder::endList() +{ + Q_D(PlainTextMarkupBuilder); + if (!d->currentListItemNumbers.isEmpty()) { + d->currentListItemStyles.removeLast(); + d->currentListItemNumbers.removeLast(); + } +} + +void PlainTextMarkupBuilder::beginListItem() +{ + Q_D(PlainTextMarkupBuilder); + for (auto i = 0; i < d->currentListItemNumbers.size(); i++) { + d->m_text.append(QStringLiteral(" ")); + } + + auto itemNumber = d->currentListItemNumbers.last(); + + switch (d->currentListItemStyles.last()) { + case QTextListFormat::ListDisc: + d->m_text.append(QStringLiteral(" * ")); + break; + case QTextListFormat::ListCircle: + d->m_text.append(QStringLiteral(" o ")); + break; + case QTextListFormat::ListSquare: + d->m_text.append(QStringLiteral(" - ")); + break; + case QTextListFormat::ListDecimal: + d->m_text.append(QStringLiteral(" %1. ").arg(itemNumber + 1)); + break; + case QTextListFormat::ListLowerAlpha: + d->m_text.append( + QStringLiteral(" %1. ").arg(d->getLetterString(itemNumber))); + break; + case QTextListFormat::ListUpperAlpha: + d->m_text.append( + QStringLiteral(" %1. ").arg(d->getLetterString(itemNumber).toUpper())); + break; + case QTextListFormat::ListLowerRoman: + d->m_text.append( + QStringLiteral(" %1. ").arg(d->getRomanString(itemNumber + 1))); + break; + case QTextListFormat::ListUpperRoman: + d->m_text.append(QStringLiteral(" %1. ").arg( + d->getRomanString(itemNumber + 1).toUpper())); + break; + default: + break; + } +} + +void PlainTextMarkupBuilder::endListItem() +{ + Q_D(PlainTextMarkupBuilder); + d->currentListItemNumbers.last() = d->currentListItemNumbers.last() + 1; + d->m_text.append(QLatin1Char('\n')); +} + +void PlainTextMarkupBuilder::beginSuperscript() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QStringLiteral("^{")); +} + +void PlainTextMarkupBuilder::endSuperscript() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('}')); +} + +void PlainTextMarkupBuilder::beginSubscript() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QStringLiteral("_{")); +} + +void PlainTextMarkupBuilder::endSubscript() +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(QLatin1Char('}')); +} + +void PlainTextMarkupBuilder::appendLiteralText(const QString &text) +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(text); +} + +void PlainTextMarkupBuilder::appendRawText(const QString &text) +{ + Q_D(PlainTextMarkupBuilder); + d->m_text.append(text); +} + +QString PlainTextMarkupBuilder::getResult() +{ + Q_D(PlainTextMarkupBuilder); + auto ret = d->m_text; + ret.append(d->getReferences()); + d->m_text.clear(); + return ret; +} + +void PlainTextMarkupBuilder::beginParagraph(Qt::Alignment a, qreal top, + qreal bottom, qreal left, + qreal right) { Q_UNUSED(a); Q_UNUSED(top); Q_UNUSED(bottom); Q_UNUSED(left); Q_UNUSED(right); - //TODO - //qDebug() << " left " << left << right << bottom << top << a; } - bool PlainTextMarkupBuilder::isQuoteBlock(qreal top, qreal bottom, qreal left, qreal right) const { -/* + /* case Html_blockquote: margin[QTextHtmlParser::MarginTop] = 12; margin[QTextHtmlParser::MarginBottom] = 12; margin[QTextHtmlParser::MarginLeft] = 40; margin[QTextHtmlParser::MarginRight] = 40; break; */ //TODO return false; } + +void PlainTextMarkupBuilder::beginBackground(const QBrush &brush) +{ + Q_UNUSED(brush); +} + +void PlainTextMarkupBuilder::beginFontFamily(const QString &family) +{ + Q_UNUSED(family); +} + +void PlainTextMarkupBuilder::beginFontPointSize(int size) { Q_UNUSED(size); } + +void PlainTextMarkupBuilder::beginForeground(const QBrush &brush) +{ + Q_UNUSED(brush); +} + +void PlainTextMarkupBuilder::beginHeader(int level) { Q_UNUSED(level); } + +void PlainTextMarkupBuilder::beginTable(qreal cellpadding, qreal cellspacing, + const QString &width) +{ + Q_UNUSED(cellpadding); + Q_UNUSED(cellspacing); + Q_UNUSED(width); +} + +void PlainTextMarkupBuilder::beginTableCell(const QString &width, int colSpan, + int rowSpan) +{ + Q_UNUSED(width); + Q_UNUSED(colSpan); + Q_UNUSED(rowSpan); +} + +void PlainTextMarkupBuilder::beginTableHeaderCell(const QString &width, + int colSpan, int rowSpan) +{ + Q_UNUSED(width); + Q_UNUSED(colSpan); + Q_UNUSED(rowSpan); +} + +void PlainTextMarkupBuilder::beginTableRow() {} + +void PlainTextMarkupBuilder::endBackground() {} + +void PlainTextMarkupBuilder::endFontFamily() {} + +void PlainTextMarkupBuilder::endFontPointSize() {} + +void PlainTextMarkupBuilder::endForeground() {} + +void PlainTextMarkupBuilder::endHeader(int level) { Q_UNUSED(level) } + +void PlainTextMarkupBuilder::endTable() {} + +void PlainTextMarkupBuilder::endTableCell() {} + +void PlainTextMarkupBuilder::endTableHeaderCell() {} + +void PlainTextMarkupBuilder::endTableRow() {} diff --git a/src/grantleebuilder/plaintextmarkupbuilder.h b/src/grantleebuilder/plaintextmarkupbuilder.h index 0af242b..c7e052f 100644 --- a/src/grantleebuilder/plaintextmarkupbuilder.h +++ b/src/grantleebuilder/plaintextmarkupbuilder.h @@ -1,40 +1,131 @@ /* Copyright (c) 2019 Montel Laurent + based on grantlee PlainTextMarkupBuilder This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef PLAINTEXTMARKUPBUILDER_H #define PLAINTEXTMARKUPBUILDER_H #include "kpimtextedit_export.h" +#include #include namespace KPIMTextEdit { -class KPIMTEXTEDIT_EXPORT PlainTextMarkupBuilder : public Grantlee::PlainTextMarkupBuilder +class PlainTextMarkupBuilderPrivate; + +class KPIMTEXTEDIT_EXPORT PlainTextMarkupBuilder + : virtual public Grantlee::AbstractMarkupBuilder { public: + /** Construct a new PlainTextHTMLMarkupBuilder. */ PlainTextMarkupBuilder(); - void beginParagraph(Qt::Alignment a, qreal top, qreal bottom, qreal left, qreal right) override; -private: + ~PlainTextMarkupBuilder() 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 beginAnchor(const QString &href = QString(), + const QString &name = QString()) override; + + void endAnchor() override; + + void beginParagraph(Qt::Alignment a = Qt::AlignLeft, qreal top = 0.0, + qreal bottom = 0.0, qreal left = 0.0, + qreal right = 0.0) override; + + void endParagraph() override; + void addNewline() override; + + void insertHorizontalRule(int width = -1) override; + + void insertImage(const QString &src, qreal width, qreal height) override; + + void beginList(QTextListFormat::Style style) override; + + void endList() override; + + void beginListItem() override; + + void endListItem() override; + + void beginSuperscript() override; + + void endSuperscript() override; + + void beginSubscript() override; + + void endSubscript() override; + + void beginTable(qreal cellpadding, qreal cellspacing, + const QString &width) override; + + void beginTableRow() override; + + void beginTableHeaderCell(const QString &width, int colSpan, + int rowSpan) override; + + void beginTableCell(const QString &width, int colSpan, int rowSpan) override; + + void appendLiteralText(const QString &text) override; + + void appendRawText(const QString &text) override; + + /** + Adds a reference to @p reference to the internal list of references in the + document. + */ + int addReference(const QString &reference); + + /** + Returns the finalised plain text markup, including references at the end. + */ + QString getResult() override; + bool isQuoteBlock(qreal top, qreal bottom, qreal left, qreal right) const; + + void beginForeground(const QBrush &brush) override; + void endForeground() override; + void beginBackground(const QBrush &brush) override; + void endBackground() override; + void beginFontFamily(const QString &family) override; + void endFontFamily() override; + void beginFontPointSize(int size) override; + void endFontPointSize() override; + void endTable() override; + void endTableRow() override; + void endTableHeaderCell() override; + void endTableCell() override; + void beginHeader(int level) override; + void endHeader(int level) override; +private: + PlainTextMarkupBuilderPrivate *const d_ptr; + Q_DECLARE_PRIVATE(PlainTextMarkupBuilder) + }; } #endif // PLAINTEXTMARKUPBUILDER_H