gboard
Loading...
Searching...
No Matches
gboard.cc
Go to the documentation of this file.
1// G4Dialog
2#include "gboard.h"
3#include "gui_session.h"
4
5// qt
6#include <QVBoxLayout>
7#include <QRegularExpression>
8
9
10GBoard::GBoard(const std::shared_ptr<GOptions>& gopt, QWidget* parent)
11 : QWidget(parent),
12 GBase(gopt, GBOARD_LOGGER) {
13 // --- Create top bar widgets ---
14 // The top bar provides a lightweight "console" UX: filter, clear, save.
15 searchLineEdit = new QLineEdit(this);
16 searchLineEdit->setObjectName("searchLineEdit");
17 searchLineEdit->setPlaceholderText("Filter log lines (case insensitive)...");
18 searchLineEdit->setClearButtonEnabled(true); // Allows quickly removing the filter text.
19
20 clearButton = new QToolButton(this);
21 clearButton->setObjectName("clearButton");
22 clearButton->setIcon(style()->standardIcon(QStyle::SP_DialogResetButton));
23 clearButton->setToolTip("Clear Log");
24 clearButton->setText("Clear");
25 // for some reason, the SP_TrashIcon icon is not showing, so using SP_DialogResetButton
26 clearButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); // Or other style
27 clearButton->setEnabled(true);
28
29 saveButton = new QToolButton(this);
30 saveButton->setIcon(style()->standardIcon(QStyle::SP_DialogSaveButton));
31 saveButton->setToolTip("Save Log to File");
32 saveButton->setEnabled(true);
33
34
35 // Create a horizontal layout for the top bar.
36 auto* topBarLayout = new QHBoxLayout;
37 topBarLayout->addWidget(searchLineEdit);
38 topBarLayout->addWidget(clearButton);
39 topBarLayout->addWidget(saveButton);
40 topBarLayout->setSpacing(5);
41
42 // Create a QTextEdit for log messages.
43 // Rich text is enabled so that HTML fragments (for example ANSI-to-HTML conversions) render correctly.
44 logTextEdit = new QTextEdit(this);
45 logTextEdit->setAcceptRichText(true);
46 logTextEdit->setReadOnly(true);
47 logTextEdit->setMinimumHeight(200);
48 logTextEdit->setMinimumWidth(400);
49
50 // --- Dark theme (local to this widget) ---
51 // This uses a local stylesheet so the log board remains readable even in otherwise light GUIs.
52 this->setStyleSheet(
53 "QWidget { background-color: #0b0e12; color: #e6e6e6; }"
54 "QTextEdit { background-color: #0f1115; color: #e6e6e6; }"
55 // Override the style for the search line edit and the clear button
56 "QLineEdit#searchLineEdit { background-color: #ffffff; color: #000000; }"
57 "QToolButton#clearButton { background-color: #f0f0f0; color: #000000; }");
58
59 auto* layout = new QVBoxLayout(this);
60 layout->addLayout(topBarLayout);
61 layout->addWidget(logTextEdit, 1); // 1: stretchable
62 setLayout(layout);
63
64 // --- Connect signals to slots ---
65 // UI changes (typing, clicking) are translated into operations on the stored log history.
66 connect(searchLineEdit, &QLineEdit::textChanged, this, &GBoard::filterLog);
67 connect(clearButton, &QToolButton::clicked, this, &GBoard::clearLog);
68 connect(saveButton, &QToolButton::clicked, this, &GBoard::saveLog);
69
70 log->info(1, "GBoard initialized");
71}
72
73void GBoard::appendLog(const QString& htmlFragment) {
74 // See header for API docs.
75 if (htmlFragment.trimmed().isEmpty()) { return; }
76
77 // Append to the source of truth, the full log line list.
78 // NOTE: We intentionally store all lines (even when filtered out) so the user can change filters later.
79 fullLogLines.append(htmlFragment);
80
81 // Refresh the view so the new line appears if it matches the current filter.
82 updateDisplay();
83}
84
85void GBoard::updateDisplay() {
86 // See header for API docs.
87 if (!logTextEdit) return;
88
89 // Ensure QTextEdit manipulation occurs on the GUI thread.
90 // This protects typical usage where log lines arrive from worker threads or external callbacks.
91 if (QThread::currentThread() != logTextEdit->thread()) {
92 QMetaObject::invokeMethod(this, "updateDisplay", Qt::QueuedConnection);
93 return;
94 }
95
96 logTextEdit->clear(); // Rebuild from scratch using the stored history.
97
98 const bool filtering = !currentFilterText.isEmpty();
99 Qt::CaseSensitivity cs = Qt::CaseInsensitive;
100
101 // Re-append only the matching HTML fragments.
102 for (const QString& line : fullLogLines) {
103 bool matches = true;
104
105 if (filtering) { matches = (line.indexOf(currentFilterText, 0, cs) >= 0); }
106
107 if (matches) { logTextEdit->append(line); }
108 }
109
110 // Auto-scroll to the bottom after updating the display.
111 logTextEdit->verticalScrollBar()->setValue(logTextEdit->verticalScrollBar()->maximum());
112}
113
114void GBoard::filterLog(const QString& searchText) {
115 // See header for API docs.
116 // Keep the filter string normalized so repeated updates remain stable.
117 currentFilterText = searchText.trimmed();
118 updateDisplay();
119}
120
121void GBoard::clearLog() {
122 // See header for API docs.
123 if (logTextEdit) {
124 fullLogLines.clear();
125 updateDisplay();
126 log->info(1, "Log cleared by user.");
127 }
128}
129
130// Slot to Save the Log
131void GBoard::saveLog() {
132 // See header for API docs.
133 if (!logTextEdit) return;
134
135 QString defaultFileName = "gboard_log.log"; // Suggest a default name
136 QString fileName = QFileDialog::getSaveFileName(this,
137 tr("Save Log File"),
138 defaultFileName, // Default file/path suggestion
139 tr("Log Files (*.log);;Text Files (*.txt);;All Files (*)"));
140
141 if (fileName.isEmpty()) {
142 return; // User cancelled
143 }
144
145 QFile file(fileName);
146 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
147 QMessageBox::warning(this, tr("Save Log Error"),
148 tr("Could not open file %1 for writing:\n%2.")
149 .arg(QDir::toNativeSeparators(fileName), file.errorString()));
150 log->warning("Failed to save log to ", fileName.toStdString(), ". Error: ", file.errorString().toStdString());
151 return;
152 }
153
154 QTextStream out(&file);
155 // Save the plain text content (most common for logs).
156 // This captures exactly what the user sees (including filtering) in a portable log-friendly format.
157 out << logTextEdit->toPlainText();
158 file.close(); // Stream destructor closes it, but explicit is fine
159
160 log->info("Log saved successfully to ", fileName.toStdString());
161 // Optional: Show a status bar message or brief confirmation dialog
162}
std::shared_ptr< GLogger > log
GBoard(const std::shared_ptr< GOptions > &gopt, QWidget *parent=nullptr)
Constructs a new GBoard widget.
Definition gboard.cc:10
void appendLog(const QString &text)
Appends a log line to the internal history and updates the display.
Definition gboard.cc:73
void warning(Args &&... args) const
void info(int level, Args &&... args) const
constexpr const char * GBOARD_LOGGER
Definition gboard.h:10