7#include <QRegularExpression>
15 searchLineEdit =
new QLineEdit(
this);
16 searchLineEdit->setObjectName(
"searchLineEdit");
17 searchLineEdit->setPlaceholderText(tr(
"Filter log lines (case insensitive)..."));
18 searchLineEdit->setClearButtonEnabled(
true);
20 clearButton =
new QToolButton(
this);
21 clearButton->setObjectName(
"clearButton");
22 clearButton->setIcon(style()->standardIcon(QStyle::SP_DialogResetButton));
23 clearButton->setToolTip(tr(
"Clear Log"));
24 clearButton->setText(tr(
"Clear"));
26 clearButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
27 clearButton->setEnabled(
true);
29 saveButton =
new QToolButton(
this);
30 saveButton->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton));
31 saveButton->setToolTip(tr(
"Save Log to File"));
32 saveButton->setEnabled(
true);
36 auto* topBarLayout =
new QHBoxLayout;
37 topBarLayout->addWidget(searchLineEdit);
38 topBarLayout->addWidget(clearButton);
39 topBarLayout->addWidget(saveButton);
40 topBarLayout->setSpacing(5);
44 logTextEdit =
new QTextEdit(
this);
45 logTextEdit->setAcceptRichText(
true);
46 logTextEdit->setReadOnly(
true);
47 logTextEdit->setMinimumHeight(200);
48 logTextEdit->setMinimumWidth(400);
50 auto* layout =
new QVBoxLayout(
this);
51 layout->addLayout(topBarLayout);
52 layout->addWidget(logTextEdit, 1);
57 connect(searchLineEdit, &QLineEdit::textChanged,
this, &GBoard::filterLog);
58 connect(clearButton, &QToolButton::clicked,
this, &GBoard::clearLog);
59 connect(saveButton, &QToolButton::clicked,
this, &GBoard::saveLog);
61 log->info(1,
"GBoard initialized");
66 if (QThread::currentThread() != thread()) {
67 QMetaObject::invokeMethod(
this, [
this, htmlFragment]() {
appendLog(htmlFragment); });
70 if (htmlFragment.trimmed().isEmpty()) {
return; }
74 fullLogLines.append(htmlFragment);
77 if (!displayUpdatePending) {
78 displayUpdatePending =
true;
79 QMetaObject::invokeMethod(
this,
"updateDisplay", Qt::QueuedConnection);
83void GBoard::updateDisplay() {
85 if (!logTextEdit)
return;
89 if (QThread::currentThread() != logTextEdit->thread()) {
90 QMetaObject::invokeMethod(
this,
"updateDisplay", Qt::QueuedConnection);
94 displayUpdatePending =
false;
96 const bool filtering = !currentFilterText.isEmpty();
97 Qt::CaseSensitivity cs = Qt::CaseInsensitive;
100 while (displayedLineCount < fullLogLines.size()) {
101 const auto& line = fullLogLines[displayedLineCount++];
104 if (filtering) { matches = (line.indexOf(currentFilterText, 0, cs) >= 0); }
106 if (matches) { logTextEdit->append(line); }
110 logTextEdit->verticalScrollBar()->setValue(logTextEdit->verticalScrollBar()->maximum());
113void GBoard::filterLog(
const QString& searchText) {
116 currentFilterText = searchText.trimmed();
117 logTextEdit->clear();
118 displayedLineCount = 0;
122void GBoard::clearLog() {
125 fullLogLines.clear();
126 logTextEdit->clear();
127 displayedLineCount = 0;
129 log->info(1,
"Log cleared by user.");
134void GBoard::saveLog() {
136 if (!logTextEdit)
return;
139 QString defaultFileName =
"gboard_log.log";
140 QString fileName = QFileDialog::getSaveFileName(
this,
143 tr(
"Log Files (*.log);;Text Files (*.txt);;All Files (*)"));
145 if (fileName.isEmpty()) {
149 QFile file(fileName);
150 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
151 QMessageBox::warning(
this, tr(
"Save Log Error"),
152 tr(
"Could not open file %1 for writing:\n%2.")
153 .arg(QDir::toNativeSeparators(fileName), file.errorString()));
155 "Failed to save log to %1. Error: %2", fileName.toStdString(), file.errorString().toStdString());
159 QTextStream out(&file);
162 out << logTextEdit->toPlainText();
165 log->info(
"Log saved successfully to %1", fileName.toStdString());
GBase(const std::shared_ptr< GOptions > &gopt, std::string logger_name="")
std::shared_ptr< GLogger > log
GBoard(const std::shared_ptr< GOptions > &gopt, QWidget *parent=nullptr)
Constructs a new GBoard widget.
void appendLog(const QString &text)
Appends a log line to the internal history and updates the display.
constexpr const char * GBOARD_LOGGER