#include "LogPage.h" #include "ui_LogPage.h" #include "MultiMC.h" #include #include #include #include "launch/LaunchTask.h" #include #include "GuiUtil.h" #include LogPage::LogPage(std::shared_ptr proc, QWidget *parent) : QWidget(parent), ui(new Ui::LogPage), m_process(proc) { ui->setupUi(this); ui->tabWidget->tabBar()->hide(); connect(m_process.get(), SIGNAL(log(QString, MessageLevel::Enum)), this, SLOT(write(QString, MessageLevel::Enum))); // create the format and set its font defaultFormat = new QTextCharFormat(ui->text->currentCharFormat()); QString fontFamily = MMC->settings()->get("ConsoleFont").toString(); bool conversionOk = false; int fontSize = MMC->settings()->get("ConsoleFontSize").toInt(&conversionOk); if(!conversionOk) { fontSize = 11; } defaultFormat->setFont(QFont(fontFamily, fontSize)); // ensure we don't eat all the RAM auto lineSetting = MMC->settings()->getSetting("ConsoleMaxLines"); int maxLines = lineSetting->get().toInt(&conversionOk); if(!conversionOk) { maxLines = lineSetting->defValue().toInt(); qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines; } ui->text->setMaximumBlockCount(maxLines); auto origForeground = ui->text->palette().color(ui->text->foregroundRole()); auto origBackground = ui->text->palette().color(ui->text->backgroundRole()); m_colors.reset(new LogColorCache(origForeground, origBackground)); m_stopOnOverflow = MMC->settings()->get("ConsoleOverflowStop").toBool(); auto findShortcut = new QShortcut(QKeySequence(QKeySequence::Find), this); connect(findShortcut, SIGNAL(activated()), SLOT(findActivated())); auto findNextShortcut = new QShortcut(QKeySequence(QKeySequence::FindNext), this); connect(findNextShortcut, SIGNAL(activated()), SLOT(findNextActivated())); connect(ui->searchBar, SIGNAL(returnPressed()), SLOT(on_findButton_clicked())); auto findPreviousShortcut = new QShortcut(QKeySequence(QKeySequence::FindPrevious), this); connect(findPreviousShortcut, SIGNAL(activated()), SLOT(findPreviousActivated())); } LogPage::~LogPage() { delete ui; delete defaultFormat; } bool LogPage::apply() { return true; } bool LogPage::shouldDisplay() const { return m_process->instance()->isRunning(); } void LogPage::on_btnPaste_clicked() { //FIXME: turn this into a proper task and move the upload logic out of GuiUtil! write(tr("MultiMC: Log upload triggered at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)), MessageLevel::MultiMC); auto url = GuiUtil::uploadPaste(ui->text->toPlainText(), this); if(!url.isEmpty()) { write(tr("MultiMC: Log uploaded to: %1").arg(url), MessageLevel::MultiMC); } else { write(tr("MultiMC: Log upload failed!"), MessageLevel::Error); } } void LogPage::on_btnCopy_clicked() { write(QString("Clipboard copy at: %1").arg(QDateTime::currentDateTime().toString(Qt::RFC2822Date)), MessageLevel::MultiMC); GuiUtil::setClipboardText(ui->text->toPlainText()); } void LogPage::on_btnClear_clicked() { ui->text->clear(); } void LogPage::on_btnBottom_clicked() { ui->text->verticalScrollBar()->setSliderPosition(ui->text->verticalScrollBar()->maximum()); } void LogPage::on_trackLogCheckbox_clicked(bool checked) { m_write_active = checked; } void LogPage::on_wrapCheckbox_clicked(bool checked) { if(checked) { ui->text->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); } else { ui->text->setWordWrapMode(QTextOption::WrapMode::NoWrap); } } void LogPage::on_findButton_clicked() { auto modifiers = QApplication::keyboardModifiers(); if (modifiers & Qt::ShiftModifier) { findPreviousActivated(); } else { findNextActivated(); } } void LogPage::findActivated() { // focus the search bar if it doesn't have focus if (!ui->searchBar->hasFocus()) { auto searchForCursor = ui->text->textCursor(); auto searchForString = searchForCursor.selectedText(); if (searchForString.size()) { ui->searchBar->setText(searchForString); } ui->searchBar->setFocus(); ui->searchBar->selectAll(); } } void LogPage::findNextActivated() { auto toSearch = ui->searchBar->text(); if (toSearch.size()) { ui->text->find(toSearch); } } void LogPage::findPreviousActivated() { auto toSearch = ui->searchBar->text(); if (toSearch.size()) { ui->text->find(toSearch, QTextDocument::FindBackward); } } void LogPage::setParentContainer(BasePageContainer * container) { m_parentContainer = container; } void LogPage::write(QString data, MessageLevel::Enum mode) { if (!m_write_active) { if (mode != MessageLevel::MultiMC) { return; } } if(m_stopOnOverflow && m_write_active) { if(mode != MessageLevel::MultiMC) { if(ui->text->blockCount() >= ui->text->maximumBlockCount()) { m_write_active = false; data = tr("MultiMC stopped watching the game log because the log length surpassed %1 lines.\n" "You may have to fix your mods because the game is still loggging to files and" " likely wasting harddrive space at an alarming rate!") .arg(ui->text->maximumBlockCount()); mode = MessageLevel::Fatal; ui->trackLogCheckbox->setCheckState(Qt::Unchecked); if(!isVisible()) { m_parentContainer->selectPage(id()); } } } } // save the cursor so it can be restored. auto savedCursor = ui->text->cursor(); QScrollBar *bar = ui->text->verticalScrollBar(); int max_bar = bar->maximum(); int val_bar = bar->value(); if (isVisible()) { if (m_scroll_active) { m_scroll_active = (max_bar - val_bar) <= 1; } else { m_scroll_active = val_bar == max_bar; } } if (data.endsWith('\n')) data = data.left(data.length() - 1); QStringList paragraphs = data.split('\n'); QStringList filtered; for (QString ¶graph : paragraphs) { //TODO: implement filtering here. filtered.append(paragraph); } QListIterator iter(filtered); QTextCharFormat format(*defaultFormat); format.setForeground(m_colors->getFront(mode)); format.setBackground(m_colors->getBack(mode)); while (iter.hasNext()) { // append a paragraph/line auto workCursor = ui->text->textCursor(); workCursor.movePosition(QTextCursor::End); workCursor.insertText(iter.next(), format); workCursor.insertBlock(); } if (isVisible()) { if (m_scroll_active) { bar->setValue(bar->maximum()); } m_last_scroll_value = bar->value(); } ui->text->setCursor(savedCursor); }