mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-05-02 15:44:28 +02:00
chore: improve log display (#3658)
This commit is contained in:
commit
5cab302ce4
@ -36,6 +36,8 @@
|
|||||||
#include "GZip.h"
|
#include "GZip.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
|
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
|
||||||
{
|
{
|
||||||
@ -136,3 +138,65 @@ bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GZipStream::GZipStream(const QString& filePath) : GZipStream(new QFile(filePath)) {}
|
||||||
|
|
||||||
|
GZipStream::GZipStream(QFile* file) : m_file(file) {}
|
||||||
|
|
||||||
|
bool GZipStream::initStream()
|
||||||
|
{
|
||||||
|
memset(&m_strm, 0, sizeof(m_strm));
|
||||||
|
return (inflateInit2(&m_strm, 16 + MAX_WBITS) == Z_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GZipStream::unzipBlockByBlock(QByteArray& uncompressedBytes)
|
||||||
|
{
|
||||||
|
uncompressedBytes.clear();
|
||||||
|
if (!m_file->isOpen()) {
|
||||||
|
if (!m_file->open(QIODevice::ReadOnly)) {
|
||||||
|
qWarning() << "Failed to open file:" << (m_file->fileName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_strm.state && !initStream()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray compressedBlock;
|
||||||
|
unsigned int blockSize = 4096;
|
||||||
|
|
||||||
|
compressedBlock = m_file->read(blockSize);
|
||||||
|
if (compressedBlock.isEmpty()) {
|
||||||
|
return true; // End of file reached
|
||||||
|
}
|
||||||
|
|
||||||
|
bool done = processBlock(compressedBlock, uncompressedBytes);
|
||||||
|
if (inflateEnd(&m_strm) != Z_OK || !done) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GZipStream::processBlock(const QByteArray& compressedBlock, QByteArray& uncompressedBytes)
|
||||||
|
{
|
||||||
|
m_strm.next_in = (Bytef*)compressedBlock.data();
|
||||||
|
m_strm.avail_in = compressedBlock.size();
|
||||||
|
|
||||||
|
unsigned int uncompLength = uncompressedBytes.size();
|
||||||
|
if (m_strm.total_out >= uncompLength) {
|
||||||
|
uncompressedBytes.resize(uncompLength * 2);
|
||||||
|
uncompLength *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_strm.next_out = reinterpret_cast<Bytef*>(uncompressedBytes.data() + m_strm.total_out);
|
||||||
|
m_strm.avail_out = uncompLength - m_strm.total_out;
|
||||||
|
|
||||||
|
int err = inflate(&m_strm, Z_NO_FLUSH);
|
||||||
|
if (err != Z_OK && err != Z_STREAM_END) {
|
||||||
|
qWarning() << "Decompression failed with error code" << err;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -1,8 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <zlib.h>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
class GZip {
|
class GZip {
|
||||||
public:
|
public:
|
||||||
static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
|
static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
|
||||||
static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
|
static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GZipStream {
|
||||||
|
public:
|
||||||
|
explicit GZipStream(const QString& filePath);
|
||||||
|
explicit GZipStream(QFile* file);
|
||||||
|
|
||||||
|
// Decompress the next block and return the decompressed data
|
||||||
|
bool unzipBlockByBlock(QByteArray& uncompressedBytes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool initStream();
|
||||||
|
|
||||||
|
bool processBlock(const QByteArray& compressedBlock, QByteArray& uncompressedBytes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QFile* m_file;
|
||||||
|
z_stream m_strm;
|
||||||
|
};
|
||||||
|
@ -161,3 +161,8 @@ bool LogModel::colorLines() const
|
|||||||
{
|
{
|
||||||
return m_colorLines;
|
return m_colorLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LogModel::isOverFlow()
|
||||||
|
{
|
||||||
|
return m_numLines >= m_maxLines && m_stopOnOverflow;
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ class LogModel : public QAbstractListModel {
|
|||||||
void setMaxLines(int maxLines);
|
void setMaxLines(int maxLines);
|
||||||
void setStopOnOverflow(bool stop);
|
void setStopOnOverflow(bool stop);
|
||||||
void setOverflowMessage(const QString& overflowMessage);
|
void setOverflowMessage(const QString& overflowMessage);
|
||||||
|
bool isOverFlow();
|
||||||
|
|
||||||
void setLineWrap(bool state);
|
void setLineWrap(bool state);
|
||||||
bool wrapLines() const;
|
bool wrapLines() const;
|
||||||
|
@ -151,6 +151,48 @@ void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReadLineAbstract {
|
||||||
|
public:
|
||||||
|
ReadLineAbstract(QFile* file) : m_file(file)
|
||||||
|
{
|
||||||
|
if (file->fileName().endsWith(".gz"))
|
||||||
|
m_gz = new GZipStream(file);
|
||||||
|
}
|
||||||
|
~ReadLineAbstract() { delete m_gz; }
|
||||||
|
|
||||||
|
QString readLine()
|
||||||
|
{
|
||||||
|
if (!m_gz)
|
||||||
|
return QString::fromUtf8(m_file->readLine());
|
||||||
|
QString line;
|
||||||
|
for (;;) {
|
||||||
|
if (!m_decodedData.isEmpty()) {
|
||||||
|
int newlineIndex = m_decodedData.indexOf('\n');
|
||||||
|
if (newlineIndex != -1) {
|
||||||
|
line += QString::fromUtf8(m_decodedData).left(newlineIndex);
|
||||||
|
m_decodedData.remove(0, newlineIndex + 1);
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
line += QString::fromUtf8(m_decodedData);
|
||||||
|
m_decodedData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_gz->unzipBlockByBlock(m_decodedData)) { // If error occurs during unzipping
|
||||||
|
m_decodedData.clear();
|
||||||
|
return QObject::tr("The content of the file(%1) could not be decoded.").arg(m_file->fileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool done() { return m_gz ? m_decodedData.isEmpty() : m_file->atEnd(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QFile* m_file;
|
||||||
|
GZipStream* m_gz = nullptr;
|
||||||
|
QByteArray m_decodedData;
|
||||||
|
};
|
||||||
|
|
||||||
void OtherLogsPage::on_btnReload_clicked()
|
void OtherLogsPage::on_btnReload_clicked()
|
||||||
{
|
{
|
||||||
if (m_currentFile.isEmpty()) {
|
if (m_currentFile.isEmpty()) {
|
||||||
@ -178,35 +220,17 @@ void OtherLogsPage::on_btnReload_clicked()
|
|||||||
showTooBig();
|
showTooBig();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString content;
|
|
||||||
if (file.fileName().endsWith(".gz")) {
|
|
||||||
QByteArray temp;
|
|
||||||
if (!GZip::unzip(file.readAll(), temp)) {
|
|
||||||
setPlainText(tr("The file (%1) is not readable.").arg(file.fileName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
content = QString::fromUtf8(temp);
|
|
||||||
} else {
|
|
||||||
content = QString::fromUtf8(file.readAll());
|
|
||||||
}
|
|
||||||
if (content.size() >= 50000000ll) {
|
|
||||||
showTooBig();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the file is not too big for display, but too slow for syntax highlighting, just show content as plain text
|
ReadLineAbstract stream(&file);
|
||||||
if (content.size() >= 10000000ll || content.isEmpty()) {
|
|
||||||
setPlainText(content);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to determine a level for each line
|
// Try to determine a level for each line
|
||||||
if (content.back() == '\n')
|
|
||||||
content = content.remove(content.size() - 1, 1);
|
|
||||||
ui->text->clear();
|
ui->text->clear();
|
||||||
ui->text->setModel(nullptr);
|
ui->text->setModel(nullptr);
|
||||||
m_model->clear();
|
m_model->clear();
|
||||||
for (auto& line : content.split('\n')) {
|
auto line = stream.readLine();
|
||||||
|
while (!stream.done()) { // just read until the model is full or the file ended
|
||||||
|
if (line.back() == '\n')
|
||||||
|
line = line.remove(line.size() - 1, 1);
|
||||||
MessageLevel::Enum level = MessageLevel::Unknown;
|
MessageLevel::Enum level = MessageLevel::Unknown;
|
||||||
|
|
||||||
// if the launcher part set a log level, use it
|
// if the launcher part set a log level, use it
|
||||||
@ -221,6 +245,10 @@ void OtherLogsPage::on_btnReload_clicked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_model->append(level, line);
|
m_model->append(level, line);
|
||||||
|
if (m_model->isOverFlow())
|
||||||
|
break;
|
||||||
|
|
||||||
|
line = stream.readLine();
|
||||||
}
|
}
|
||||||
ui->text->setModel(m_proxy);
|
ui->text->setModel(m_proxy);
|
||||||
ui->text->scrollToBottom();
|
ui->text->scrollToBottom();
|
||||||
|
@ -42,6 +42,7 @@ LogView::LogView(QWidget* parent) : QPlainTextEdit(parent)
|
|||||||
{
|
{
|
||||||
setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
|
||||||
m_defaultFormat = new QTextCharFormat(currentCharFormat());
|
m_defaultFormat = new QTextCharFormat(currentCharFormat());
|
||||||
|
setUndoRedoEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogView::~LogView()
|
LogView::~LogView()
|
||||||
@ -129,6 +130,8 @@ void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
|
|||||||
QTextDocument document;
|
QTextDocument document;
|
||||||
QTextCursor cursor(&document);
|
QTextCursor cursor(&document);
|
||||||
|
|
||||||
|
cursor.movePosition(QTextCursor::End);
|
||||||
|
cursor.beginEditBlock();
|
||||||
for (int i = first; i <= last; i++) {
|
for (int i = first; i <= last; i++) {
|
||||||
auto idx = m_model->index(i, 0, parent);
|
auto idx = m_model->index(i, 0, parent);
|
||||||
auto text = m_model->data(idx, Qt::DisplayRole).toString();
|
auto text = m_model->data(idx, Qt::DisplayRole).toString();
|
||||||
@ -145,10 +148,10 @@ void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
|
|||||||
if (bg.isValid() && m_colorLines) {
|
if (bg.isValid() && m_colorLines) {
|
||||||
format.setBackground(bg.value<QColor>());
|
format.setBackground(bg.value<QColor>());
|
||||||
}
|
}
|
||||||
cursor.movePosition(QTextCursor::End);
|
|
||||||
cursor.insertText(text, format);
|
cursor.insertText(text, format);
|
||||||
cursor.insertBlock();
|
cursor.insertBlock();
|
||||||
}
|
}
|
||||||
|
cursor.endEditBlock();
|
||||||
|
|
||||||
QTextDocumentFragment fragment(&document);
|
QTextDocumentFragment fragment(&document);
|
||||||
QTextCursor workCursor = textCursor();
|
QTextCursor workCursor = textCursor();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user