File indexing completed on 2024-05-12 16:59:35

0001 /*
0002     This file is part of the Qt Quick Controls module of the Qt Toolkit.
0003     SPDX-FileCopyrightText: 2013 Digia Plc and /or its subsidiary(-ies) <http://www.qt-project.org/legal>
0004 
0005     SPDX-License-Identifier: BSD-3-Clause
0006  */
0007 
0008 /*
0009  * This file was imported from Qt into Plasma
0010  * I expect this to become public API at some point
0011  * at which point we should delete this
0012  */
0013 
0014 #include "documenthandler.h"
0015 
0016 #include <QClipboard>
0017 #include <QFontDatabase>
0018 #include <QGuiApplication>
0019 #include <QMimeData>
0020 #include <QTextCursor>
0021 #include <QTextDocument>
0022 #include <QTextDocumentFragment>
0023 
0024 #include <KTextToHTML>
0025 
0026 DocumentHandler::DocumentHandler()
0027     : m_target(nullptr)
0028     , m_doc(nullptr)
0029     , m_cursorPosition(-1)
0030     , m_selectionStart(0)
0031     , m_selectionEnd(0)
0032 {
0033 }
0034 
0035 void DocumentHandler::setTarget(QQuickItem *target)
0036 {
0037     m_doc = nullptr;
0038     m_target = target;
0039     if (!m_target) {
0040         return;
0041     }
0042 
0043     QVariant doc = m_target->property("textDocument");
0044     if (doc.canConvert<QQuickTextDocument *>()) {
0045         QQuickTextDocument *qqdoc = doc.value<QQuickTextDocument *>();
0046         if (qqdoc) {
0047             m_doc = qqdoc->textDocument();
0048         }
0049     }
0050     Q_EMIT targetChanged();
0051 }
0052 
0053 QString DocumentHandler::documentTitle() const
0054 {
0055     return m_documentTitle;
0056 }
0057 
0058 void DocumentHandler::setDocumentTitle(QString arg)
0059 {
0060     if (m_documentTitle != arg) {
0061         m_documentTitle = arg;
0062         Q_EMIT documentTitleChanged();
0063     }
0064 }
0065 
0066 void DocumentHandler::pasteWithoutFormatting()
0067 {
0068     QTextCursor cursor = textCursor();
0069     if (cursor.isNull()) {
0070         return;
0071     }
0072 
0073     QClipboard *clipboard = QGuiApplication::clipboard();
0074     if (!clipboard) {
0075         return;
0076     }
0077 
0078     const QMimeData *mimeData = clipboard->mimeData();
0079     if (!mimeData) {
0080         return;
0081     }
0082 
0083     QString content = KTextToHTML::convertToHtml(mimeData->text(), KTextToHTML::Options(KTextToHTML::PreserveSpaces));
0084 
0085     if (content.endsWith("</a>", Qt::CaseInsensitive)) {
0086         content += " ";
0087     }
0088 
0089     cursor.insertHtml(content);
0090 }
0091 
0092 void DocumentHandler::setText(const QString &arg)
0093 {
0094     if (m_text != arg) {
0095         m_text = arg;
0096         Q_EMIT textChanged();
0097     }
0098 }
0099 
0100 QString DocumentHandler::text() const
0101 {
0102     return m_text;
0103 }
0104 
0105 void DocumentHandler::setCursorPosition(int position)
0106 {
0107     if (position == m_cursorPosition) {
0108         return;
0109     }
0110 
0111     m_cursorPosition = position;
0112 
0113     reset();
0114 }
0115 
0116 void DocumentHandler::reset()
0117 {
0118     Q_EMIT fontFamilyChanged();
0119     Q_EMIT alignmentChanged();
0120     Q_EMIT boldChanged();
0121     Q_EMIT italicChanged();
0122     Q_EMIT underlineChanged();
0123     Q_EMIT strikeOutChanged();
0124     Q_EMIT fontSizeChanged();
0125     Q_EMIT textColorChanged();
0126 }
0127 
0128 QTextCursor DocumentHandler::textCursor() const
0129 {
0130     if (!m_doc) {
0131         return QTextCursor();
0132     }
0133     QTextCursor cursor = QTextCursor(m_doc);
0134     if (m_selectionStart != m_selectionEnd) {
0135         cursor.setPosition(m_selectionStart);
0136         cursor.setPosition(m_selectionEnd, QTextCursor::KeepAnchor);
0137     } else {
0138         cursor.setPosition(m_cursorPosition);
0139     }
0140     return cursor;
0141 }
0142 
0143 void DocumentHandler::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
0144 {
0145     QTextCursor cursor = textCursor();
0146     if (!cursor.hasSelection()) {
0147         cursor.select(QTextCursor::WordUnderCursor);
0148     }
0149     cursor.mergeCharFormat(format);
0150 }
0151 
0152 void DocumentHandler::setSelectionStart(int position)
0153 {
0154     m_selectionStart = position;
0155 }
0156 
0157 void DocumentHandler::setSelectionEnd(int position)
0158 {
0159     m_selectionEnd = position;
0160 }
0161 
0162 void DocumentHandler::setAlignment(Qt::Alignment a)
0163 {
0164     QTextBlockFormat fmt;
0165     fmt.setAlignment((Qt::Alignment)a);
0166     QTextCursor cursor = QTextCursor(m_doc);
0167     cursor.setPosition(m_selectionStart, QTextCursor::MoveAnchor);
0168     cursor.setPosition(m_selectionEnd, QTextCursor::KeepAnchor);
0169     cursor.mergeBlockFormat(fmt);
0170     Q_EMIT alignmentChanged();
0171 }
0172 
0173 Qt::Alignment DocumentHandler::alignment() const
0174 {
0175     QTextCursor cursor = textCursor();
0176     if (cursor.isNull()) {
0177         return Qt::AlignLeft;
0178     }
0179     return textCursor().blockFormat().alignment();
0180 }
0181 
0182 bool DocumentHandler::bold() const
0183 {
0184     QTextCursor cursor = textCursor();
0185     if (cursor.isNull()) {
0186         return false;
0187     }
0188     return textCursor().charFormat().fontWeight() == QFont::Bold;
0189 }
0190 
0191 bool DocumentHandler::italic() const
0192 {
0193     QTextCursor cursor = textCursor();
0194     if (cursor.isNull()) {
0195         return false;
0196     }
0197     return textCursor().charFormat().fontItalic();
0198 }
0199 
0200 bool DocumentHandler::underline() const
0201 {
0202     QTextCursor cursor = textCursor();
0203     if (cursor.isNull()) {
0204         return false;
0205     }
0206     return textCursor().charFormat().fontUnderline();
0207 }
0208 
0209 bool DocumentHandler::strikeOut() const
0210 {
0211     QTextCursor cursor = textCursor();
0212     if (cursor.isNull()) {
0213         return false;
0214     }
0215     return textCursor().charFormat().fontStrikeOut();
0216 }
0217 
0218 void DocumentHandler::setBold(bool arg)
0219 {
0220     QTextCharFormat fmt;
0221     fmt.setFontWeight(arg ? QFont::Bold : QFont::Normal);
0222     mergeFormatOnWordOrSelection(fmt);
0223     Q_EMIT boldChanged();
0224 }
0225 
0226 void DocumentHandler::setItalic(bool arg)
0227 {
0228     QTextCharFormat fmt;
0229     fmt.setFontItalic(arg);
0230     mergeFormatOnWordOrSelection(fmt);
0231     Q_EMIT italicChanged();
0232 }
0233 
0234 void DocumentHandler::setUnderline(bool arg)
0235 {
0236     QTextCharFormat fmt;
0237     fmt.setFontUnderline(arg);
0238     mergeFormatOnWordOrSelection(fmt);
0239     Q_EMIT underlineChanged();
0240 }
0241 
0242 void DocumentHandler::setStrikeOut(bool arg)
0243 {
0244     QTextCharFormat fmt;
0245     fmt.setFontStrikeOut(arg);
0246     mergeFormatOnWordOrSelection(fmt);
0247     Q_EMIT strikeOutChanged();
0248 }
0249 
0250 int DocumentHandler::fontSize() const
0251 {
0252     QTextCursor cursor = textCursor();
0253     if (cursor.isNull()) {
0254         return 0;
0255     }
0256     QTextCharFormat format = cursor.charFormat();
0257     return format.font().pointSize();
0258 }
0259 
0260 void DocumentHandler::setFontSize(int arg)
0261 {
0262     QTextCursor cursor = textCursor();
0263     if (cursor.isNull()) {
0264         return;
0265     }
0266     QTextCharFormat format;
0267     format.setFontPointSize(arg);
0268     mergeFormatOnWordOrSelection(format);
0269     // Also set the block char format, otherwise the old block font will stay and
0270     // end up taking effect if the user deletes all the text.
0271     cursor.mergeBlockCharFormat(format);
0272 
0273     Q_EMIT fontSizeChanged();
0274 }
0275 
0276 int DocumentHandler::defaultFontSize() const
0277 {
0278     return m_doc ? m_doc->defaultFont().pointSize() : 0;
0279 }
0280 
0281 void DocumentHandler::setDefaultFontSize(int arg)
0282 {
0283     if (!m_doc) {
0284         return;
0285     }
0286 
0287     auto font = m_doc->defaultFont();
0288     font.setPointSize(arg);
0289     m_doc->setDefaultFont(font);
0290     Q_EMIT defaultFontSizeChanged();
0291 }
0292 
0293 QColor DocumentHandler::textColor() const
0294 {
0295     QTextCursor cursor = textCursor();
0296     if (cursor.isNull()) {
0297         return QColor(Qt::black);
0298     }
0299     QTextCharFormat format = cursor.charFormat();
0300     return format.foreground().color();
0301 }
0302 
0303 void DocumentHandler::setTextColor(const QColor &c)
0304 {
0305     QTextCursor cursor = textCursor();
0306     if (cursor.isNull()) {
0307         return;
0308     }
0309     QTextCharFormat format;
0310     format.setForeground(QBrush(c));
0311     mergeFormatOnWordOrSelection(format);
0312     Q_EMIT textColorChanged();
0313 }
0314 
0315 QString DocumentHandler::fontFamily() const
0316 {
0317     QTextCursor cursor = textCursor();
0318     if (cursor.isNull()) {
0319         return QString();
0320     }
0321     QTextCharFormat format = cursor.charFormat();
0322     return format.font().family();
0323 }
0324 
0325 void DocumentHandler::setFontFamily(const QString &arg)
0326 {
0327     QTextCursor cursor = textCursor();
0328     if (cursor.isNull()) {
0329         return;
0330     }
0331     QTextCharFormat format;
0332     format.setFontFamily(arg);
0333     mergeFormatOnWordOrSelection(format);
0334     Q_EMIT fontFamilyChanged();
0335 }
0336 
0337 QStringList DocumentHandler::defaultFontSizes() const
0338 {
0339     // uhm... this is quite ugly
0340     QStringList sizes;
0341     const QList<int> standardSizes = QFontDatabase::standardSizes();
0342     sizes.reserve(standardSizes.count());
0343     for (int size : standardSizes) {
0344         sizes.append(QString::number(size));
0345     }
0346     return sizes;
0347 }
0348 
0349 QString DocumentHandler::strip(const QString text)
0350 {
0351     return QTextDocumentFragment::fromHtml(text).toPlainText();
0352 }
0353 
0354 QString DocumentHandler::stripAndSimplify(const QString text)
0355 {
0356     QString myText = text;
0357     QString plainText = QTextDocumentFragment::fromHtml(myText).toPlainText();
0358     // Normalize all whitespace to increase the fuzziness of the match
0359     plainText = plainText.simplified();
0360     return plainText;
0361 }
0362 
0363 QString DocumentHandler::strippedClipboardText()
0364 {
0365     QClipboard *clipboard = QGuiApplication::clipboard();
0366     if (!clipboard) {
0367         return QString();
0368     }
0369 
0370     return stripAndSimplify(clipboard->text());
0371 }