Krita Source Code Documentation
Loading...
Searching...
No Matches
LogDockerDock.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7
8#include "LogDockerDock.h"
9
10#include <QHBoxLayout>
11#include <QScrollBar>
12#include <QStandardPaths>
13#include <QDateTime>
14#include <QCheckBox>
15#include <QMessageBox>
16
17#include <klocalizedstring.h>
18#include <ksharedconfig.h>
19#include <kconfiggroup.h>
20
21#include <KisPart.h>
22#include <KoDialog.h>
23#include <KoCanvasBase.h>
24#include <KoIcon.h>
25#include <KoFileDialog.h>
26
27#include "kis_canvas2.h"
28#include "KisViewManager.h"
29#include "KisMainWindow.h"
30#include "kis_config.h"
31
32#include <QThread>
33#include <QMutex>
34#include <QWaitCondition>
35#include <QGlobalStatic>
37
38QTextCharFormat LogDockerDock::s_debug;
39QTextCharFormat LogDockerDock::s_info;
40QTextCharFormat LogDockerDock::s_warning;
41QTextCharFormat LogDockerDock::s_critical;
42QTextCharFormat LogDockerDock::s_fatal;
43
45 qRegisterMetaType<QtMsgType>("QtMsgType");
46}
47
55class MessageForwarderThread : public QThread
56{
57 Q_OBJECT
58public:
59 void run() override {
60 while (1) {
61 QMutexLocker locker(&m_mutex);
63 if (m_exitFlag) break;
64
65 while (!m_messages.empty()) {
66 auto message = m_messages.dequeue();
67 Q_EMIT sigDeliverMessage(message.first, message.second);
68 }
69 }
70 }
71
72 void pushMessage(QtMsgType type, const QString &message) {
73 QMutexLocker locker(&m_mutex);
74 m_messages.enqueue(std::make_pair(type, message));
75 locker.unlock();
76 m_waitCondition.wakeAll();
77 }
78
79 void pushExitFlag() {
80 QMutexLocker locker(&m_mutex);
81 m_exitFlag = true;
82 locker.unlock();
83 m_waitCondition.wakeAll();
84 }
85
86Q_SIGNALS:
87 void sigDeliverMessage(QtMsgType type, const QString &message);
88
89
90private:
91 QMutex m_mutex;
92 QWaitCondition m_waitCondition;
93 QQueue<std::pair<QtMsgType, QString>> m_messages;
94 bool m_exitFlag {false};
95};
96
102void kritaLoggerMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
103
112class MessageHandler : public QObject
113{
114 Q_OBJECT
115public:
117 setLoggingEnabled(false);
118 }
119
121 if (value == isLoggingEnabled()) return;
122
123 if (value) {
124 const QtMessageHandler oldHandler = qInstallMessageHandler(kritaLoggerMessageHandler);
125 m_originalMessageHandler = oldHandler;
128 m_forwarderThread->start();
129 } else {
130 qInstallMessageHandler(nullptr);
131 m_originalMessageHandler = nullptr;
132 m_forwarderThread->pushExitFlag();
133 m_forwarderThread->wait();
134 m_forwarderThread.reset();
135 }
136 }
137
138 bool isLoggingEnabled() const {
140 }
141
142Q_SIGNALS:
143 void sigDeliverMessage(QtMsgType type, const QString &message);
144
145public:
146 QtMessageHandler m_originalMessageHandler {nullptr};
147 std::unique_ptr<MessageForwarderThread> m_forwarderThread;
148};
149
150Q_GLOBAL_STATIC(MessageHandler, s_messageHandlerObject)
151
152void kritaLoggerMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
153{
154 KIS_SAFE_ASSERT_RECOVER_RETURN(s_messageHandlerObject->m_forwarderThread);
155 KIS_SAFE_ASSERT_RECOVER_RETURN(s_messageHandlerObject->m_originalMessageHandler);
156
157 s_messageHandlerObject->m_forwarderThread->pushMessage(type, message);
158 s_messageHandlerObject->m_originalMessageHandler(type, context, message);
159}
160
162 : QDockWidget(i18n("Log Viewer"))
163{
164 QWidget *page = new QWidget(this);
165 setupUi(page);
166 setWidget(page);
167
168 bnToggle->setIcon(koIcon("view-list-text-16"));
169 connect(bnToggle, SIGNAL(clicked(bool)), SLOT(toggleLogging(bool)));
170 bnToggle->setChecked(KisConfig(true).readEntry<bool>("logviewer_enabled", false));
171 toggleLogging(KisConfig(true).readEntry<bool>("logviewer_enabled", false));
172
173 bnClear->setIcon(koIcon("edit-clear-16"));
174 connect(bnClear, SIGNAL(clicked(bool)), SLOT(clearLog()));
175
176 bnSave->setIcon(koIcon("document-save-16"));
177 connect(bnSave, SIGNAL(clicked(bool)), SLOT(saveLog()));
178
179 bnSettings->setIcon(koIcon("configure-thicker"));
180 connect(bnSettings, SIGNAL(clicked(bool)), SLOT(settings()));
181
182 connect(s_messageHandlerObject, SIGNAL(sigDeliverMessage(QtMsgType,QString)), this, SLOT(insertMessage(QtMsgType,QString)), Qt::AutoConnection);
183
184 changeTheme();
185}
186
188{
189 setEnabled(true);
190}
191
193{
194 connect(kisview->mainWindow(), SIGNAL(themeChanged()), SLOT(changeTheme()));
195}
196
198{
199 KisConfig(false).writeEntry<bool>("logviewer_enabled", toggle);
200
201 if (toggle) {
203 } else {
204 QLoggingCategory::setFilterRules(QString());
205 }
206
207 s_messageHandlerObject->setLoggingEnabled(toggle);
208}
209
211{
212 txtLogViewer->document()->clear();
213}
214
216{
217 KoFileDialog fileDialog(this, KoFileDialog::SaveFile, "logfile");
218 fileDialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + "/" + QString("krita_%1.log").arg(QDateTime::currentDateTime().toString("yyyy-MM-ddThh")));
219 QString filename = fileDialog.filename();
220 if (!filename.isEmpty()) {
221 QFile f(filename);
222 if (f.open(QFile::WriteOnly)) {
223 f.write(txtLogViewer->document()->toPlainText().toUtf8());
224 f.close();
225 } else {
226 QMessageBox::warning(this, i18nc("@title:window", "Krita"),
227 i18n("Could not save %1.\nReason: %2.", f.fileName(), f.errorString()));
228 }
229 }
230}
231
233{
234 KoDialog dlg(this);
236 dlg.setCaption(i18n("Log Settings"));
237 QWidget *page = new QWidget(&dlg);
238 dlg.setMainWidget(page);
239 QVBoxLayout *layout = new QVBoxLayout(page);
240
241 KConfigGroup cfg( KSharedConfig::openConfig(), "LogDocker");
242
243 QCheckBox *chkKrita = new QCheckBox(i18n("General"), page);
244 chkKrita->setChecked(cfg.readEntry("krita_41000", false));
245 layout->addWidget(chkKrita);
246
247 QCheckBox *chkResources = new QCheckBox(i18n("Resource Management"), page);
248 chkResources->setChecked(cfg.readEntry("resources_30009", false));
249 layout->addWidget(chkResources);
250
251 QCheckBox *chkImage = new QCheckBox(i18n("Image Core"), page);
252 chkImage->setChecked(cfg.readEntry("image_41001", false));
253 layout->addWidget(chkImage);
254
255 QCheckBox *chkRegistry = new QCheckBox(i18n("Registries"), page);
256 chkRegistry->setChecked(cfg.readEntry("registry_41002", false));
257 layout->addWidget(chkRegistry);
258
259 QCheckBox *chkTools = new QCheckBox(i18n("Tools"), page);
260 chkTools->setChecked(cfg.readEntry("tools_41003", false));
261 layout->addWidget(chkTools);
262
263 QCheckBox *chkTiles = new QCheckBox(i18n("Tile Engine"), page);
264 chkTiles->setChecked(cfg.readEntry("tiles_41004", false));
265 layout->addWidget(chkTiles);
266
267 QCheckBox *chkFilters = new QCheckBox(i18nc("Filter as an effect", "Filters"), page);
268 chkFilters->setChecked(cfg.readEntry("filters_41005", false));
269 layout->addWidget(chkFilters);
270
271 QCheckBox *chkPlugins = new QCheckBox(i18n("Plugin Management"), page);
272 chkPlugins->setChecked(cfg.readEntry("plugins_41006", false));
273 layout->addWidget(chkPlugins);
274
275 QCheckBox *chkUi = new QCheckBox(i18n("User Interface"), page);
276 chkUi->setChecked(cfg.readEntry("ui_41007", false));
277 layout->addWidget(chkUi);
278
279 QCheckBox *chkFile = new QCheckBox(i18n("File loading and saving"), page);
280 chkFile->setChecked(cfg.readEntry("file_41008", false));
281 layout->addWidget(chkFile);
282
283 QCheckBox *chkMath = new QCheckBox(i18n("Mathematics and calculations"), page);
284 chkMath->setChecked(cfg.readEntry("math_41009", false));
285 layout->addWidget(chkMath);
286
287 QCheckBox *chkRender = new QCheckBox(i18n("Image Rendering"), page);
288 chkRender->setChecked(cfg.readEntry("render_41010", false));
289 layout->addWidget(chkRender);
290
291 QCheckBox *chkScript = new QCheckBox(i18n("Scripting"), page);
292 chkScript->setChecked(cfg.readEntry("script_41011", false));
293 layout->addWidget(chkScript);
294
295 QCheckBox *chkInput = new QCheckBox(i18n("Input handling"), page);
296 chkInput->setChecked(cfg.readEntry("input_41012", false));
297 layout->addWidget(chkInput);
298
299 QCheckBox *chkAction = new QCheckBox(i18n("Actions"), page);
300 chkAction->setChecked(cfg.readEntry("action_41013", false));
301 layout->addWidget(chkAction);
302
303 QCheckBox *chkTablet = new QCheckBox(i18n("Tablet Handling"), page);
304 chkTablet->setChecked(cfg.readEntry("tablet_41014", false));
305 layout->addWidget(chkTablet);
306
307 QCheckBox *chkOpenGL = new QCheckBox(i18n("GPU Canvas"), page);
308 chkOpenGL->setChecked(cfg.readEntry("opengl_41015", false));
309 layout->addWidget(chkOpenGL);
310
311 QCheckBox *chkMetaData = new QCheckBox(i18n("Metadata"), page);
312 chkMetaData->setChecked(cfg.readEntry("metadata_41016", false));
313 layout->addWidget(chkMetaData);
314
315 QCheckBox *chkPigment = new QCheckBox(i18n("Color Management"), page);
316 chkPigment->setChecked(cfg.readEntry("pigment", false));
317 layout->addWidget(chkPigment);
318
319
320 if (dlg.exec()) {
321 // Apply the new settings
322 cfg.writeEntry("resources_30009", chkResources->isChecked());
323 cfg.writeEntry("krita_41000", chkKrita->isChecked());
324 cfg.writeEntry("image_41001", chkImage->isChecked());
325 cfg.writeEntry("registry_41002", chkRegistry->isChecked());
326 cfg.writeEntry("tools_41003", chkTools->isChecked());
327 cfg.writeEntry("tiles_41004", chkTiles->isChecked());
328 cfg.writeEntry("filters_41005", chkFilters->isChecked());
329 cfg.writeEntry("plugins_41006", chkPlugins->isChecked());
330 cfg.writeEntry("ui_41007", chkUi->isChecked());
331 cfg.writeEntry("file_41008", chkFile->isChecked());
332 cfg.writeEntry("math_41009", chkMath->isChecked());
333 cfg.writeEntry("render_41010", chkRender->isChecked());
334 cfg.writeEntry("script_41011", chkScript->isChecked());
335 cfg.writeEntry("input_41012", chkInput->isChecked());
336 cfg.writeEntry("action_41013", chkAction->isChecked());
337 cfg.writeEntry("tablet_41014", chkTablet->isChecked());
338 cfg.writeEntry("opengl_41015", chkOpenGL->isChecked());
339 cfg.writeEntry("metadata_41016", chkMetaData->isChecked());
340 cfg.writeEntry("pigment", chkPigment->isChecked());
341
342 if (bnToggle->isChecked()) {
344 }
345 }
346
347}
348
349QString cfgToString(const char *category, bool cfg)
350{
351 if (cfg) {
352 return QStringLiteral("%0=true").arg(QLatin1String(category));
353 }
354 return QStringLiteral("%0.debug=false").arg(QLatin1String(category));
355}
356
358{
359 QStringList filters;
360 KConfigGroup cfg( KSharedConfig::openConfig(), "LogDocker");
361
362 filters << cfgToString("krita.general", cfg.readEntry("krita_41000", false));
363 filters << cfgToString("krita.lib.resources", cfg.readEntry("resources_30009", false));
364 filters << cfgToString("krita.core", cfg.readEntry("image_41001", false));
365 filters << cfgToString("krita.registry", cfg.readEntry("registry_41002", false));
366
367 filters << cfgToString("krita.tools", cfg.readEntry("tools_41003", false));
368 filters << cfgToString("krita.lib.flake", cfg.readEntry("tools_41003", false));
369
370 filters << cfgToString("krita.tiles", cfg.readEntry("tiles_41004", false));
371 filters << cfgToString("krita.filters", cfg.readEntry("filters_41005", false));
372
373 filters << cfgToString("krita.plugins", cfg.readEntry("plugins_41006", false));
374 filters << cfgToString("krita.lib.plugin", cfg.readEntry("plugins_41006", false));
375
376 filters << cfgToString("krita.ui", cfg.readEntry("ui_41007", false));
377 filters << cfgToString("krita.widgets", cfg.readEntry("ui_41007", false));
378 filters << cfgToString("krita.widgetutils", cfg.readEntry("ui_41007", false));
379
380 filters << cfgToString("krita.file", cfg.readEntry("file_41008", false));
381 filters << cfgToString("krita.lib.store", cfg.readEntry("file_41008", false));
382 filters << cfgToString("krita.lib.odf", cfg.readEntry("file_41008", false));
383
384 filters << cfgToString("krita.math", cfg.readEntry("math_41009", false));
385 filters << cfgToString("krita.grender", cfg.readEntry("render_41010", false));
386 filters << cfgToString("krita.scripting", cfg.readEntry("script_41011", false));
387 filters << cfgToString("krita.input", cfg.readEntry("input_41012", false));
388 filters << cfgToString("krita.action", cfg.readEntry("action_41013", false));
389 filters << cfgToString("krita.tablet", cfg.readEntry("tablet_41014", false));
390 filters << cfgToString("krita.opengl", cfg.readEntry("opengl_41015", false));
391 filters << cfgToString("krita.metadata", cfg.readEntry("metadata_41016", false));
392
393 filters << cfgToString("krita.lib.pigment", cfg.readEntry("pigment", false));
394
395 QLoggingCategory::setFilterRules(filters.join("\n"));
396}
397
398void LogDockerDock::insertMessage(QtMsgType type, const QString &msg)
399{
400 QTextDocument *doc = txtLogViewer->document();
401 QTextCursor cursor(doc);
402 cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
403 cursor.beginEditBlock();
404
405 switch (type) {
406 case QtDebugMsg:
407 cursor.insertText(msg + "\n", s_debug);
408 break;
409 case QtInfoMsg:
410 cursor.insertText(msg + "\n", s_info);
411 break;
412 case QtWarningMsg:
413 cursor.insertText(msg + "\n", s_warning);
414 break;
415 case QtCriticalMsg:
416 cursor.insertText(msg + "\n", s_critical);
417 break;
418 case QtFatalMsg:
419 cursor.insertText(msg + "\n", s_fatal);
420 break;
421 }
422
423 cursor.endEditBlock();
424 txtLogViewer->verticalScrollBar()->setValue(txtLogViewer->verticalScrollBar()->maximum());
425}
426
428{
429 clearLog();
430 QColor background = qApp->palette().window().color();
431 if (background.value() > 100) {
432 s_debug.setForeground(Qt::black);
433 s_info.setForeground(Qt::darkGreen);
434 s_warning.setForeground(Qt::darkYellow);
435 s_critical.setForeground(Qt::darkRed);
436 s_fatal.setForeground(Qt::darkRed);
437 }
438 else {
439 s_debug.setForeground(Qt::white);
440 s_info.setForeground(Qt::green);
441 s_warning.setForeground(Qt::yellow);
442 s_critical.setForeground(Qt::red);
443 s_fatal.setForeground(Qt::red);
444 }
445 s_fatal.setFontWeight(QFont::Bold);
446}
447
448#include <LogDockerDock.moc>
float value(const T *src, size_t ch)
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
QString cfgToString(const char *category, bool cfg)
KIS_DECLARE_STATIC_INITIALIZER
void kritaLoggerMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
void writeEntry(const QString &name, const T &value)
Definition kis_config.h:825
KisMainWindow * mainWindow() const
A dialog base class with standard buttons and predefined layouts.
Definition KoDialog.h:116
void setMainWidget(QWidget *widget)
Definition KoDialog.cpp:345
virtual void setCaption(const QString &caption)
Definition KoDialog.cpp:489
void setButtons(ButtonCodes buttonMask)
Definition KoDialog.cpp:195
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
Definition KoDialog.h:127
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
Definition KoDialog.h:130
QString filename()
Get the file name the user selected in the file dialog.
void setDefaultDir(const QString &defaultDir, bool force=false)
setDefaultDir set the default directory to defaultDir.
static QTextCharFormat s_critical
void setCanvas(KoCanvasBase *canvas) override
void setViewManager(KisViewManager *kisview) override
void insertMessage(QtMsgType type, const QString &msg)
static QTextCharFormat s_info
static QTextCharFormat s_debug
static QTextCharFormat s_warning
void toggleLogging(bool toggle)
static QTextCharFormat s_fatal
QQueue< std::pair< QtMsgType, QString > > m_messages
QWaitCondition m_waitCondition
void pushMessage(QtMsgType type, const QString &message)
void sigDeliverMessage(QtMsgType type, const QString &message)
void setLoggingEnabled(bool value)
bool isLoggingEnabled() const
std::unique_ptr< MessageForwarderThread > m_forwarderThread
void sigDeliverMessage(QtMsgType type, const QString &message)
QtMessageHandler m_originalMessageHandler
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define koIcon(name)
Use these macros for icons without any issues.
Definition kis_icon.h:25
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)