1 /*
2  *  Copyright (c) 2018 Boudewijn Rempt <boud@valdyas.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 
20 #include "LogDockerDock.h"
21 
22 #include <QHBoxLayout>
23 #include <QToolButton>
24 #include <QScrollBar>
25 #include <QStandardPaths>
26 #include <QDateTime>
27 #include <QCheckBox>
28 
29 #include <klocalizedstring.h>
30 #include <ksharedconfig.h>
31 #include <kconfiggroup.h>
32 
33 #include <KisPart.h>
34 #include <KoDialog.h>
35 #include <KoCanvasBase.h>
36 #include <KoIcon.h>
37 #include <KoFileDialog.h>
38 
39 #include "kis_canvas2.h"
40 #include "KisViewManager.h"
41 #include "kis_config.h"
42 
43 MessageSender *LogDockerDock::s_messageSender {new MessageSender()};
44 QTextCharFormat LogDockerDock::s_debug;
45 QTextCharFormat LogDockerDock::s_info;
46 QTextCharFormat LogDockerDock::s_warning;
47 QTextCharFormat LogDockerDock::s_critical;
48 QTextCharFormat LogDockerDock::s_fatal;
49 
LogDockerDock()50 LogDockerDock::LogDockerDock( )
51     : QDockWidget(i18n("Log Viewer"))
52 {
53     QWidget *page = new QWidget(this);
54     setupUi(page);
55     setWidget(page);
56 
57     bnToggle->setIcon(koIcon("view-list-text"));
58     connect(bnToggle, SIGNAL(clicked(bool)), SLOT(toggleLogging(bool)));
59     bnToggle->setChecked(KisConfig(true).readEntry<bool>("logviewer_enabled", false));
60     toggleLogging(KisConfig(true).readEntry<bool>("logviewer_enabled", false));
61 
62     bnClear->setIcon(koIcon("edit-clear"));
63     connect(bnClear, SIGNAL(clicked(bool)), SLOT(clearLog()));
64 
65     bnSave->setIcon(koIcon("document-save"));
66     connect(bnSave, SIGNAL(clicked(bool)), SLOT(saveLog()));
67 
68     bnSettings->setIcon(koIcon("configure"));
69     connect(bnSettings, SIGNAL(clicked(bool)), SLOT(settings()));
70 
71     qRegisterMetaType<QtMsgType>("QtMsgType");
72     connect(s_messageSender, SIGNAL(emitMessage(QtMsgType,QString)), this, SLOT(insertMessage(QtMsgType,QString)), Qt::AutoConnection);
73 
74     applyCategories();
75     changeTheme();
76 }
77 
setCanvas(KoCanvasBase *)78 void LogDockerDock::setCanvas(KoCanvasBase *)
79 {
80     setEnabled(true);
81 }
82 
setViewManager(KisViewManager * kisview)83 void LogDockerDock::setViewManager(KisViewManager *kisview)
84 {
85     connect(static_cast<KisMainWindow*>(kisview->mainWindow()), SIGNAL(themeChanged()), SLOT(changeTheme()));
86 }
87 
toggleLogging(bool toggle)88 void LogDockerDock::toggleLogging(bool toggle)
89 {
90     KisConfig(false).writeEntry<bool>("logviewer_enabled", toggle);
91     if (toggle) {
92         qInstallMessageHandler(messageHandler);
93         applyCategories();
94     }
95     else {
96         qInstallMessageHandler(0);
97     }
98 
99 }
100 
clearLog()101 void LogDockerDock::clearLog()
102 {
103     txtLogViewer->document()->clear();
104 }
105 
saveLog()106 void LogDockerDock::saveLog()
107 {
108     KoFileDialog fileDialog(this, KoFileDialog::SaveFile, "logfile");
109     fileDialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + "/" + QString("krita_%1.log").arg(QDateTime::currentDateTime().toString()));
110     QString filename = fileDialog.filename();
111     if (!filename.isEmpty()) {
112         QFile f(filename);
113         f.open(QFile::WriteOnly);
114         f.write(txtLogViewer->document()->toPlainText().toUtf8());
115         f.close();
116     }
117 }
118 
settings()119 void LogDockerDock::settings()
120 {
121     KoDialog dlg(this);
122     dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
123     dlg.setCaption(i18n("Log Settings"));
124     QWidget *page = new QWidget(&dlg);
125     dlg.setMainWidget(page);
126     QVBoxLayout *layout = new QVBoxLayout(page);
127 
128     KConfigGroup cfg( KSharedConfig::openConfig(), "LogDocker");
129 
130     QCheckBox *chkKrita = new QCheckBox(i18n("General"), page);
131     chkKrita->setChecked(cfg.readEntry("krita_41000", false));
132     layout->addWidget(chkKrita);
133 
134     QCheckBox *chkResources = new QCheckBox(i18n("Resource Management"), page);
135     chkResources->setChecked(cfg.readEntry("resources_30009", false));
136     layout->addWidget(chkResources);
137 
138     QCheckBox *chkImage = new QCheckBox(i18n("Image Core"), page);
139     chkImage->setChecked(cfg.readEntry("image_41001", false));
140     layout->addWidget(chkImage);
141 
142     QCheckBox *chkRegistry = new QCheckBox(i18n("Registries"), page);
143     chkRegistry->setChecked(cfg.readEntry("registry_41002", false));
144     layout->addWidget(chkRegistry);
145 
146     QCheckBox *chkTools = new QCheckBox(i18n("Tools"), page);
147     chkTools->setChecked(cfg.readEntry("tools_41003", false));
148     layout->addWidget(chkTools);
149 
150     QCheckBox *chkTiles = new QCheckBox(i18n("Tile Engine"), page);
151     chkTiles->setChecked(cfg.readEntry("tiles_41004", false));
152     layout->addWidget(chkTiles);
153 
154     QCheckBox *chkFilters = new QCheckBox(i18n("Filters"), page);
155     chkFilters->setChecked(cfg.readEntry("filters_41005", false));
156     layout->addWidget(chkFilters);
157 
158     QCheckBox *chkPlugins = new QCheckBox(i18n("Plugin Management"), page);
159     chkPlugins->setChecked(cfg.readEntry("plugins_41006", false));
160     layout->addWidget(chkPlugins);
161 
162     QCheckBox *chkUi = new QCheckBox(i18n("User Interface"), page);
163     chkUi->setChecked(cfg.readEntry("ui_41007", false));
164     layout->addWidget(chkUi);
165 
166     QCheckBox *chkFile = new QCheckBox(i18n("File loading and saving"), page);
167     chkFile->setChecked(cfg.readEntry("file_41008", false));
168     layout->addWidget(chkFile);
169 
170     QCheckBox *chkMath = new QCheckBox(i18n("Mathematics and calculations"), page);
171     chkMath->setChecked(cfg.readEntry("math_41009", false));
172     layout->addWidget(chkMath);
173 
174     QCheckBox *chkRender = new QCheckBox(i18n("Image Rendering"), page);
175     chkRender->setChecked(cfg.readEntry("render_41010", false));
176     layout->addWidget(chkRender);
177 
178     QCheckBox *chkScript = new QCheckBox(i18n("Scripting"), page);
179     chkScript->setChecked(cfg.readEntry("script_41011", false));
180     layout->addWidget(chkScript);
181 
182     QCheckBox *chkInput = new QCheckBox(i18n("Input handling"), page);
183     chkInput->setChecked(cfg.readEntry("input_41012", false));
184     layout->addWidget(chkInput);
185 
186     QCheckBox *chkAction = new QCheckBox(i18n("Actions"), page);
187     chkAction->setChecked(cfg.readEntry("action_41013", false));
188     layout->addWidget(chkAction);
189 
190     QCheckBox *chkTablet = new QCheckBox(i18n("Tablet Handling"), page);
191     chkTablet->setChecked(cfg.readEntry("tablet_41014", false));
192     layout->addWidget(chkTablet);
193 
194     QCheckBox *chkOpenGL = new QCheckBox(i18n("GPU Canvas"), page);
195     chkOpenGL->setChecked(cfg.readEntry("opengl_41015", false));
196     layout->addWidget(chkOpenGL);
197 
198     QCheckBox *chkMetaData = new QCheckBox(i18n("Metadata"), page);
199     chkMetaData->setChecked(cfg.readEntry("metadata_41016", false));
200     layout->addWidget(chkMetaData);
201 
202     QCheckBox *chkPigment = new QCheckBox(i18n("Color Management"), page);
203     chkPigment->setChecked(cfg.readEntry("pigment", false));
204     layout->addWidget(chkPigment);
205 
206 
207     if (dlg.exec()) {
208         // Apply the new settings
209         cfg.writeEntry("resources_30009", chkResources->isChecked());
210         cfg.writeEntry("krita_41000", chkKrita->isChecked());
211         cfg.writeEntry("image_41001", chkImage->isChecked());
212         cfg.writeEntry("registry_41002", chkRegistry->isChecked());
213         cfg.writeEntry("tools_41003", chkTools->isChecked());
214         cfg.writeEntry("tiles_41004", chkTiles->isChecked());
215         cfg.writeEntry("filters_41005", chkFilters->isChecked());
216         cfg.writeEntry("plugins_41006", chkPlugins->isChecked());
217         cfg.writeEntry("ui_41007", chkUi->isChecked());
218         cfg.writeEntry("file_41008", chkFile->isChecked());
219         cfg.writeEntry("math_41009", chkMath->isChecked());
220         cfg.writeEntry("render_41010", chkRender->isChecked());
221         cfg.writeEntry("script_41011", chkScript->isChecked());
222         cfg.writeEntry("input_41012", chkInput->isChecked());
223         cfg.writeEntry("action_41013", chkAction->isChecked());
224         cfg.writeEntry("tablet_41014", chkTablet->isChecked());
225         cfg.writeEntry("opengl_41015", chkOpenGL->isChecked());
226         cfg.writeEntry("metadata_41016", chkMetaData->isChecked());
227         cfg.writeEntry("pigment", chkPigment->isChecked());
228 
229         applyCategories();
230     }
231 
232 }
233 
cfgToString(QString tpl,bool cfg)234 QString cfgToString(QString tpl, bool cfg)
235 {
236     return tpl.arg(cfg ? "true" : "false");
237 }
238 
applyCategories()239 void LogDockerDock::applyCategories()
240 {
241     QStringList filters;
242     KConfigGroup cfg( KSharedConfig::openConfig(), "LogDocker");
243 
244     filters << cfgToString("krita.general=%1", cfg.readEntry("krita_41000", false));
245     filters << cfgToString("krita.lib.resources=%1", cfg.readEntry("resources_30009", false));
246     filters << cfgToString("krita.core=%1", cfg.readEntry("image_41001", false));
247     filters << cfgToString("krita.registry=%1", cfg.readEntry("registry_41002", false));
248 
249     filters << cfgToString("krita.tools=%1", cfg.readEntry("tools_41003", false));
250     filters << cfgToString("krita.lib.flake=%1", cfg.readEntry("tools_41003", false));
251 
252     filters << cfgToString("krita.tiles=%1", cfg.readEntry("tiles_41004", false));
253     filters << cfgToString("krita.filters=%1", cfg.readEntry("filters_41005", false));
254 
255     filters << cfgToString("krita.plugins=%1", cfg.readEntry("plugins_41006", false));
256     filters << cfgToString("krita.lib.plugin=%1", cfg.readEntry("plugins_41006", false));
257 
258     filters << cfgToString("krita.ui=%1", cfg.readEntry("ui_41007", false));
259     filters << cfgToString("krita.widgets=%1", cfg.readEntry("ui_41007", false));
260     filters << cfgToString("krita.widgetutils=%1", cfg.readEntry("ui_41007", false));
261 
262     filters << cfgToString("krita.file=%1", cfg.readEntry("file_41008", false));
263     filters << cfgToString("krita.lib.store=%1", cfg.readEntry("file_41008", false));
264     filters << cfgToString("krita.lib.odf=%1", cfg.readEntry("file_41008", false));
265 
266     filters << cfgToString("krita.math=%1", cfg.readEntry("math_41009", false));
267     filters << cfgToString("krita.grender=%1", cfg.readEntry("render_41010", false));
268     filters << cfgToString("krita.scripting=%1", cfg.readEntry("script_41011", false));
269     filters << cfgToString("krita.input=%1", cfg.readEntry("input_41012", false));
270     filters << cfgToString("krita.action=%1", cfg.readEntry("action_41013", false));
271     filters << cfgToString("krita.tablet=%1", cfg.readEntry("tablet_41014", false));
272     filters << cfgToString("krita.opengl=%1", cfg.readEntry("opengl_41015", false));
273     filters << cfgToString("krita.metadata=%1", cfg.readEntry("metadata_41016", false));
274 
275     filters << cfgToString("krita.lib.pigment=%1", cfg.readEntry("pigment", false));
276 
277     QLoggingCategory::setFilterRules(filters.join("\n"));
278 }
279 
messageHandler(QtMsgType type,const QMessageLogContext &,const QString & msg)280 void LogDockerDock::messageHandler(QtMsgType type, const QMessageLogContext &/*context*/, const QString &msg)
281 {
282     s_messageSender->sendMessage(type, msg);
283 }
284 
insertMessage(QtMsgType type,const QString & msg)285 void LogDockerDock::insertMessage(QtMsgType type, const QString &msg)
286 {
287     QTextDocument *doc = txtLogViewer->document();
288     QTextCursor cursor(doc);
289     cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
290     cursor.beginEditBlock();
291 
292     switch (type) {
293     case QtDebugMsg:
294         cursor.insertText(msg + "\n", s_debug);
295         break;
296     case QtInfoMsg:
297         cursor.insertText(msg + "\n", s_info);
298         break;
299     case QtWarningMsg:
300         cursor.insertText(msg + "\n", s_warning);
301         break;
302     case QtCriticalMsg:
303         cursor.insertText(msg + "\n", s_critical);
304         break;
305     case QtFatalMsg:
306         cursor.insertText(msg + "\n", s_fatal);
307         break;
308     }
309 
310     cursor.endEditBlock();
311     txtLogViewer->verticalScrollBar()->setValue(txtLogViewer->verticalScrollBar()->maximum());
312 }
313 
changeTheme()314 void LogDockerDock::changeTheme()
315 {
316     clearLog();
317     QColor background = qApp->palette().window().color();
318     if (background.value() > 100) {
319         s_debug.setForeground(Qt::black);
320         s_info.setForeground(Qt::darkGreen);
321         s_warning.setForeground(Qt::darkYellow);
322         s_critical.setForeground(Qt::darkRed);
323         s_fatal.setForeground(Qt::darkRed);
324     }
325     else {
326         s_debug.setForeground(Qt::white);
327         s_info.setForeground(Qt::green);
328         s_warning.setForeground(Qt::yellow);
329         s_critical.setForeground(Qt::red);
330         s_fatal.setForeground(Qt::red);
331     }
332     s_fatal.setFontWeight(QFont::Bold);
333 }
334 
sendMessage(QtMsgType type,const QString & msg)335 void MessageSender::sendMessage(QtMsgType type, const QString &msg)
336 {
337     emit emitMessage(type, msg);
338 }
339