File indexing completed on 2024-05-19 04:48:09

0001 /****************************************************************************
0002  * *
0003  ** Copyright (C) 2017 The Qt Company Ltd.
0004  ** Contact: https://www.qt.io/licensing/
0005  **
0006  ** This file is part of the examples of the Qt Toolkit.
0007  **
0008  ** $QT_BEGIN_LICENSE:BSD$
0009  ** Commercial License Usage
0010  ** Licensees holding valid commercial Qt licenses may use this file in
0011  ** accordance with the commercial license agreement provided with the
0012  ** Software or, alternatively, in accordance with the terms contained in
0013  ** a written agreement between you and The Qt Company. For licensing terms
0014  ** and conditions see https://www.qt.io/terms-conditions. For further
0015  ** information use the contact form at https://www.qt.io/contact-us.
0016  **
0017  ** BSD License Usage
0018  ** Alternatively, you may use this file under the terms of the BSD license
0019  ** as follows:
0020  **
0021  ** "Redistribution and use in source and binary forms, with or without
0022  ** modification, are permitted provided that the following conditions are
0023  ** met:
0024  **   * Redistributions of source code must retain the above copyright
0025  **     notice, this list of conditions and the following disclaimer.
0026  **   * Redistributions in binary form must reproduce the above copyright
0027  **     notice, this list of conditions and the following disclaimer in
0028  **     the documentation and/or other materials provided with the
0029  **     distribution.
0030  **   * Neither the name of The Qt Company Ltd nor the names of its
0031  **     contributors may be used to endorse or promote products derived
0032  **     from this software without specific prior written permission.
0033  **
0034  **
0035  ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0036  ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0037  ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0038  ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0039  ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0040  ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0041  ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0042  ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0043  ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0044  ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0045  ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
0046  **
0047  ** $QT_END_LICENSE$
0048  **
0049  ****************************************************************************/
0050 
0051 #pragma once
0052 
0053 #include <QAbstractListModel>
0054 #include <QDebug>
0055 #include <QFont>
0056 #include <QObject>
0057 #include <QTextCursor>
0058 #include <QThread>
0059 #include <QTimer>
0060 #include <QUrl>
0061 
0062 QT_BEGIN_NAMESPACE
0063 class QFileSystemWatcher;
0064 class QTextDocument;
0065 class QQuickTextDocument;
0066 QT_END_NAMESPACE
0067 
0068 namespace KSyntaxHighlighting
0069 {
0070 class Repository;
0071 class SyntaxHighlighter;
0072 }
0073 
0074 /**
0075  * @brief The AlertAction struct
0076  */
0077 struct AlertAction {
0078     QString label;
0079     std::function<void()> action;
0080 };
0081 
0082 /**
0083  * @brief The DocumentAlert class
0084  */
0085 class DocumentAlert : public QObject
0086 {
0087     Q_OBJECT
0088     Q_PROPERTY(QString title MEMBER m_title CONSTANT FINAL)
0089     Q_PROPERTY(QString body MEMBER m_body CONSTANT FINAL)
0090     Q_PROPERTY(uint level MEMBER m_level CONSTANT FINAL)
0091     Q_PROPERTY(QStringList actionLabels READ actionLabels CONSTANT FINAL)
0092     
0093 public:
0094     enum LEVEL : uint { INFO_LEVEL = 0, WARNING_LEVEL = 1, DANGER_LEVEL = 2 };
0095 
0096     DocumentAlert(const QString &title, const QString &body, const uint &level, const int &id, QObject *parent = nullptr)
0097         : QObject(parent)
0098     {
0099         this->m_title = title;
0100         this->m_body = body;
0101         this->m_level = level;
0102         this->m_id = id;
0103     }
0104 
0105     /**
0106      * @brief setIndex
0107      * @param index
0108      */
0109     void setIndex(const int &index)
0110     {
0111         this->m_index = index;
0112     }
0113 
0114     /**
0115      * @brief setActions
0116      * @param actions
0117      */
0118     void setActions(QVector<AlertAction> actions)
0119     {
0120         this->m_actions = actions;
0121     }
0122 
0123     /**
0124      * @brief getId
0125      * @return
0126      */
0127     int getId() const
0128     {
0129         return this->m_id;
0130     }
0131 
0132     /**
0133      * @brief operator ==
0134      * @param other
0135      * @param other2
0136      * @return
0137      */
0138     friend bool operator==(const DocumentAlert &other, const DocumentAlert &other2)
0139     {
0140         return other.getId() == other2.getId();
0141     }
0142 
0143     /**
0144      * @brief actionLabels
0145      * @return
0146      */
0147     QStringList actionLabels() const
0148     {
0149         return std::accumulate(this->m_actions.constBegin(), this->m_actions.constEnd(), QStringList(), [](QStringList &labels, const AlertAction &action) -> QStringList {
0150             labels << action.label;
0151             return labels;
0152         });
0153     }
0154 
0155 private:
0156     QString m_title;
0157     QString m_body;
0158     uint m_level;
0159     int m_index = -1;
0160     int m_id = -1;
0161 
0162     QVector<AlertAction> m_actions;
0163 
0164 public Q_SLOTS:
0165     /**
0166      * @brief triggerAction
0167      * @param actionIndex
0168      * @param alertIndex
0169      */
0170     void triggerAction(const int &actionIndex, const int &alertIndex)
0171     {
0172         qDebug() << "TRIGGERING DOCUMENT ACTION AT INDEX << " << actionIndex << alertIndex;
0173         this->m_actions.at(actionIndex).action();
0174         Q_EMIT this->done(alertIndex);
0175     }
0176 
0177 Q_SIGNALS:
0178     /**
0179      * @brief done
0180      * @param index
0181      */
0182     void done(int index);
0183 };
0184 
0185 /**
0186  * @brief The Alerts class
0187  */
0188 class Alerts : public QAbstractListModel
0189 {
0190     Q_OBJECT
0191 
0192 public:
0193     enum ROLES : uint { ALERT = Qt::DisplayRole + 1 };
0194 
0195     enum ALERT_TYPES : uint { MISSING, UNSAVED, MODIFIED, SAVE_ERROR };
0196 
0197     explicit Alerts(QObject *parent = nullptr);
0198     ~Alerts();
0199     QVariant data(const QModelIndex &index, int role) const override final;
0200     int rowCount(const QModelIndex &parent = QModelIndex()) const override final;
0201     QHash<int, QByteArray> roleNames() const override;
0202 
0203     void append(DocumentAlert *alert);
0204 
0205 private:
0206     QVector<DocumentAlert *> m_alerts;
0207     bool contains(DocumentAlert *const alert);
0208 };
0209 
0210 /**
0211  * @brief The FileLoader class
0212  */
0213 class FileLoader : public QObject
0214 {
0215     Q_OBJECT
0216 
0217 public Q_SLOTS:
0218     /**
0219      * @brief loadFile
0220      * @param url
0221      */
0222     void loadFile(const QUrl &url);
0223 
0224 Q_SIGNALS:
0225     /**
0226      * @brief fileReady
0227      * @param array
0228      * @param url
0229      */
0230     void fileReady(QString array, QUrl url);
0231 };
0232 
0233 /**
0234  * @brief The DocumentHandler class
0235  */
0236 class DocumentHandler : public QObject
0237 {
0238     Q_OBJECT
0239 
0240     Q_PROPERTY(QQuickTextDocument *document READ document WRITE setDocument NOTIFY documentChanged)
0241     Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
0242     Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged)
0243     Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged)
0244 
0245     Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor NOTIFY textColorChanged)
0246     Q_PROPERTY(QString fontFamily READ fontFamily WRITE setFontFamily NOTIFY fontFamilyChanged)
0247     Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged)
0248 
0249     Q_PROPERTY(bool bold READ bold WRITE setBold NOTIFY boldChanged)
0250     Q_PROPERTY(bool uppercase READ uppercase WRITE setUppercase NOTIFY uppercaseChanged)
0251     Q_PROPERTY(bool italic READ italic WRITE setItalic NOTIFY italicChanged)
0252     Q_PROPERTY(bool underline READ underline WRITE setUnderline NOTIFY underlineChanged)
0253     Q_PROPERTY(bool isRich READ getIsRich NOTIFY isRichChanged)
0254 
0255     Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged)
0256     Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged)
0257     Q_PROPERTY(qreal tabSpace READ tabSpace WRITE setTabSpace NOTIFY tabSpaceChanged)
0258 
0259     Q_PROPERTY(QString fileName READ fileName NOTIFY fileUrlChanged)
0260     Q_PROPERTY(QString fileType READ fileType NOTIFY fileUrlChanged)
0261 
0262     Q_PROPERTY(QVariantMap fileInfo READ fileInfo NOTIFY fileInfoChanged)
0263     Q_PROPERTY(QUrl fileUrl READ fileUrl WRITE setFileUrl NOTIFY fileUrlChanged)
0264 
0265     Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
0266 
0267     Q_PROPERTY(bool externallyModified READ getExternallyModified WRITE setExternallyModified NOTIFY externallyModifiedChanged)
0268 
0269     Q_PROPERTY(bool modified READ getModified NOTIFY modifiedChanged)
0270 
0271     Q_PROPERTY(bool autoReload READ getAutoReload WRITE setAutoReload NOTIFY autoReloadChanged)
0272     Q_PROPERTY(bool autoSave READ autoSave WRITE setAutoSave NOTIFY autoSaveChanged)
0273 
0274     Q_PROPERTY(QString formatName READ formatName WRITE setFormatName NOTIFY formatNameChanged)
0275 
0276     Q_PROPERTY(int currentLineIndex READ getCurrentLineIndex NOTIFY currentLineIndexChanged)
0277 
0278     Q_PROPERTY(Alerts *alerts READ getAlerts CONSTANT FINAL)
0279 
0280     Q_PROPERTY(QColor backgroundColor READ getBackgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged)
0281 
0282     Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
0283 
0284     Q_PROPERTY(bool enableSyntaxHighlighting READ enableSyntaxHighlighting WRITE setEnableSyntaxHighlighting NOTIFY enableSyntaxHighlightingChanged)    
0285         
0286     Q_PROPERTY(bool findWholeWords MEMBER m_findWholeWords NOTIFY findWholeWordsChanged)    
0287     
0288     Q_PROPERTY(bool findCaseSensitively MEMBER m_findCaseSensitively NOTIFY findCaseSensitivelyChanged)
0289 
0290 public:
0291     explicit DocumentHandler(QObject *parent = nullptr);
0292     ~DocumentHandler();
0293 
0294     /**
0295      * @brief document
0296      * @return
0297      */
0298     QQuickTextDocument *document() const;
0299 
0300     /**
0301      * @brief setDocument
0302      * @param document
0303      */
0304     void setDocument(QQuickTextDocument *document);
0305 
0306     /**
0307      * @brief cursorPosition
0308      * @return
0309      */
0310     int cursorPosition() const;
0311 
0312     /**
0313      * @brief setCursorPosition
0314      * @param position
0315      */
0316     void setCursorPosition(int position);
0317 
0318     /**
0319      * @brief selectionStart
0320      * @return
0321      */
0322     int selectionStart() const;
0323 
0324     /**
0325      * @brief setSelectionStart
0326      * @param position
0327      */
0328     void setSelectionStart(int position);
0329 
0330     /**
0331      * @brief selectionEnd
0332      * @return
0333      */
0334     int selectionEnd() const;
0335 
0336     /**
0337      * @brief setSelectionEnd
0338      * @param position
0339      */
0340     void setSelectionEnd(int position);
0341 
0342     /**
0343      * @brief fontFamily
0344      * @return
0345      */
0346     QString fontFamily() const;
0347 
0348     /**
0349      * @brief setFontFamily
0350      * @param family
0351      */
0352     void setFontFamily(const QString &family);
0353 
0354     /**
0355      * @brief textColor
0356      * @return
0357      */
0358     QColor textColor() const;
0359 
0360     /**
0361      * @brief setTextColor
0362      * @param color
0363      */
0364     void setTextColor(const QColor &color);
0365 
0366     /**
0367      * @brief alignment
0368      * @return
0369      */
0370     Qt::Alignment alignment() const;
0371 
0372     /**
0373      * @brief setAlignment
0374      * @param alignment
0375      */
0376     void setAlignment(Qt::Alignment alignment);
0377 
0378     /**
0379      * @brief bold
0380      * @return
0381      */
0382     bool bold() const;
0383 
0384     /**
0385      * @brief setBold
0386      * @param bold
0387      */
0388     void setBold(bool bold);
0389 
0390     /**
0391      * @brief uppercase
0392      * @return
0393      */
0394     bool uppercase() const;
0395 
0396     /**
0397      * @brief setUppercase
0398      * @param uppercase
0399      */
0400     void setUppercase(bool uppercase);
0401 
0402     /**
0403      * @brief italic
0404      * @return
0405      */
0406     bool italic() const;
0407 
0408     /**
0409      * @brief setItalic
0410      * @param italic
0411      */
0412     void setItalic(bool italic);
0413 
0414     /**
0415      * @brief underline
0416      * @return
0417      */
0418     bool underline() const;
0419 
0420     /**
0421      * @brief setUnderline
0422      * @param underline
0423      */
0424     void setUnderline(bool underline);
0425 
0426     /**
0427      * @brief getIsRich
0428      * @return
0429      */
0430     bool getIsRich() const;
0431 
0432     /**
0433      * @brief fontSize
0434      * @return
0435      */
0436     int fontSize() const;
0437 
0438     /**
0439      * @brief setFontSize
0440      * @param size
0441      */
0442     void setFontSize(int size);
0443 
0444     qreal tabSpace() const;
0445     void setTabSpace(qreal value);
0446 
0447     /**
0448      * @brief fileName
0449      * @return
0450      */
0451     QString fileName() const;
0452 
0453     /**
0454      * @brief fileType
0455      * @return
0456      */
0457     QString fileType() const;
0458 
0459     /**
0460      * @brief fileUrl
0461      * @return
0462      */
0463     QUrl fileUrl() const;
0464 
0465     /**
0466      * @brief setFileUrl
0467      * @param url
0468      */
0469     void setFileUrl(const QUrl &url);
0470 
0471     /**
0472      * @brief fileInfo
0473      * @return
0474      */
0475     QVariantMap fileInfo() const;
0476 
0477     /**
0478      * @brief text
0479      * @return
0480      */
0481     inline QString text() const
0482     {
0483         return m_text;
0484     }
0485 
0486     /**
0487      * @brief setText
0488      * @param text
0489      */
0490     void setText(const QString &text);
0491 
0492     /**
0493      * @brief getAutoReload
0494      * @return
0495      */
0496     bool getAutoReload() const;
0497 
0498     /**
0499      * @brief setAutoReload
0500      * @param value
0501      */
0502     void setAutoReload(const bool &value);
0503 
0504     /**
0505      * @brief autoSave
0506      * @return
0507      */
0508     bool autoSave() const;
0509 
0510     /**
0511      * @brief setAutoSave
0512      * @param value
0513      */
0514     void setAutoSave(const bool &value);
0515 
0516     /**
0517      * @brief getModified
0518      * @return
0519      */
0520     bool getModified() const;
0521 
0522     /**
0523      * @brief getExternallyModified
0524      * @return
0525      */
0526     bool getExternallyModified() const;
0527 
0528     /**
0529      * @brief setExternallyModified
0530      * @param value
0531      */
0532     void setExternallyModified(const bool &value);
0533 
0534     /**
0535      * @brief formatName
0536      * @return
0537      */
0538     QString formatName() const;
0539 
0540     /**
0541      * @brief setFormatName
0542      * @param formatName
0543      */
0544     void setFormatName(const QString &formatName);
0545 
0546     /**
0547      * @brief getBackgroundColor
0548      * @return
0549      */
0550     QColor getBackgroundColor() const;
0551 
0552     /**
0553      * @brief setBackgroundColor
0554      * @param color
0555      */
0556     void setBackgroundColor(const QColor &color);
0557 
0558     /**
0559      * @brief getAlerts
0560      * @return
0561      */
0562     Alerts *getAlerts() const;
0563 
0564     /**
0565      * @brief theme
0566      * @return
0567      */
0568     QString theme() const;
0569 
0570     /**
0571      * @brief setTheme
0572      * @param theme
0573      */
0574     void setTheme(const QString &theme);
0575 
0576     /**
0577      * @brief enableSyntaxHighlighting
0578      * @return
0579      */
0580     bool enableSyntaxHighlighting() const;
0581 
0582     /**
0583      * @brief setEnableSyntaxHighlighting
0584      * @param value
0585      */
0586     void setEnableSyntaxHighlighting(const bool &value);
0587     
0588     /**
0589      * @brief isDark
0590      * @param color
0591      * @return
0592      */
0593     static bool isDark(const QColor &color)
0594     {
0595         const double darkness = 1 - (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
0596         return (darkness > 0.5);
0597     }
0598 
0599 public Q_SLOTS:
0600     /**
0601      * @brief load
0602      * @param url
0603      */
0604     void load(const QUrl &url);
0605 
0606     /**
0607      * @brief saveAs
0608      * @param url
0609      */
0610     void saveAs(const QUrl &url);
0611 
0612     /**
0613      * @brief find
0614      * @param query
0615      */
0616     void find(const QString &query, const bool &forward = true);
0617 
0618     void replace(const QString &query, const QString &value);
0619     
0620     void replaceAll(const QString &query, const QString &value);
0621     
0622     bool isFoldable(const int &line) const;
0623     bool isFolded(const int &line) const;
0624     void toggleFold(const int &line);
0625 
0626     /**
0627      * @brief lineHeight
0628      * @param line
0629      * @return
0630      */
0631     int lineHeight(const int &line);
0632     
0633     int lineCount();
0634 
0635     /**
0636      * @brief getCurrentLineIndex
0637      * @return
0638      */
0639     int getCurrentLineIndex();
0640     
0641     int goToLine(const int &line);
0642 
0643     /**
0644      * @brief getLanguageNameList
0645      * @return
0646      */
0647     static const QStringList getLanguageNameList();
0648 
0649     /**
0650      * @brief getLanguageNameFromFileName
0651      * @param fileName
0652      * @return
0653      */
0654     static const QString getLanguageNameFromFileName(const QUrl &fileName);
0655 
0656 Q_SIGNALS:
0657     void documentChanged();
0658     void fileSaved();
0659 
0660     void cursorPositionChanged();
0661     void selectionStartChanged();
0662     void selectionEndChanged();
0663 
0664     void fontFamilyChanged();
0665     void textColorChanged();
0666     void alignmentChanged();
0667 
0668     void boldChanged();
0669     void uppercaseChanged();
0670     void italicChanged();
0671     void underlineChanged();
0672     void isRichChanged();
0673 
0674     void lineCountChanged();
0675     void fontSizeChanged();
0676     void tabSpaceChanged();
0677 
0678     void textChanged();
0679     void fileUrlChanged();
0680     void fileInfoChanged();
0681 
0682     void loaded(const QUrl &url);
0683     void error(const QString &message);
0684     void loadFile(QUrl url);
0685 
0686     void autoReloadChanged();
0687     void autoSaveChanged();
0688 
0689     void externallyModifiedChanged();
0690 
0691     void backgroundColorChanged();
0692 
0693     void formatNameChanged();
0694 
0695     void modifiedChanged();
0696 
0697     void currentLineIndexChanged();
0698 
0699     void enableSyntaxHighlightingChanged();
0700     void themeChanged();
0701     
0702     void searchFound(int start, int end);
0703     void findCaseSensitivelyChanged();
0704     void findWholeWordsChanged();
0705 //     void cursorYPosChanged();
0706 
0707 private:
0708     void reset();
0709     void setStyle();
0710 
0711     QTextCursor textCursor() const;
0712     QTextDocument *textDocument() const;
0713     void mergeFormatOnWordOrSelection(const QTextCharFormat &format);
0714 
0715     QQuickTextDocument *m_document;
0716     QFileSystemWatcher *m_watcher;
0717 
0718     int m_cursorPosition;
0719     int m_selectionStart;
0720     int m_selectionEnd;
0721 
0722     bool isRich = false;
0723 
0724     QFont m_font;
0725     int m_fontSize = 12;
0726     qreal m_tabSpace = 8;
0727 
0728     QUrl m_fileUrl;
0729 
0730     QThread m_worker;
0731     QString m_text;
0732 
0733     bool m_autoReload = false;
0734     bool m_autoSave = false;
0735 
0736     bool m_externallyModified = false;
0737     bool m_internallyModified = false;
0738     
0739     bool m_findCaseSensitively = false;
0740     bool m_findWholeWords = false;
0741 
0742     QColor m_backgroundColor;
0743 
0744     static int m_instanceCount;
0745     QString m_formatName = "None";
0746     static KSyntaxHighlighting::Repository *m_repository;
0747     KSyntaxHighlighting::SyntaxHighlighter *m_highlighter;
0748 
0749     bool m_enableSyntaxHighlighting = false;
0750     QString m_theme;
0751     
0752     QString m_searchQuery;
0753     QString m_replaceText;
0754 
0755     Alerts *m_alerts;
0756     DocumentAlert *missingAlert();
0757     DocumentAlert *externallyModifiedAlert();
0758     DocumentAlert *canNotSaveAlert(const QString &details);
0759 
0760     QTimer m_autoSaveTimer;
0761     
0762     void refreshAllBlocks();
0763 };