diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj
index affc96666d..461d958711 100644
--- a/rpcs3/rpcs3.vcxproj
+++ b/rpcs3/rpcs3.vcxproj
@@ -472,6 +472,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -762,6 +767,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -1072,6 +1082,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -1362,6 +1377,11 @@
true
true
+
+ true
+ true
+ true
+
true
true
@@ -1537,6 +1557,7 @@
+
@@ -2305,6 +2326,24 @@
.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+ $(QTDIR)\bin\moc.exe;%(FullPath)
+ Moc%27ing %(Identity)...
+ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl" "-I.\..\3rdparty\curl\include" "-I.\..\3rdparty\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent"
+
diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters
index fe82b1474b..1c72125b83 100644
--- a/rpcs3/rpcs3.vcxproj.filters
+++ b/rpcs3/rpcs3.vcxproj.filters
@@ -1090,6 +1090,21 @@
Gui\custom items
+
+ Gui\log
+
+
+ Generated Files\Release - LLVM
+
+
+ Generated Files\Debug
+
+
+ Generated Files\Release
+
+
+ Generated Files\Debug - LLVM
+
@@ -1427,6 +1442,9 @@
Gui\settings
+
+ Gui\log
+
diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt
index dbd8fc13ac..1a3bf5222d 100644
--- a/rpcs3/rpcs3qt/CMakeLists.txt
+++ b/rpcs3/rpcs3qt/CMakeLists.txt
@@ -34,6 +34,7 @@ set(SRC_FILES
localized.cpp
localized_emu.h
log_frame.cpp
+ log_viewer.cpp
main_window.cpp
memory_string_searcher.cpp
memory_viewer_panel.cpp
diff --git a/rpcs3/rpcs3qt/cg_disasm_window.cpp b/rpcs3/rpcs3qt/cg_disasm_window.cpp
index e7175c84ed..deafd86140 100644
--- a/rpcs3/rpcs3qt/cg_disasm_window.cpp
+++ b/rpcs3/rpcs3qt/cg_disasm_window.cpp
@@ -63,13 +63,13 @@ cg_disasm_window::cg_disasm_window(std::shared_ptr xSettings): xgu
void cg_disasm_window::ShowContextMenu(const QPoint &pos)
{
- QMenu myMenu;
+ QMenu menu;
QAction* clear = new QAction(tr("&Clear"));
QAction* open = new QAction(tr("Open &Cg binary program"));
- myMenu.addAction(open);
- myMenu.addSeparator();
- myMenu.addAction(clear);
+ menu.addAction(open);
+ menu.addSeparator();
+ menu.addAction(clear);
connect(clear, &QAction::triggered, [this]()
{
@@ -79,9 +79,10 @@ void cg_disasm_window::ShowContextMenu(const QPoint &pos)
connect(open, &QAction::triggered, [this]()
{
- QString filePath = QFileDialog::getOpenFileName(this, tr("Select Cg program object"), m_path_last, tr("Cg program objects (*.fpo;*.vpo);;"));
- if (filePath == NULL) return;
- m_path_last = filePath;
+ const QString file_path = QFileDialog::getOpenFileName(this, tr("Select Cg program object"), m_path_last, tr("Cg program objects (*.fpo;*.vpo);;"));
+ if (file_path.isEmpty())
+ return;
+ m_path_last = file_path;
ShowDisasm();
});
@@ -102,7 +103,7 @@ void cg_disasm_window::ShowContextMenu(const QPoint &pos)
origin = mapToGlobal(pos);
}
- myMenu.exec(origin);
+ menu.exec(origin);
}
void cg_disasm_window::ShowDisasm()
diff --git a/rpcs3/rpcs3qt/cg_disasm_window.h b/rpcs3/rpcs3qt/cg_disasm_window.h
index ae56d3fe16..03203f8bd2 100644
--- a/rpcs3/rpcs3qt/cg_disasm_window.h
+++ b/rpcs3/rpcs3qt/cg_disasm_window.h
@@ -4,6 +4,7 @@
#include
#include
+
#include
class AsmHighlighter;
@@ -16,14 +17,14 @@ class cg_disasm_window : public QWidget
private Q_SLOTS:
void ShowContextMenu(const QPoint &pos);
+
+private:
void ShowDisasm();
bool IsValidFile(const QMimeData& md, bool save = false);
-private:
QString m_path_last;
QTextEdit* m_disasm_text;
QTextEdit* m_glsl_text;
- QList m_urls;
QAction *openCgBinaryProgram;
diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h
index c093c07919..87ad01cefc 100644
--- a/rpcs3/rpcs3qt/gui_settings.h
+++ b/rpcs3/rpcs3qt/gui_settings.h
@@ -129,6 +129,7 @@ namespace gui
const gui_save fd_boot_game = gui_save(main_window, "lastExplorePathGAME", "");
const gui_save fd_decrypt_sprx = gui_save(main_window, "lastExplorePathSPRX", "");
const gui_save fd_cg_disasm = gui_save(main_window, "lastExplorePathCGD", "");
+ const gui_save fd_log_viewer = gui_save(main_window, "lastExplorePathLOG", "");
const gui_save mw_debugger = gui_save(main_window, "debuggerVisible", false);
const gui_save mw_logger = gui_save(main_window, "loggerVisible", true);
diff --git a/rpcs3/rpcs3qt/log_viewer.cpp b/rpcs3/rpcs3qt/log_viewer.cpp
new file mode 100644
index 0000000000..771bbf2f8e
--- /dev/null
+++ b/rpcs3/rpcs3qt/log_viewer.cpp
@@ -0,0 +1,197 @@
+#include "stdafx.h"
+
+#include "log_viewer.h"
+#include "gui_settings.h"
+#include "syntax_highlighter.h"
+#include "find_dialog.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+LOG_CHANNEL(gui_log, "GUI");
+
+constexpr auto qstr = QString::fromStdString;
+inline std::string sstr(const QString& _in)
+{
+ return _in.toStdString();
+}
+
+log_viewer::log_viewer(std::shared_ptr settings)
+ : m_gui_settings(settings)
+{
+ setWindowTitle(tr("Log Viewer"));
+ setObjectName("log_viewer");
+ setAttribute(Qt::WA_DeleteOnClose);
+ setAttribute(Qt::WA_StyledBackground);
+ setAcceptDrops(true);
+ setMinimumSize(QSize(200, 150)); // seems fine on win 10
+ resize(QSize(620, 395));
+
+ m_path_last = m_gui_settings->GetValue(gui::fd_log_viewer).toString();
+
+ m_log_text = new QTextEdit(this);
+ m_log_text->setReadOnly(true);
+ m_log_text->setContextMenuPolicy(Qt::CustomContextMenu);
+ m_log_text->setWordWrapMode(QTextOption::NoWrap);
+ m_log_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
+ m_log_text->installEventFilter(this);
+
+ // m_log_text syntax highlighter
+ m_log_highlighter = new LogHighlighter(m_log_text->document());
+
+ QHBoxLayout* layout = new QHBoxLayout();
+ layout->addWidget(m_log_text);
+
+ setLayout(layout);
+
+ connect(m_log_text, &QWidget::customContextMenuRequested, this, &log_viewer::show_context_menu);
+
+ show_log();
+}
+
+void log_viewer::show_context_menu(const QPoint& pos)
+{
+ QMenu menu;
+ QAction* clear = new QAction(tr("&Clear"));
+ QAction* open = new QAction(tr("&Open log file"));
+
+ menu.addAction(open);
+ menu.addSeparator();
+ menu.addAction(clear);
+
+ connect(clear, &QAction::triggered, [this]()
+ {
+ m_log_text->clear();
+ });
+
+ connect(open, &QAction::triggered, [this]()
+ {
+ const QString file_path = QFileDialog::getOpenFileName(this, tr("Select log file"), m_path_last, tr("Log files (*.log);;"));
+ if (file_path.isEmpty())
+ return;
+ m_path_last = file_path;
+ show_log();
+ });
+
+ const auto obj = qobject_cast(sender());
+
+ QPoint origin;
+
+ if (obj == m_log_text)
+ {
+ origin = m_log_text->viewport()->mapToGlobal(pos);
+ }
+ else
+ {
+ origin = mapToGlobal(pos);
+ }
+
+ menu.exec(origin);
+}
+
+void log_viewer::show_log()
+{
+ if (m_path_last.isEmpty())
+ {
+ return;
+ }
+
+ m_log_text->clear();
+
+ if (QFile file(m_path_last);
+ file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text))
+ {
+ m_gui_settings->SetValue(gui::fd_log_viewer, m_path_last);
+
+ QTextStream stream(&file);
+
+ while (!stream.atEnd())
+ {
+ m_log_text->append(stream.readLine());
+ }
+
+ file.close();
+ }
+ else
+ {
+ gui_log.error("log_viewer: Failed to open %s", sstr(m_path_last));
+ }
+}
+
+bool log_viewer::is_valid_file(const QMimeData& md, bool save)
+{
+ const QList urls = md.urls();
+
+ if (urls.count() > 1)
+ {
+ return false;
+ }
+
+ const QString suffix = QFileInfo(urls[0].fileName()).suffix().toLower();
+
+ if (suffix == "log")
+ {
+ if (save)
+ {
+ m_path_last = urls[0].toLocalFile();
+ }
+ return true;
+ }
+ return false;
+}
+
+void log_viewer::dropEvent(QDropEvent* ev)
+{
+ if (is_valid_file(*ev->mimeData(), true))
+ {
+ show_log();
+ }
+}
+
+void log_viewer::dragEnterEvent(QDragEnterEvent* ev)
+{
+ if (is_valid_file(*ev->mimeData()))
+ {
+ ev->accept();
+ }
+}
+
+void log_viewer::dragMoveEvent(QDragMoveEvent* ev)
+{
+ if (is_valid_file(*ev->mimeData()))
+ {
+ ev->accept();
+ }
+}
+
+void log_viewer::dragLeaveEvent(QDragLeaveEvent* ev)
+{
+ ev->accept();
+}
+
+bool log_viewer::eventFilter(QObject* object, QEvent* event)
+{
+ if (object != m_log_text)
+ {
+ return QWidget::eventFilter(object, event);
+ }
+
+ if (event->type() == QEvent::KeyPress)
+ {
+ QKeyEvent* e = static_cast(event);
+ if (e && e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_F)
+ {
+ if (m_find_dialog && m_find_dialog->isVisible())
+ m_find_dialog->close();
+
+ m_find_dialog.reset(new find_dialog(static_cast(object), this));
+ }
+ }
+
+ return QWidget::eventFilter(object, event);
+}
diff --git a/rpcs3/rpcs3qt/log_viewer.h b/rpcs3/rpcs3qt/log_viewer.h
new file mode 100644
index 0000000000..27fe840983
--- /dev/null
+++ b/rpcs3/rpcs3qt/log_viewer.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+class LogHighlighter;
+class gui_settings;
+class find_dialog;
+
+class log_viewer : public QWidget
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void show_context_menu(const QPoint& pos);
+
+private:
+ void show_log();
+ bool is_valid_file(const QMimeData& md, bool save = false);
+
+ std::shared_ptr m_gui_settings;
+ QString m_path_last;
+ QTextEdit* m_log_text;
+ LogHighlighter* m_log_highlighter;
+ std::unique_ptr m_find_dialog;
+
+public:
+ explicit log_viewer(std::shared_ptr settings);
+
+protected:
+ void dropEvent(QDropEvent* ev) override;
+ void dragEnterEvent(QDragEnterEvent* ev) override;
+ void dragMoveEvent(QDragMoveEvent* ev) override;
+ void dragLeaveEvent(QDragLeaveEvent* ev) override;
+ bool eventFilter(QObject* object, QEvent* event) override;
+};
diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp
index 806e7b222f..ce689a5091 100644
--- a/rpcs3/rpcs3qt/main_window.cpp
+++ b/rpcs3/rpcs3qt/main_window.cpp
@@ -13,6 +13,7 @@
#include "rpcn_settings_dialog.h"
#include "auto_pause_settings_dialog.h"
#include "cg_disasm_window.h"
+#include "log_viewer.h"
#include "memory_string_searcher.h"
#include "memory_viewer_panel.h"
#include "rsx_debugger.h"
@@ -1832,6 +1833,12 @@ void main_window::CreateConnects()
cgdw->show();
});
+ connect(ui->actionLog_Viewer, &QAction::triggered, [this]
+ {
+ log_viewer* viewer = new log_viewer(m_gui_settings);
+ viewer->show();
+ });
+
connect(ui->toolskernel_explorerAct, &QAction::triggered, [this]
{
if (!m_kernel_explorer)
diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui
index e55d0100c1..4b57e140dc 100644
--- a/rpcs3/rpcs3qt/main_window.ui
+++ b/rpcs3/rpcs3qt/main_window.ui
@@ -248,6 +248,7 @@
Utilities
+
@@ -1110,6 +1111,11 @@
Configure RPCN
+
+
+ Log Viewer
+
+
diff --git a/rpcs3/rpcs3qt/syntax_highlighter.cpp b/rpcs3/rpcs3qt/syntax_highlighter.cpp
index ac6d3b948e..f5468d6197 100644
--- a/rpcs3/rpcs3qt/syntax_highlighter.cpp
+++ b/rpcs3/rpcs3qt/syntax_highlighter.cpp
@@ -1,4 +1,5 @@
#include "syntax_highlighter.h"
+#include "qt_utils.h"
Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent)
{
@@ -14,7 +15,7 @@ void Highlighter::addRule(const QString &pattern, const QBrush &brush)
void Highlighter::highlightBlock(const QString &text)
{
- foreach (const HighlightingRule &rule, highlightingRules)
+ for (const HighlightingRule &rule : highlightingRules)
{
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext())
@@ -34,8 +35,8 @@ void Highlighter::highlightBlock(const QString &text)
while (startIndex >= 0)
{
- QRegularExpressionMatch match = commentEndExpression.match(text, startIndex);
- int endIndex = match.capturedStart();
+ const QRegularExpressionMatch match = commentEndExpression.match(text, startIndex);
+ const int endIndex = match.capturedStart();
int commentLength = 0;
if (endIndex == -1)
@@ -52,6 +53,18 @@ void Highlighter::highlightBlock(const QString &text)
}
}
+LogHighlighter::LogHighlighter(QTextDocument* parent) : Highlighter(parent)
+{
+ //addRule("^[^·].*$", gui::utils::get_label_color("log_level_always")); // unused for now
+ addRule("^·F.*$", gui::utils::get_label_color("log_level_fatal"));
+ addRule("^·E.*$", gui::utils::get_label_color("log_level_error"));
+ addRule("^·U.*$", gui::utils::get_label_color("log_level_todo"));
+ addRule("^·S.*$", gui::utils::get_label_color("log_level_success"));
+ addRule("^·W.*$", gui::utils::get_label_color("log_level_warning"));
+ addRule("^·!.*$", gui::utils::get_label_color("log_level_notice"));
+ addRule("^·T.*$", gui::utils::get_label_color("log_level_trace"));
+}
+
AsmHighlighter::AsmHighlighter(QTextDocument *parent) : Highlighter(parent)
{
addRule("^[A-Z0-9]+", Qt::darkBlue); // Instructions
@@ -65,7 +78,7 @@ AsmHighlighter::AsmHighlighter(QTextDocument *parent) : Highlighter(parent)
GlslHighlighter::GlslHighlighter(QTextDocument *parent) : Highlighter(parent)
{
- QStringList keywordPatterns = QStringList()
+ const QStringList keywordPatterns = QStringList()
// Selection-Iteration-Jump Statements:
<< "if" << "else" << "switch" << "case" << "default"
<< "for" << "while" << "do" << "foreach" //?
@@ -155,7 +168,7 @@ GlslHighlighter::GlslHighlighter(QTextDocument *parent) : Highlighter(parent)
<< "r16_snorm" << "r32ui"
<< "r8_snorm" << "r16ui";
- foreach (const QString &pattern, keywordPatterns)
+ for (const QString &pattern : keywordPatterns)
addRule("\\b" + pattern + "\\b", Qt::darkBlue); // normal words like: soka, nani, or gomen
addRule("\\bGL_(?:[A-Z]|_)+\\b", Qt::darkMagenta); // constants like: GL_OMAE_WA_MOU_SHINDEIRU
diff --git a/rpcs3/rpcs3qt/syntax_highlighter.h b/rpcs3/rpcs3qt/syntax_highlighter.h
index 4cd1d36c9b..8e043b9d6d 100644
--- a/rpcs3/rpcs3qt/syntax_highlighter.h
+++ b/rpcs3/rpcs3qt/syntax_highlighter.h
@@ -29,6 +29,14 @@ protected:
QTextCharFormat multiLineCommentFormat;
};
+class LogHighlighter : public Highlighter
+{
+ Q_OBJECT
+
+public:
+ LogHighlighter(QTextDocument* parent = 0);
+};
+
class AsmHighlighter : public Highlighter
{
Q_OBJECT