10 #include "util/option_manager.h"
22 setWindowTitle(
"Log");
23 resize(320, parent->height());
25 QGridLayout* grid =
new QGridLayout(
this);
26 grid->setContentsMargins(5, 10, 5, 5);
28 qRegisterMetaType<QTextCursor>(
"QTextCursor");
29 qRegisterMetaType<QTextBlock>(
"QTextBlock");
31 QTimer*
timer =
new QTimer(
this);
39 std::cout, LogWidget::Update,
this);
42 std::cerr, LogWidget::Update,
this);
45 std::clog, LogWidget::Update,
this);
47 QHBoxLayout* left_button_layout =
new QHBoxLayout();
49 QPushButton* save_log_button =
new QPushButton(tr(
"Save"),
this);
50 connect(save_log_button, &QPushButton::released,
this, &LogWidget::SaveLog);
51 left_button_layout->addWidget(save_log_button);
53 QPushButton* clear_button =
new QPushButton(tr(
"Clear"),
this);
55 left_button_layout->addWidget(clear_button);
57 grid->addLayout(left_button_layout, 0, 0, Qt::AlignLeft);
59 QHBoxLayout* right_button_layout =
new QHBoxLayout();
61 grid->addLayout(right_button_layout, 0, 1, Qt::AlignRight);
63 text_box_ =
new QPlainTextEdit(
this);
64 text_box_->setReadOnly(
true);
65 text_box_->setMaximumBlockCount(max_num_blocks);
66 text_box_->setWordWrapMode(QTextOption::NoWrap);
67 text_box_->setFont(QFont(
"Courier", 10));
68 grid->addWidget(text_box_, 1, 0, 1, 2);
73 if (!cvlog_buffer_.empty()) {
74 QString remaining = QString::fromStdString(cvlog_buffer_).trimmed();
75 if (!remaining.isEmpty()) {
80 if (log_file_.is_open()) {
84 delete cout_redirector_;
85 delete cerr_redirector_;
86 delete clog_redirector_;
92 QList<QPair<QString, int>> cvlog_messages;
95 QMutexLocker locker(&mutex_);
99 if (log_file_.is_open()) {
105 cvlog_buffer_ += text;
109 while ((pos = cvlog_buffer_.find(
'\n')) != std::string::npos) {
110 std::string line = cvlog_buffer_.substr(0, pos);
111 cvlog_buffer_.erase(0, pos + 1);
114 QString qline = QString::fromStdString(line);
115 qline = qline.trimmed();
117 if (!qline.isEmpty()) {
120 QString lowerLine = qline.toLower();
124 "\\b(error|fatal|exception|crash)"
128 "\\b(warning|warn|caution)\\b",
138 if (lowerLine.startsWith(
"error") ||
139 lowerLine.startsWith(
"[error") ||
140 lowerLine.startsWith(
"e ") || hasError) {
142 }
else if (lowerLine.startsWith(
"warning") ||
143 lowerLine.startsWith(
"[warning") ||
144 lowerLine.startsWith(
"w ") || hasWarning) {
149 cvlog_messages.append(qMakePair(qline, logLevel));
155 if (cvlog_buffer_.size() > 1024) {
156 QString remaining = QString::fromStdString(cvlog_buffer_).trimmed();
157 if (!remaining.isEmpty()) {
158 cvlog_messages.append(
161 cvlog_buffer_.clear();
167 for (
const auto& msg : cvlog_messages) {
173 QMutexLocker locker(&mutex_);
175 if (text_queue_.size() > 0) {
177 text_box_->moveCursor(QTextCursor::End);
178 text_box_->insertPlainText(QString::fromStdString(text_queue_));
179 text_box_->moveCursor(QTextCursor::End);
185 QMutexLocker locker(&mutex_);
187 cvlog_buffer_.clear();
191 void LogWidget::Update(
const char* text,
192 std::streamsize
count,
193 void* log_widget_ptr) {
194 std::string text_str;
195 for (std::streamsize i = 0; i <
count; ++i) {
196 if (text[i] ==
'\n') {
204 log_widget->Append(text_str);
207 void LogWidget::SaveLog() {
208 const std::string log_path =
209 QFileDialog::getSaveFileName(
this, tr(
"Select path to log file"),
210 "", tr(
"Log (*.log)"))
214 if (log_path ==
"") {
218 std::ofstream file(log_path, std::ios::app);
219 CHECK(file.is_open()) << log_path;
220 file << text_box_->toPlainText().toUtf8().constData();
QRegularExpression QtCompatRegExp
bool qtCompatRegExpMatch(const QRegularExpression ®ex, const QString &str)
static void LogMessage(const QString &message, int level)
Static shortcut to CVLog::logMessage.
constexpr QRegularExpression::PatternOption CaseInsensitive
Generic file read and write utility for python interface.