/* * Copyright (C) by Klaas Freitag * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "logbrowser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "configfile.h" #include "logger.h" namespace OCC { // ============================================================================== LogWidget::LogWidget(QWidget *parent) : QPlainTextEdit(parent) { setReadOnly(true); QFont font; font.setFamily(QLatin1String("Courier New")); font.setFixedPitch(true); document()->setDefaultFont(font); } // ============================================================================== LogBrowser::LogBrowser(QWidget *parent) : QDialog(parent) , _logWidget(new LogWidget(parent)) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setObjectName("LogBrowser"); // for save/restoreGeometry() setWindowTitle(tr("Log Output")); setMinimumWidth(600); auto *mainLayout = new QVBoxLayout; // mainLayout->setMargin(0); mainLayout->addWidget(_logWidget); auto *toolLayout = new QHBoxLayout; mainLayout->addLayout(toolLayout); // Search input field auto *lab = new QLabel(tr("&Search:") + " "); _findTermEdit = new QLineEdit; lab->setBuddy(_findTermEdit); toolLayout->addWidget(lab); toolLayout->addWidget(_findTermEdit); // find button auto *findBtn = new QPushButton; findBtn->setText(tr("&Find")); connect(findBtn, &QAbstractButton::clicked, this, &LogBrowser::slotFind); toolLayout->addWidget(findBtn); // stretch toolLayout->addStretch(1); _statusLabel = new QLabel; toolLayout->addWidget(_statusLabel); toolLayout->addStretch(5); // Debug logging _logDebugCheckBox = new QCheckBox(tr("&Capture debug messages") + " "); connect(_logDebugCheckBox, &QCheckBox::stateChanged, this, &LogBrowser::slotDebugCheckStateChanged); toolLayout->addWidget(_logDebugCheckBox); auto *btnbox = new QDialogButtonBox; QPushButton *closeBtn = btnbox->addButton(QDialogButtonBox::Close); connect(closeBtn, &QAbstractButton::clicked, this, &QWidget::close); mainLayout->addWidget(btnbox); // button to permanently save logs _permanentLogging = new QCheckBox; _permanentLogging->setText(tr("Permanently save logs")); _permanentLogging->setToolTip( tr("When this option is enabled and no other logging is configured, " "logs will be written to a temporary folder and expire after a few hours. " "This setting persists across client restarts.\n" "\n" "Logs will be written to %1") .arg(Logger::instance()->temporaryFolderLogDirPath())); _permanentLogging->setChecked(ConfigFile().automaticLogDir()); btnbox->addButton(_permanentLogging, QDialogButtonBox::ActionRole); connect(_permanentLogging, &QCheckBox::toggled, this, &LogBrowser::togglePermanentLogging); // clear button _clearBtn = new QPushButton; _clearBtn->setText(tr("Clear")); _clearBtn->setToolTip(tr("Clear the log display.")); btnbox->addButton(_clearBtn, QDialogButtonBox::ActionRole); connect(_clearBtn, &QAbstractButton::clicked, this, &LogBrowser::slotClearLog); // save Button _saveBtn = new QPushButton; _saveBtn->setText(tr("S&ave")); _saveBtn->setToolTip(tr("Save the log file to a file on disk for debugging.")); btnbox->addButton(_saveBtn, QDialogButtonBox::ActionRole); connect(_saveBtn, &QAbstractButton::clicked, this, &LogBrowser::slotSave); setLayout(mainLayout); setModal(false); Logger::instance()->setLogWindowActivated(true); // Direct connection for log coming from this thread, and queued for the one in a different thread connect(Logger::instance(), &Logger::logWindowLog, this, &LogBrowser::slotNewLog, Qt::AutoConnection); auto *showLogWindow = new QAction(this); showLogWindow->setShortcut(QKeySequence("F12")); connect(showLogWindow, &QAction::triggered, this, &QWidget::close); addAction(showLogWindow); ConfigFile cfg; cfg.restoreGeometry(this); int lines = cfg.maxLogLines(); _logWidget->document()->setMaximumBlockCount(lines); } LogBrowser::~LogBrowser() = default; void LogBrowser::showEvent(QShowEvent *) { // This could have been changed through the --logdebug argument passed through the single application. _logDebugCheckBox->setCheckState(Logger::instance()->logDebug() ? Qt::Checked : Qt::Unchecked); } void LogBrowser::closeEvent(QCloseEvent *) { ConfigFile cfg; cfg.saveGeometry(this); } void LogBrowser::slotNewLog(const QString &msg) { if (_logWidget->isVisible()) { _logWidget->appendPlainText(msg); } } void LogBrowser::slotFind() { QString searchText = _findTermEdit->text(); if (searchText.isEmpty()) return; search(searchText); } void LogBrowser::slotDebugCheckStateChanged(int checkState) { Logger::instance()->setLogDebug(checkState == Qt::Checked); } void LogBrowser::search(const QString &str) { QList extraSelections; _logWidget->moveCursor(QTextCursor::Start); QColor color = QColor(Qt::gray).lighter(130); _statusLabel->clear(); while (_logWidget->find(str)) { QTextEdit::ExtraSelection extra; extra.format.setBackground(color); extra.cursor = _logWidget->textCursor(); extraSelections.append(extra); } QString stat = QString::fromLatin1("Search term %1 with %2 search results.").arg(str).arg(extraSelections.count()); _statusLabel->setText(stat); _logWidget->setExtraSelections(extraSelections); } void LogBrowser::slotSave() { _saveBtn->setEnabled(false); QString saveFile = QFileDialog::getSaveFileName(this, tr("Save log file"), QDir::homePath()); if (!saveFile.isEmpty()) { QFile file(saveFile); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream << _logWidget->toPlainText(); file.close(); } else { QMessageBox::critical(this, tr("Error"), tr("Could not write to log file %1").arg(saveFile)); } } _saveBtn->setEnabled(true); } void LogBrowser::slotClearLog() { _logWidget->clear(); } void LogBrowser::togglePermanentLogging(bool enabled) { ConfigFile().setAutomaticLogDir(enabled); auto logger = Logger::instance(); if (enabled) { if (!logger->isLoggingToFile()) { logger->setupTemporaryFolderLogDir(); } } else { logger->disableTemporaryFolderLogDir(); } } } // namespace