From 5407e42b764c866a7bd1b14a58b010e58416017b Mon Sep 17 00:00:00 2001 From: Megamouse Date: Mon, 11 Apr 2022 23:05:36 +0200 Subject: [PATCH] Qt: add last thread actions option to log viewer --- rpcs3/rpcs3qt/log_viewer.cpp | 99 +++++++++++++++++++++++++++++++----- rpcs3/rpcs3qt/log_viewer.h | 2 + 2 files changed, 89 insertions(+), 12 deletions(-) diff --git a/rpcs3/rpcs3qt/log_viewer.cpp b/rpcs3/rpcs3qt/log_viewer.cpp index 284fbe3059..95a6dc01c5 100644 --- a/rpcs3/rpcs3qt/log_viewer.cpp +++ b/rpcs3/rpcs3qt/log_viewer.cpp @@ -15,6 +15,10 @@ #include #include #include +#include + +#include +#include LOG_CHANNEL(gui_log, "GUI"); @@ -67,6 +71,10 @@ void log_viewer::show_context_menu(const QPoint& pos) threads->setCheckable(true); threads->setChecked(m_show_threads); + QAction* last_actions_only = new QAction(tr("&Last actions only")); + last_actions_only->setCheckable(true); + last_actions_only->setChecked(m_last_actions_only); + QActionGroup* log_level_acts = new QActionGroup(this); QAction* fatal_act = new QAction(tr("Fatal"), log_level_acts); QAction* error_act = new QAction(tr("Error"), log_level_acts); @@ -104,6 +112,8 @@ void log_viewer::show_context_menu(const QPoint& pos) menu.addSeparator(); menu.addAction(threads); menu.addSeparator(); + menu.addAction(last_actions_only); + menu.addSeparator(); menu.addActions(log_level_acts->actions()); menu.addSeparator(); menu.addAction(clear); @@ -135,6 +145,12 @@ void log_viewer::show_context_menu(const QPoint& pos) filter_log(); }); + connect(last_actions_only, &QAction::toggled, this, [this](bool checked) + { + m_last_actions_only = checked; + filter_log(); + }); + const auto obj = qobject_cast(sender()); QPoint origin; @@ -179,6 +195,13 @@ void log_viewer::show_log() } } +void log_viewer::set_text_and_keep_position(const QString& text) +{ + const int pos = m_log_text->verticalScrollBar()->value(); + m_log_text->setPlainText(text); + m_log_text->verticalScrollBar()->setValue(pos); +} + void log_viewer::filter_log() { if (m_full_log.isEmpty()) @@ -200,19 +223,17 @@ void log_viewer::filter_log() if (!m_log_levels.test(static_cast(logs::level::notice))) excluded_log_levels.push_back("·! "); if (!m_log_levels.test(static_cast(logs::level::trace))) excluded_log_levels.push_back("·T "); - if (m_filter_term.isEmpty() && excluded_log_levels.empty() && m_show_threads) + if (m_filter_term.isEmpty() && excluded_log_levels.empty() && m_show_threads && !m_last_actions_only) { - const int pos = m_log_text->verticalScrollBar()->value(); - m_log_text->setPlainText(m_full_log); - m_log_text->verticalScrollBar()->setValue(pos); + set_text_and_keep_position(m_full_log); return; } QString result; - - QRegularExpression regexp("\{.*\} "); QTextStream stream(&m_full_log); - for (QString line = stream.readLine(); !line.isNull(); line = stream.readLine()) + const QRegularExpression thread_regexp("\{.*\} "); + + const auto add_line = [this, &result, &excluded_log_levels, &thread_regexp](QString& line) { bool exclude_line = false; @@ -227,14 +248,14 @@ void log_viewer::filter_log() if (exclude_line) { - continue; + return; } if (m_filter_term.isEmpty() || line.contains(m_filter_term)) { if (!m_show_threads) { - line.remove(regexp); + line.remove(thread_regexp); } if (!line.isEmpty()) @@ -244,9 +265,63 @@ void log_viewer::filter_log() } }; - const int pos = m_log_text->verticalScrollBar()->value(); - m_log_text->setPlainText(result); - m_log_text->verticalScrollBar()->setValue(pos); + if (m_last_actions_only) + { + if (const int start_pos = m_full_log.lastIndexOf("LDR: Used configuration:"); start_pos >= 0) + { + if (!stream.seek(start_pos)) // TODO: is this correct ? + { + gui_log.error("Log viewer failed to seek to pos %d of log.", start_pos); + } + + std::map> all_thread_actions; + + for (QString line = stream.readLine(); !line.isNull(); line = stream.readLine()) + { + if (const QRegularExpressionMatch match = thread_regexp.match(line); match.hasMatch()) + { + if (const QString thread_name = match.captured(); !thread_name.isEmpty()) + { + std::deque& actions = all_thread_actions[thread_name]; + actions.push_back(line); + + if (actions.size() > 10) + { + actions.pop_front(); + } + } + } + } + + for (auto& [thread_name, actions] : all_thread_actions) + { + for (QString& line : actions) + { + add_line(line); + } + } + + set_text_and_keep_position(result); + return; + } + else + { + QMessageBox::information(this, tr("Ooops!"), tr("Cannot find any game boot!")); + // Pass through to regular log filter + } + } + + if (!stream.seek(0)) + { + gui_log.error("Log viewer failed to seek to beginning of log."); + } + + for (QString line = stream.readLine(); !line.isNull(); line = stream.readLine()) + { + add_line(line); + }; + + set_text_and_keep_position(result); } bool log_viewer::is_valid_file(const QMimeData& md, bool save) diff --git a/rpcs3/rpcs3qt/log_viewer.h b/rpcs3/rpcs3qt/log_viewer.h index 340274e9c0..910321d3d4 100644 --- a/rpcs3/rpcs3qt/log_viewer.h +++ b/rpcs3/rpcs3qt/log_viewer.h @@ -22,6 +22,7 @@ private Q_SLOTS: void show_context_menu(const QPoint& pos); private: + void set_text_and_keep_position(const QString& text); void filter_log(); bool is_valid_file(const QMimeData& md, bool save = false); @@ -34,6 +35,7 @@ private: std::unique_ptr m_find_dialog; std::bitset<32> m_log_levels = std::bitset<32>(0b11111111u); bool m_show_threads = true; + bool m_last_actions_only = false; protected: void dropEvent(QDropEvent* ev) override;