File indexing completed on 2024-05-12 05:52:05
0001 /* 0002 SPDX-FileCopyrightText: 2019 Mark Nauwelaerts <mark.nauwelaerts@gmail.com> 0003 SPDX-FileCopyrightText: 2022 Waqar Ahmed <waqar.17a@gmail.com> 0004 SPDX-License-Identifier: MIT 0005 */ 0006 #pragma once 0007 0008 #include "kateprivate_export.h" 0009 0010 #include "diagnostic_types.h" 0011 0012 #include <QJsonObject> 0013 #include <QPainter> 0014 #include <QPointer> 0015 #include <QStandardItemModel> 0016 #include <QUrl> 0017 #include <QWidget> 0018 0019 #include <KColorScheme> 0020 #include <KXMLGUIClient> 0021 0022 #include <KTextEditor/Document> 0023 #include <KTextEditor/Range> 0024 0025 class KConfigGroup; 0026 class SessionDiagnosticSuppressions; 0027 class KateMainWindow; 0028 class QSortFilterProxyModel; 0029 class KateTextHintProvider; 0030 0031 namespace KTextEditor 0032 { 0033 class MainWindow; 0034 class Mark; 0035 class View; 0036 class MovingRange; 0037 } 0038 0039 class KATE_PRIVATE_EXPORT DiagnosticsProvider : public QObject 0040 { 0041 Q_OBJECT 0042 public: 0043 explicit DiagnosticsProvider(KTextEditor::MainWindow *mainWindow, QObject *parent = nullptr); 0044 0045 // Get suppressions 0046 // e.g json object 0047 /* 0048 * "suppressions": { 0049 * "rulename": ["filename_regex", "message regexp", "code regexp"], 0050 * } 0051 */ 0052 virtual QJsonObject suppressions(KTextEditor::Document *) const 0053 { 0054 return {}; 0055 } 0056 0057 /** 0058 * If @p filterTo is a valid provider than DiagnosticView will 0059 * filter out all diagnostics that are not from @p filterTo. 0060 */ 0061 void showDiagnosticsView(DiagnosticsProvider *filterTo = nullptr); 0062 0063 /** 0064 * If @p filterTo is a valid provider, then DiagnosticView will 0065 * filter out all diagnostics that are not from @p filterTo. 0066 */ 0067 void filterDiagnosticsViewTo(DiagnosticsProvider *filterTo); 0068 0069 /** 0070 * Whether diagnostics of this provider should be automatically cleared 0071 * when a document is closed 0072 */ 0073 void setPersistentDiagnostics(bool p) 0074 { 0075 m_persistentDiagnostics = p; 0076 } 0077 0078 bool persistentDiagnostics() const 0079 { 0080 return m_persistentDiagnostics; 0081 } 0082 0083 QString name; 0084 0085 Q_SIGNALS: 0086 /// emitted by provider when diags are available 0087 void diagnosticsAdded(const FileDiagnostics &); 0088 0089 /// emitted by provider 0090 /// DiagnosticView will remove diagnostics where provider is @p provider 0091 void requestClearDiagnostics(DiagnosticsProvider *provider); 0092 0093 /// Request fixes for given diagnostic 0094 /// @p data must be passed back when fixes are sent back via fixesAvailable() 0095 /// emitted by DiagnosticView 0096 void requestFixes(const QUrl &, const Diagnostic &, const QVariant &data); 0097 0098 /// emitted by provider when fixes are available 0099 void fixesAvailable(const QList<DiagnosticFix> &fixes, const QVariant &data); 0100 0101 /// emitted by provider to clear suppressions 0102 /// (as some state that the previously provided ones depend on may have changed 0103 void requestClearSuppressions(DiagnosticsProvider *provider); 0104 0105 private: 0106 friend class DiagnosticsView; 0107 class DiagnosticsView *diagnosticView; 0108 bool m_persistentDiagnostics = false; 0109 }; 0110 0111 class DiagTabOverlay : public QWidget 0112 { 0113 public: 0114 DiagTabOverlay(QWidget *parent) 0115 : QWidget(parent) 0116 , m_tabButton(parent) 0117 { 0118 if (!parent) { 0119 hide(); 0120 return; 0121 } 0122 setAttribute(Qt::WA_TransparentForMouseEvents, true); 0123 setGeometry(parent->geometry()); 0124 move({0, 0}); 0125 show(); 0126 raise(); 0127 } 0128 0129 void setActive(bool a) 0130 { 0131 if (m_tabButton && (m_active != a)) { 0132 m_active = a; 0133 if (m_tabButton->size() != size()) { 0134 resize(m_tabButton->size()); 0135 } 0136 update(); 0137 } 0138 } 0139 0140 protected: 0141 void paintEvent(QPaintEvent *) override 0142 { 0143 if (m_active) { 0144 QPainter p(this); 0145 p.setOpacity(0.25); 0146 p.setBrush(KColorScheme().foreground(KColorScheme::NeutralText)); 0147 p.setPen(Qt::NoPen); 0148 p.drawRect(rect().adjusted(1, 1, -1, -1)); 0149 } 0150 } 0151 0152 private: 0153 bool m_active = false; 0154 QWidget *m_tabButton = nullptr; 0155 }; 0156 0157 class DiagnosticsView : public QWidget, public KXMLGUIClient 0158 { 0159 Q_OBJECT 0160 friend class ForwardingTextHintProvider; 0161 0162 protected: 0163 explicit DiagnosticsView(QWidget *parent, KTextEditor::MainWindow *mainWindow); 0164 0165 public: 0166 static DiagnosticsView *instance(KTextEditor::MainWindow *mainWindow); 0167 ~DiagnosticsView(); 0168 0169 void registerDiagnosticsProvider(DiagnosticsProvider *provider); 0170 void unregisterDiagnosticsProvider(DiagnosticsProvider *provider); 0171 0172 void readSessionConfig(const KConfigGroup &config); 0173 void writeSessionConfig(KConfigGroup &config); 0174 0175 void onTextHint(KTextEditor::View *view, const KTextEditor::Cursor &position) const; 0176 0177 void showToolview(DiagnosticsProvider *filterTo = nullptr); 0178 void filterViewTo(DiagnosticsProvider *provider); 0179 0180 protected: 0181 void showEvent(QShowEvent *e) override; 0182 void handleEsc(QEvent *e); 0183 0184 private Q_SLOTS: 0185 void tabForToolViewAdded(QWidget *toolView, QWidget *tab); 0186 0187 private: 0188 void onFixesAvailable(const QList<DiagnosticFix> &fixes, const QVariant &data); 0189 void showFixesInMenu(const QList<DiagnosticFix> &fixes); 0190 void quickFix(); 0191 void moveDiagnosticsSelection(bool forward); 0192 void nextItem(); 0193 void previousItem(); 0194 void onDiagnosticsAdded(const FileDiagnostics &diagnostics); 0195 void clearDiagnosticsFromProvider(DiagnosticsProvider *provider) 0196 { 0197 clearDiagnosticsForStaleDocs({}, provider); 0198 } 0199 void clearDiagnosticsForStaleDocs(const QList<QString> &filesToKeep, DiagnosticsProvider *provider); 0200 void clearSuppressionsFromProvider(DiagnosticsProvider *provider); 0201 void onDocumentUrlChanged(); 0202 void updateDiagnosticsState(struct DocumentDiagnosticItem *&topItem); 0203 void updateMarks(const std::vector<QUrl> &urls = {}); 0204 void goToItemLocation(QModelIndex index); 0205 0206 void onViewChanged(KTextEditor::View *v); 0207 0208 void onDoubleClicked(const QModelIndex &index, bool quickFix = false); 0209 0210 void addMarks(KTextEditor::Document *doc, QStandardItem *item); 0211 void addMarksRec(KTextEditor::Document *doc, QStandardItem *item); 0212 void addMarks(KTextEditor::Document *doc); 0213 0214 Q_SLOT void clearAllMarks(KTextEditor::Document *doc); 0215 Q_SLOT void onMarkClicked(KTextEditor::Document *document, KTextEditor::Mark mark, bool &handled); 0216 0217 bool syncDiagnostics(KTextEditor::Document *document, int line, bool allowTop, bool doShow); 0218 void updateDiagnosticsSuppression(struct DocumentDiagnosticItem *topItem, KTextEditor::Document *doc, bool force = false); 0219 0220 void onContextMenuRequested(const QPoint &pos); 0221 0222 void setupDiagnosticViewToolbar(class QVBoxLayout *mainLayout); 0223 0224 int m_diagnosticsCount = 0; 0225 KTextEditor::MainWindow *const m_mainWindow; 0226 class QTreeView *const m_diagnosticsTree; 0227 class QToolButton *const m_clearButton; 0228 class QLineEdit *const m_filterLineEdit; 0229 class QComboBox *const m_providerCombo; 0230 class QToolButton *const m_errFilterBtn; 0231 class QToolButton *const m_warnFilterBtn; 0232 class KMessageWidget *const m_diagLimitReachedWarning; 0233 0234 class ProviderListModel *m_providerModel; 0235 0236 QStandardItemModel m_model; 0237 QSortFilterProxyModel *const m_proxy; 0238 std::vector<DiagnosticsProvider *> m_providers; 0239 std::unique_ptr<SessionDiagnosticSuppressions> m_sessionDiagnosticSuppressions; 0240 0241 QHash<KTextEditor::Document *, QList<KTextEditor::MovingRange *>> m_diagnosticsRanges; 0242 // applied marks 0243 QSet<KTextEditor::Document *> m_diagnosticsMarks; 0244 0245 QPointer<DiagTabOverlay> m_tabButtonOverlay; 0246 0247 QMetaObject::Connection posChangedConnection; 0248 QTimer *const m_posChangedTimer; 0249 QTimer *const m_filterChangedTimer; 0250 QTimer *const m_urlChangedTimer; 0251 std::unique_ptr<KateTextHintProvider> m_textHintProvider; 0252 int m_diagnosticLimit = 0; 0253 };