File indexing completed on 2025-01-26 04:15:00
0001 /* 0002 * Copyright (C) 2020 Dan Leinir Turthra Jensen <admin@leinir.dk> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public 0015 * License along with this library; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0017 * 0018 */ 0019 0020 #include "TextDocumentEditor.h" 0021 0022 #include <QQuickTextDocument> 0023 #include <QTextBlock> 0024 0025 class TextDocumentEditor::Private { 0026 public: 0027 Private() {} 0028 QQuickTextDocument* textDocument{nullptr}; 0029 }; 0030 0031 TextDocumentEditor::TextDocumentEditor(QObject* parent) 0032 : QObject(parent) 0033 , d(new Private) 0034 { 0035 } 0036 0037 TextDocumentEditor::~TextDocumentEditor() = default; 0038 0039 QObject * TextDocumentEditor::textDocument() const 0040 { 0041 return d->textDocument; 0042 } 0043 0044 void TextDocumentEditor::setTextDocument(QObject* textDocument) 0045 { 0046 if (d->textDocument != textDocument) { 0047 d->textDocument = qobject_cast<QQuickTextDocument*>(textDocument); 0048 Q_EMIT textDocumentChanged(); 0049 } 0050 } 0051 0052 QPoint TextDocumentEditor::linkStartEnd(int cursorPosition) 0053 { 0054 QPoint point; 0055 if (d->textDocument) { 0056 QTextBlock block = d->textDocument->textDocument()->findBlock(cursorPosition); 0057 while (block.isValid() && block.contains(cursorPosition)) { 0058 // Don't be so heavy on large documents... 0059 qApp->processEvents(); 0060 QTextBlock::iterator it; 0061 for (it = block.begin(); !(it.atEnd()); ++it) { 0062 QTextFragment currentFragment = it.fragment(); 0063 if (currentFragment.isValid() && currentFragment.contains(cursorPosition)) { 0064 point.setX(currentFragment.position()); 0065 point.setY(currentFragment.position() + currentFragment.length()); 0066 break; 0067 } 0068 } 0069 block = block.next(); 0070 } 0071 } 0072 return point; 0073 } 0074 0075 QString TextDocumentEditor::linkText(int cursorPosition) 0076 { 0077 QString text; 0078 if (d->textDocument) { 0079 QTextBlock block = d->textDocument->textDocument()->findBlock(cursorPosition); 0080 while (block.isValid() && block.contains(cursorPosition)) { 0081 // Don't be so heavy on large documents... 0082 qApp->processEvents(); 0083 QTextBlock::iterator it; 0084 for (it = block.begin(); !(it.atEnd()); ++it) { 0085 QTextFragment currentFragment = it.fragment(); 0086 if (currentFragment.isValid() && currentFragment.contains(cursorPosition)) { 0087 text = currentFragment.text(); 0088 break; 0089 } 0090 } 0091 if (!text.isEmpty()) { 0092 break; 0093 } 0094 block = block.next(); 0095 } 0096 } 0097 return text; 0098 } 0099 0100 QString TextDocumentEditor::linkHref(int cursorPosition) 0101 { 0102 QString text; 0103 if (d->textDocument) { 0104 QTextBlock block = d->textDocument->textDocument()->findBlock(cursorPosition); 0105 while (block.isValid() && block.contains(cursorPosition)) { 0106 // Don't be so heavy on large documents... 0107 qApp->processEvents(); 0108 QTextBlock::iterator it; 0109 for (it = block.begin(); !(it.atEnd()); ++it) { 0110 QTextFragment currentFragment = it.fragment(); 0111 if (currentFragment.isValid() && currentFragment.contains(cursorPosition)) { 0112 text = currentFragment.charFormat().anchorHref(); 0113 break; 0114 } 0115 } 0116 if (!text.isEmpty()) { 0117 break; 0118 } 0119 block = block.next(); 0120 } 0121 } 0122 return text; 0123 } 0124 0125 QStringList TextDocumentEditor::paragraphs() const 0126 { 0127 QStringList paragraphs; 0128 if (d->textDocument) { 0129 QTextBlock block = d->textDocument->textDocument()->firstBlock(); 0130 while (block.isValid()) { 0131 QString paragraph; 0132 QStringList tagStack; 0133 QTextBlock::iterator it; 0134 for (it = block.begin(); !(it.atEnd()); ++it) { 0135 QTextFragment fragment = it.fragment(); 0136 if (fragment.isValid()) { 0137 QTextCharFormat format = fragment.charFormat(); 0138 if (fragment.isValid()) { 0139 QStringList endStack; 0140 // First set all the tags that ACBF supports, and add the tags we need to close to our tag stack 0141 // <strong>...</strong> 0142 if (format.fontWeight() == QFont::Bold) { 0143 paragraph += "<strong>"; 0144 endStack << "</strong>"; 0145 } 0146 // <emphasis>...</emphasis> 0147 if (format.fontItalic()) { 0148 paragraph += "<emphasis>"; 0149 endStack << "</emphasis>"; 0150 } 0151 // <strikethrough>...</strikethrough> 0152 if (format.fontStrikeOut()) { 0153 paragraph += "<strikethrough>"; 0154 endStack << "</strikethrough>"; 0155 } 0156 // <sub>...</sub> 0157 if (format.verticalAlignment() == QTextCharFormat::AlignSubScript) { 0158 paragraph += "<sub>"; 0159 endStack << "</sub>"; 0160 } 0161 // <sup>...</sup> 0162 if (format.verticalAlignment() == QTextCharFormat::AlignSuperScript) { 0163 paragraph += "<sup>"; 0164 endStack << "</sup>"; 0165 } 0166 // <a href="">...</a> 0167 if (format.isAnchor()) { 0168 paragraph += QString("<a href=\"%1\">").arg(format.anchorHref().toHtmlEscaped()); 0169 endStack << "</a>"; 0170 } 0171 0172 // Add in the fragment's text contents 0173 paragraph += fragment.text().toHtmlEscaped(); 0174 0175 // Finally, close our own tags again, from the inside 0176 while (endStack.count() > 0) { 0177 paragraph += endStack.takeLast(); 0178 } 0179 } 0180 } 0181 } 0182 paragraphs << paragraph; 0183 block = block.next(); 0184 } 0185 } 0186 return paragraphs; 0187 }