File indexing completed on 2024-12-22 04:14:52

0001 /*
0002  *  SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 
0008 #include "LogDockerDock.h"
0009 
0010 #include <QHBoxLayout>
0011 #include <QToolButton>
0012 #include <QScrollBar>
0013 #include <QStandardPaths>
0014 #include <QDateTime>
0015 #include <QCheckBox>
0016 
0017 #include <klocalizedstring.h>
0018 #include <ksharedconfig.h>
0019 #include <kconfiggroup.h>
0020 
0021 #include <KisPart.h>
0022 #include <KoDialog.h>
0023 #include <KoCanvasBase.h>
0024 #include <KoIcon.h>
0025 #include <KoFileDialog.h>
0026 
0027 #include "kis_canvas2.h"
0028 #include "KisViewManager.h"
0029 #include "KisMainWindow.h"
0030 #include "kis_config.h"
0031 
0032 MessageSender *LogDockerDock::s_messageSender {new MessageSender()};
0033 QTextCharFormat LogDockerDock::s_debug;
0034 QTextCharFormat LogDockerDock::s_info;
0035 QTextCharFormat LogDockerDock::s_warning;
0036 QTextCharFormat LogDockerDock::s_critical;
0037 QTextCharFormat LogDockerDock::s_fatal;
0038 
0039 static QtMessageHandler s_originalMessageHandler{nullptr};
0040 
0041 LogDockerDock::LogDockerDock( )
0042     : QDockWidget(i18n("Log Viewer"))
0043 {
0044     QWidget *page = new QWidget(this);
0045     setupUi(page);
0046     setWidget(page);
0047 
0048     bnToggle->setIcon(koIcon("view-list-text-16"));
0049     connect(bnToggle, SIGNAL(clicked(bool)), SLOT(toggleLogging(bool)));
0050     bnToggle->setChecked(KisConfig(true).readEntry<bool>("logviewer_enabled", false));
0051     toggleLogging(KisConfig(true).readEntry<bool>("logviewer_enabled", false));
0052 
0053     bnClear->setIcon(koIcon("edit-clear-16"));
0054     connect(bnClear, SIGNAL(clicked(bool)), SLOT(clearLog()));
0055 
0056     bnSave->setIcon(koIcon("document-save-16"));
0057     connect(bnSave, SIGNAL(clicked(bool)), SLOT(saveLog()));
0058 
0059     bnSettings->setIcon(koIcon("configure-thicker"));
0060     connect(bnSettings, SIGNAL(clicked(bool)), SLOT(settings()));
0061 
0062     qRegisterMetaType<QtMsgType>("QtMsgType");
0063     connect(s_messageSender, SIGNAL(emitMessage(QtMsgType,QString)), this, SLOT(insertMessage(QtMsgType,QString)), Qt::AutoConnection);
0064 
0065     changeTheme();
0066 }
0067 
0068 void LogDockerDock::setCanvas(KoCanvasBase *)
0069 {
0070     setEnabled(true);
0071 }
0072 
0073 void LogDockerDock::setViewManager(KisViewManager *kisview)
0074 {
0075     connect(kisview->mainWindow(), SIGNAL(themeChanged()), SLOT(changeTheme()));
0076 }
0077 
0078 void LogDockerDock::toggleLogging(bool toggle)
0079 {
0080     KisConfig(false).writeEntry<bool>("logviewer_enabled", toggle);
0081     if (toggle) {
0082         const QtMessageHandler oldHandler = qInstallMessageHandler(messageHandler);
0083         if (!s_originalMessageHandler) {
0084             s_originalMessageHandler = oldHandler;
0085         }
0086         applyCategories();
0087     }
0088     else {
0089         qInstallMessageHandler(nullptr);
0090         QLoggingCategory::setFilterRules(QString());
0091     }
0092 
0093 }
0094 
0095 void LogDockerDock::clearLog()
0096 {
0097     txtLogViewer->document()->clear();
0098 }
0099 
0100 void LogDockerDock::saveLog()
0101 {
0102     KoFileDialog fileDialog(this, KoFileDialog::SaveFile, "logfile");
0103     fileDialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + "/" + QString("krita_%1.log").arg(QDateTime::currentDateTime().toString("yyyy-MM-ddThh")));
0104     QString filename = fileDialog.filename();
0105     if (!filename.isEmpty()) {
0106         QFile f(filename);
0107         f.open(QFile::WriteOnly);
0108         f.write(txtLogViewer->document()->toPlainText().toUtf8());
0109         f.close();
0110     }
0111 }
0112 
0113 void LogDockerDock::settings()
0114 {
0115     KoDialog dlg(this);
0116     dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
0117     dlg.setCaption(i18n("Log Settings"));
0118     QWidget *page = new QWidget(&dlg);
0119     dlg.setMainWidget(page);
0120     QVBoxLayout *layout = new QVBoxLayout(page);
0121 
0122     KConfigGroup cfg( KSharedConfig::openConfig(), "LogDocker");
0123 
0124     QCheckBox *chkKrita = new QCheckBox(i18n("General"), page);
0125     chkKrita->setChecked(cfg.readEntry("krita_41000", false));
0126     layout->addWidget(chkKrita);
0127 
0128     QCheckBox *chkResources = new QCheckBox(i18n("Resource Management"), page);
0129     chkResources->setChecked(cfg.readEntry("resources_30009", false));
0130     layout->addWidget(chkResources);
0131 
0132     QCheckBox *chkImage = new QCheckBox(i18n("Image Core"), page);
0133     chkImage->setChecked(cfg.readEntry("image_41001", false));
0134     layout->addWidget(chkImage);
0135 
0136     QCheckBox *chkRegistry = new QCheckBox(i18n("Registries"), page);
0137     chkRegistry->setChecked(cfg.readEntry("registry_41002", false));
0138     layout->addWidget(chkRegistry);
0139 
0140     QCheckBox *chkTools = new QCheckBox(i18n("Tools"), page);
0141     chkTools->setChecked(cfg.readEntry("tools_41003", false));
0142     layout->addWidget(chkTools);
0143 
0144     QCheckBox *chkTiles = new QCheckBox(i18n("Tile Engine"), page);
0145     chkTiles->setChecked(cfg.readEntry("tiles_41004", false));
0146     layout->addWidget(chkTiles);
0147 
0148     QCheckBox *chkFilters = new QCheckBox(i18nc("Filter as an effect", "Filters"), page);
0149     chkFilters->setChecked(cfg.readEntry("filters_41005", false));
0150     layout->addWidget(chkFilters);
0151 
0152     QCheckBox *chkPlugins = new QCheckBox(i18n("Plugin Management"), page);
0153     chkPlugins->setChecked(cfg.readEntry("plugins_41006", false));
0154     layout->addWidget(chkPlugins);
0155 
0156     QCheckBox *chkUi = new QCheckBox(i18n("User Interface"), page);
0157     chkUi->setChecked(cfg.readEntry("ui_41007", false));
0158     layout->addWidget(chkUi);
0159 
0160     QCheckBox *chkFile = new QCheckBox(i18n("File loading and saving"), page);
0161     chkFile->setChecked(cfg.readEntry("file_41008", false));
0162     layout->addWidget(chkFile);
0163 
0164     QCheckBox *chkMath = new QCheckBox(i18n("Mathematics and calculations"), page);
0165     chkMath->setChecked(cfg.readEntry("math_41009", false));
0166     layout->addWidget(chkMath);
0167 
0168     QCheckBox *chkRender = new QCheckBox(i18n("Image Rendering"), page);
0169     chkRender->setChecked(cfg.readEntry("render_41010", false));
0170     layout->addWidget(chkRender);
0171 
0172     QCheckBox *chkScript = new QCheckBox(i18n("Scripting"), page);
0173     chkScript->setChecked(cfg.readEntry("script_41011", false));
0174     layout->addWidget(chkScript);
0175 
0176     QCheckBox *chkInput = new QCheckBox(i18n("Input handling"), page);
0177     chkInput->setChecked(cfg.readEntry("input_41012", false));
0178     layout->addWidget(chkInput);
0179 
0180     QCheckBox *chkAction = new QCheckBox(i18n("Actions"), page);
0181     chkAction->setChecked(cfg.readEntry("action_41013", false));
0182     layout->addWidget(chkAction);
0183 
0184     QCheckBox *chkTablet = new QCheckBox(i18n("Tablet Handling"), page);
0185     chkTablet->setChecked(cfg.readEntry("tablet_41014", false));
0186     layout->addWidget(chkTablet);
0187 
0188     QCheckBox *chkOpenGL = new QCheckBox(i18n("GPU Canvas"), page);
0189     chkOpenGL->setChecked(cfg.readEntry("opengl_41015", false));
0190     layout->addWidget(chkOpenGL);
0191 
0192     QCheckBox *chkMetaData = new QCheckBox(i18n("Metadata"), page);
0193     chkMetaData->setChecked(cfg.readEntry("metadata_41016", false));
0194     layout->addWidget(chkMetaData);
0195 
0196     QCheckBox *chkPigment = new QCheckBox(i18n("Color Management"), page);
0197     chkPigment->setChecked(cfg.readEntry("pigment", false));
0198     layout->addWidget(chkPigment);
0199 
0200 
0201     if (dlg.exec()) {
0202         // Apply the new settings
0203         cfg.writeEntry("resources_30009", chkResources->isChecked());
0204         cfg.writeEntry("krita_41000", chkKrita->isChecked());
0205         cfg.writeEntry("image_41001", chkImage->isChecked());
0206         cfg.writeEntry("registry_41002", chkRegistry->isChecked());
0207         cfg.writeEntry("tools_41003", chkTools->isChecked());
0208         cfg.writeEntry("tiles_41004", chkTiles->isChecked());
0209         cfg.writeEntry("filters_41005", chkFilters->isChecked());
0210         cfg.writeEntry("plugins_41006", chkPlugins->isChecked());
0211         cfg.writeEntry("ui_41007", chkUi->isChecked());
0212         cfg.writeEntry("file_41008", chkFile->isChecked());
0213         cfg.writeEntry("math_41009", chkMath->isChecked());
0214         cfg.writeEntry("render_41010", chkRender->isChecked());
0215         cfg.writeEntry("script_41011", chkScript->isChecked());
0216         cfg.writeEntry("input_41012", chkInput->isChecked());
0217         cfg.writeEntry("action_41013", chkAction->isChecked());
0218         cfg.writeEntry("tablet_41014", chkTablet->isChecked());
0219         cfg.writeEntry("opengl_41015", chkOpenGL->isChecked());
0220         cfg.writeEntry("metadata_41016", chkMetaData->isChecked());
0221         cfg.writeEntry("pigment", chkPigment->isChecked());
0222 
0223         if (bnToggle->isChecked()) {
0224             applyCategories();
0225         }
0226     }
0227 
0228 }
0229 
0230 QString cfgToString(const char *category, bool cfg)
0231 {
0232     if (cfg) {
0233         return QStringLiteral("%0=true").arg(QLatin1String(category));
0234     }
0235     return QStringLiteral("%0.debug=false").arg(QLatin1String(category));
0236 }
0237 
0238 void LogDockerDock::applyCategories()
0239 {
0240     QStringList filters;
0241     KConfigGroup cfg( KSharedConfig::openConfig(), "LogDocker");
0242 
0243     filters << cfgToString("krita.general", cfg.readEntry("krita_41000", false));
0244     filters << cfgToString("krita.lib.resources", cfg.readEntry("resources_30009", false));
0245     filters << cfgToString("krita.core", cfg.readEntry("image_41001", false));
0246     filters << cfgToString("krita.registry", cfg.readEntry("registry_41002", false));
0247 
0248     filters << cfgToString("krita.tools", cfg.readEntry("tools_41003", false));
0249     filters << cfgToString("krita.lib.flake", cfg.readEntry("tools_41003", false));
0250 
0251     filters << cfgToString("krita.tiles", cfg.readEntry("tiles_41004", false));
0252     filters << cfgToString("krita.filters", cfg.readEntry("filters_41005", false));
0253 
0254     filters << cfgToString("krita.plugins", cfg.readEntry("plugins_41006", false));
0255     filters << cfgToString("krita.lib.plugin", cfg.readEntry("plugins_41006", false));
0256 
0257     filters << cfgToString("krita.ui", cfg.readEntry("ui_41007", false));
0258     filters << cfgToString("krita.widgets", cfg.readEntry("ui_41007", false));
0259     filters << cfgToString("krita.widgetutils", cfg.readEntry("ui_41007", false));
0260 
0261     filters << cfgToString("krita.file", cfg.readEntry("file_41008", false));
0262     filters << cfgToString("krita.lib.store", cfg.readEntry("file_41008", false));
0263     filters << cfgToString("krita.lib.odf", cfg.readEntry("file_41008", false));
0264 
0265     filters << cfgToString("krita.math", cfg.readEntry("math_41009", false));
0266     filters << cfgToString("krita.grender", cfg.readEntry("render_41010", false));
0267     filters << cfgToString("krita.scripting", cfg.readEntry("script_41011", false));
0268     filters << cfgToString("krita.input", cfg.readEntry("input_41012", false));
0269     filters << cfgToString("krita.action", cfg.readEntry("action_41013", false));
0270     filters << cfgToString("krita.tablet", cfg.readEntry("tablet_41014", false));
0271     filters << cfgToString("krita.opengl", cfg.readEntry("opengl_41015", false));
0272     filters << cfgToString("krita.metadata", cfg.readEntry("metadata_41016", false));
0273 
0274     filters << cfgToString("krita.lib.pigment", cfg.readEntry("pigment", false));
0275 
0276     QLoggingCategory::setFilterRules(filters.join("\n"));
0277 }
0278 
0279 void LogDockerDock::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
0280 {
0281     s_messageSender->sendMessage(type, msg);
0282     if (s_originalMessageHandler) {
0283         s_originalMessageHandler(type, context, msg);
0284     }
0285 }
0286 
0287 void LogDockerDock::insertMessage(QtMsgType type, const QString &msg)
0288 {
0289     QTextDocument *doc = txtLogViewer->document();
0290     QTextCursor cursor(doc);
0291     cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
0292     cursor.beginEditBlock();
0293 
0294     switch (type) {
0295     case QtDebugMsg:
0296         cursor.insertText(msg + "\n", s_debug);
0297         break;
0298     case QtInfoMsg:
0299         cursor.insertText(msg + "\n", s_info);
0300         break;
0301     case QtWarningMsg:
0302         cursor.insertText(msg + "\n", s_warning);
0303         break;
0304     case QtCriticalMsg:
0305         cursor.insertText(msg + "\n", s_critical);
0306         break;
0307     case QtFatalMsg:
0308         cursor.insertText(msg + "\n", s_fatal);
0309         break;
0310     }
0311 
0312     cursor.endEditBlock();
0313     txtLogViewer->verticalScrollBar()->setValue(txtLogViewer->verticalScrollBar()->maximum());
0314 }
0315 
0316 void LogDockerDock::changeTheme()
0317 {
0318     clearLog();
0319     QColor background = qApp->palette().window().color();
0320     if (background.value() > 100) {
0321         s_debug.setForeground(Qt::black);
0322         s_info.setForeground(Qt::darkGreen);
0323         s_warning.setForeground(Qt::darkYellow);
0324         s_critical.setForeground(Qt::darkRed);
0325         s_fatal.setForeground(Qt::darkRed);
0326     }
0327     else {
0328         s_debug.setForeground(Qt::white);
0329         s_info.setForeground(Qt::green);
0330         s_warning.setForeground(Qt::yellow);
0331         s_critical.setForeground(Qt::red);
0332         s_fatal.setForeground(Qt::red);
0333     }
0334     s_fatal.setFontWeight(QFont::Bold);
0335 }
0336 
0337 void MessageSender::sendMessage(QtMsgType type, const QString &msg)
0338 {
0339     emit emitMessage(type, msg);
0340 }