#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include // RawView shows the raw UART output with timestamps, search (with next/ // previous navigation and wrap-around), tag suppression, unlimited history, // H+V scrolling and a copy-to-clipboard button. // A "Matches" panel (Ctrl+Shift+F) lists every line containing the search // text; entries can be multi-selected and copied (with timestamps by default) // or double-clicked to jump to the line in the log. // Auto-scroll is ON by default. class RawView : public QWidget { Q_OBJECT public: explicit RawView(QWidget *parent = nullptr); public slots: void appendLine(const QString &line, const QSet &suppressedTags = {}); void clear(); private slots: void onSearch(const QString &text); void onScrollValueChanged(int value); void onAutoScrollToggled(bool enabled); void copyToClipboard(); void findNext(); void findPrevious(); void toggleMatchPanel(bool show); void refreshMatches(); void updateMatchLabel(); void jumpToMatch(QListWidgetItem *item); void copySelectedMatches(); private: void setupUi(); void applyColorScheme(); // Searches for `text` starting at the current cursor, honouring `flags` // (e.g. QTextDocument::FindBackward). If nothing is found and // `wrapAllowed` is true, retries once from the start/end of the // document so search wraps around instead of dead-ending. bool searchAndSelect(const QString &text, QTextDocument::FindFlags flags, bool wrapAllowed); // Regex helpers: makeRegex() honours the "Aa" (match case) checkbox; // regexError() returns an empty string if the pattern is usable, else // a short reason (invalid syntax, or it matches empty text which would // make "find next" stall and match every line in the list). QRegularExpression makeRegex(const QString &text) const; static QString regexError(const QRegularExpression &re); QPlainTextEdit *m_textEdit = nullptr; QLineEdit *m_searchEdit = nullptr; QPushButton *m_findPrevBtn = nullptr; QPushButton *m_findNextBtn = nullptr; QPushButton *m_clearBtn = nullptr; QPushButton *m_copyBtn = nullptr; QCheckBox *m_autoScrollCb = nullptr; QLabel *m_lineCountLbl = nullptr; // Matches panel (list of all lines containing the search text) QPushButton *m_matchBtn = nullptr; QWidget *m_matchPanel = nullptr; QListWidget *m_matchList = nullptr; QLabel *m_matchCountLbl = nullptr; QCheckBox *m_caseCb = nullptr; // toolbar: "Aa" match case QCheckBox *m_regexCb = nullptr; // toolbar: "Regex" QString m_matchError; // non-empty = invalid regex QCheckBox *m_noTsCb = nullptr; QPushButton *m_refreshBtn = nullptr; QPushButton *m_selectAllBtn = nullptr; QPushButton *m_copyMatchBtn = nullptr; QTimer *m_matchTimer = nullptr; int m_matchTotal = 0; bool m_matchTruncated = false; bool m_autoScroll = true; // ON by default int m_lineCount = 0; static const QRegularExpression s_tagRe; };