Warning, file /office/marknote/src/documenthandler.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // SPDX-FileCopyrightText: 2017 The Qt Company Ltd.
0002 // SPDX-License-Identifier: BSD-3-Clause
0003 
0004 #include "documenthandler.h"
0005 
0006 #include <QDebug>
0007 #include <QFile>
0008 #include <QFileInfo>
0009 #include <QFileSelector>
0010 #include <QMimeDatabase>
0011 #include <QQmlFile>
0012 #include <QQmlFileSelector>
0013 #include <QQuickTextDocument>
0014 #include <QTextCharFormat>
0015 #include <QTextDocument>
0016 
0017 DocumentHandler::DocumentHandler(QObject *parent)
0018     : QObject(parent)
0019     , m_document(nullptr)
0020     , m_cursorPosition(-1)
0021     , m_selectionStart(0)
0022     , m_selectionEnd(0)
0023 {
0024 }
0025 
0026 QQuickTextDocument *DocumentHandler::document() const
0027 {
0028     return m_document;
0029 }
0030 
0031 void DocumentHandler::setDocument(QQuickTextDocument *document)
0032 {
0033     if (document == m_document)
0034         return;
0035 
0036     if (m_document)
0037         m_document->textDocument()->disconnect(this);
0038     m_document = document;
0039     if (m_document)
0040         connect(m_document->textDocument(), &QTextDocument::modificationChanged, this, &DocumentHandler::modifiedChanged);
0041     Q_EMIT documentChanged();
0042 }
0043 
0044 int DocumentHandler::cursorPosition() const
0045 {
0046     return m_cursorPosition;
0047 }
0048 
0049 void DocumentHandler::setCursorPosition(int position)
0050 {
0051     if (position == m_cursorPosition)
0052         return;
0053 
0054     m_cursorPosition = position;
0055     reset();
0056     Q_EMIT cursorPositionChanged();
0057 }
0058 
0059 int DocumentHandler::selectionStart() const
0060 {
0061     return m_selectionStart;
0062 }
0063 
0064 void DocumentHandler::setSelectionStart(int position)
0065 {
0066     if (position == m_selectionStart)
0067         return;
0068 
0069     m_selectionStart = position;
0070     Q_EMIT selectionStartChanged();
0071 }
0072 
0073 int DocumentHandler::selectionEnd() const
0074 {
0075     return m_selectionEnd;
0076 }
0077 
0078 void DocumentHandler::setSelectionEnd(int position)
0079 {
0080     if (position == m_selectionEnd)
0081         return;
0082 
0083     m_selectionEnd = position;
0084     Q_EMIT selectionEndChanged();
0085 }
0086 
0087 QString DocumentHandler::fontFamily() const
0088 {
0089     QTextCursor cursor = textCursor();
0090     if (cursor.isNull())
0091         return QString();
0092     QTextCharFormat format = cursor.charFormat();
0093     return format.font().family();
0094 }
0095 
0096 void DocumentHandler::setFontFamily(const QString &family)
0097 {
0098     QTextCharFormat format;
0099     format.setFontFamilies({family});
0100     mergeFormatOnWordOrSelection(format);
0101     Q_EMIT fontFamilyChanged();
0102 }
0103 
0104 QColor DocumentHandler::textColor() const
0105 {
0106     QTextCursor cursor = textCursor();
0107     if (cursor.isNull())
0108         return QColor(Qt::black);
0109     QTextCharFormat format = cursor.charFormat();
0110     return format.foreground().color();
0111 }
0112 
0113 void DocumentHandler::setTextColor(const QColor &color)
0114 {
0115     QTextCharFormat format;
0116     format.setForeground(QBrush(color));
0117     mergeFormatOnWordOrSelection(format);
0118     Q_EMIT textColorChanged();
0119 }
0120 
0121 Qt::Alignment DocumentHandler::alignment() const
0122 {
0123     QTextCursor cursor = textCursor();
0124     if (cursor.isNull())
0125         return Qt::AlignLeft;
0126     return textCursor().blockFormat().alignment();
0127 }
0128 
0129 void DocumentHandler::setAlignment(Qt::Alignment alignment)
0130 {
0131     QTextBlockFormat format;
0132     format.setAlignment(alignment);
0133     QTextCursor cursor = textCursor();
0134     cursor.mergeBlockFormat(format);
0135     Q_EMIT alignmentChanged();
0136 }
0137 
0138 bool DocumentHandler::bold() const
0139 {
0140     QTextCursor cursor = textCursor();
0141     if (cursor.isNull())
0142         return false;
0143     return textCursor().charFormat().fontWeight() == QFont::Bold;
0144 }
0145 
0146 void DocumentHandler::setBold(bool bold)
0147 {
0148     QTextCharFormat format;
0149     format.setFontWeight(bold ? QFont::Bold : QFont::Normal);
0150     mergeFormatOnWordOrSelection(format);
0151     Q_EMIT boldChanged();
0152 }
0153 
0154 bool DocumentHandler::italic() const
0155 {
0156     QTextCursor cursor = textCursor();
0157     if (cursor.isNull())
0158         return false;
0159     return textCursor().charFormat().fontItalic();
0160 }
0161 
0162 void DocumentHandler::setItalic(bool italic)
0163 {
0164     QTextCharFormat format;
0165     format.setFontItalic(italic);
0166     mergeFormatOnWordOrSelection(format);
0167     Q_EMIT italicChanged();
0168 }
0169 
0170 bool DocumentHandler::underline() const
0171 {
0172     QTextCursor cursor = textCursor();
0173     if (cursor.isNull())
0174         return false;
0175     return textCursor().charFormat().fontUnderline();
0176 }
0177 
0178 void DocumentHandler::setUnderline(bool underline)
0179 {
0180     QTextCharFormat format;
0181     format.setFontUnderline(underline);
0182     mergeFormatOnWordOrSelection(format);
0183     Q_EMIT underlineChanged();
0184 }
0185 
0186 int DocumentHandler::fontSize() const
0187 {
0188     QTextCursor cursor = textCursor();
0189     if (cursor.isNull())
0190         return 0;
0191     QTextCharFormat format = cursor.charFormat();
0192     return format.font().pointSize();
0193 }
0194 
0195 void DocumentHandler::setFontSize(int size)
0196 {
0197     if (size <= 0)
0198         return;
0199 
0200     QTextCursor cursor = textCursor();
0201     if (cursor.isNull())
0202         return;
0203 
0204     if (!cursor.hasSelection())
0205         cursor.select(QTextCursor::WordUnderCursor);
0206 
0207     if (cursor.charFormat().property(QTextFormat::FontPointSize).toInt() == size)
0208         return;
0209 
0210     QTextCharFormat format;
0211     format.setFontPointSize(size);
0212     mergeFormatOnWordOrSelection(format);
0213     Q_EMIT fontSizeChanged();
0214 }
0215 
0216 QString DocumentHandler::fileName() const
0217 {
0218     const QString filePath = QQmlFile::urlToLocalFileOrQrc(m_fileUrl);
0219     const QString fileName = QFileInfo(filePath).fileName();
0220     if (fileName.isEmpty())
0221         return QStringLiteral("untitled.txt");
0222     return fileName;
0223 }
0224 
0225 QString DocumentHandler::fileType() const
0226 {
0227     return QFileInfo(fileName()).suffix();
0228 }
0229 
0230 QUrl DocumentHandler::fileUrl() const
0231 {
0232     return m_fileUrl;
0233 }
0234 
0235 void DocumentHandler::load(const QUrl &fileUrl)
0236 {
0237     if (fileUrl == m_fileUrl)
0238         return;
0239 
0240     QQmlEngine *engine = qmlEngine(this);
0241     if (!engine) {
0242         qWarning() << "load() called before DocumentHandler has QQmlEngine";
0243         return;
0244     }
0245 
0246     const QUrl path = QQmlFileSelector::get(engine)->selector()->select(fileUrl);
0247     const QString fileName = QQmlFile::urlToLocalFileOrQrc(path);
0248     if (QFile::exists(fileName)) {
0249         QFile file(fileName);
0250         if (file.open(QFile::ReadOnly)) {
0251             QByteArray data = file.readAll();
0252             if (QTextDocument *doc = textDocument()) {
0253                 doc->setBaseUrl(path.adjusted(QUrl::RemoveFilename));
0254                 Q_EMIT loaded(QString::fromUtf8(data), Qt::MarkdownText);
0255                 doc->setModified(false);
0256             }
0257 
0258             reset();
0259         }
0260     }
0261 
0262     m_fileUrl = fileUrl;
0263     Q_EMIT fileUrlChanged();
0264 }
0265 
0266 void DocumentHandler::saveAs(const QUrl &fileUrl)
0267 {
0268     QTextDocument *doc = textDocument();
0269     if (!doc)
0270         return;
0271 
0272     const QString filePath = fileUrl.toLocalFile();
0273     QFile file(filePath);
0274     if (!file.open(QFile::WriteOnly | QFile::Truncate)) {
0275         Q_EMIT error(tr("Cannot save: ") + file.errorString());
0276         return;
0277     }
0278     file.write(doc->toMarkdown().toUtf8());
0279     file.close();
0280 
0281     if (fileUrl == m_fileUrl)
0282         return;
0283 
0284     m_fileUrl = fileUrl;
0285     Q_EMIT fileUrlChanged();
0286 }
0287 
0288 void DocumentHandler::reset()
0289 {
0290     Q_EMIT fontFamilyChanged();
0291     Q_EMIT alignmentChanged();
0292     Q_EMIT boldChanged();
0293     Q_EMIT italicChanged();
0294     Q_EMIT underlineChanged();
0295     Q_EMIT fontSizeChanged();
0296     Q_EMIT textColorChanged();
0297 }
0298 
0299 QTextCursor DocumentHandler::textCursor() const
0300 {
0301     QTextDocument *doc = textDocument();
0302     if (!doc)
0303         return QTextCursor();
0304 
0305     QTextCursor cursor = QTextCursor(doc);
0306     if (m_selectionStart != m_selectionEnd) {
0307         cursor.setPosition(m_selectionStart);
0308         cursor.setPosition(m_selectionEnd, QTextCursor::KeepAnchor);
0309     } else {
0310         cursor.setPosition(m_cursorPosition);
0311     }
0312     return cursor;
0313 }
0314 
0315 QTextDocument *DocumentHandler::textDocument() const
0316 {
0317     if (!m_document)
0318         return nullptr;
0319 
0320     return m_document->textDocument();
0321 }
0322 
0323 void DocumentHandler::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
0324 {
0325     QTextCursor cursor = textCursor();
0326     if (!cursor.hasSelection())
0327         cursor.select(QTextCursor::WordUnderCursor);
0328     cursor.mergeCharFormat(format);
0329 }
0330 
0331 bool DocumentHandler::modified() const
0332 {
0333     return m_document && m_document->textDocument()->isModified();
0334 }
0335 
0336 void DocumentHandler::setModified(bool m)
0337 {
0338     if (m_document)
0339         m_document->textDocument()->setModified(m);
0340 }