Fix doc path
[opentx.git] / companion / src / appdebugmessagehandler.cpp
blob0a75d7949770be9f4e4e776874b9a933b749cdae
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include "appdebugmessagehandler.h"
23 #include <QFileDevice>
25 AppDebugMessageHandler::AppDebugMessageHandler(QObject * parent) :
26 QObject(parent),
27 m_appDebugOutputLevel(APP_DBG_HANDLER_DEFAULT_LEVEL),
28 m_showSourcePath(APP_DBG_HANDLER_SHOW_SRC_PATH),
29 m_showFunctionDeclarations(APP_DBG_HANDLER_SHOW_FUNCTION_DECL)
31 m_srcPathFilter = QRegularExpression("^" APP_DBG_HANDLER_SRC_PATH "[\\\\\\/](.*?)$", QRegularExpression::InvertedGreedinessOption);
32 m_functionFilter = QRegularExpression("^.+?(\\w+\\().+$");
35 AppDebugMessageHandler * AppDebugMessageHandler::instance()
37 static AppDebugMessageHandler * _instance = NULL;
38 #if APP_DBG_HANDLER_ENABLE
39 if(_instance == NULL && !qApp->closingDown())
40 _instance = new AppDebugMessageHandler(qApp); // Ensure this object is cleaned up when the QApplication exits.
41 #endif
42 return _instance;
45 void AppDebugMessageHandler::setAppDebugOutputLevel(const quint8 & appDebugOutputLevel)
47 m_appDebugOutputLevel = appDebugOutputLevel;
50 void AppDebugMessageHandler::setShowSourcePath(bool showSourcePath)
52 m_showSourcePath = showSourcePath;
55 void AppDebugMessageHandler::setShowFunctionDeclarations(bool showFunctionDeclarations)
57 m_showFunctionDeclarations = showFunctionDeclarations;
60 void AppDebugMessageHandler::addOutputDevice(QIODevice * device)
62 if (device && !m_outputDevices.contains(device))
63 m_outputDevices.append(device);
66 void AppDebugMessageHandler::removeOutputDevice(QIODevice * device)
68 if (device) {
69 // no QVector::removeAll() in Qt < 5.4
70 int i = 0;
71 foreach (QIODevice * d, m_outputDevices) {
72 if (d == device)
73 m_outputDevices.remove(i);
74 ++i;
79 void AppDebugMessageHandler::installAppMessageHandler()
81 m_defaultHandler = qInstallMessageHandler(g_appDebugMessageHandler);
84 void AppDebugMessageHandler::messageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
86 static const char symbols[] = { 'D', 'W', 'E', 'X', 'I' }; // correspond to QtMsgType enum
87 // normalize types, QtDebugMsg stays 0, QtInfoMsg becomes 1, rest are QtMsgType + 1
88 quint8 lvl = type;
89 if (type == QtInfoMsg)
90 lvl = 1;
91 else if (type > QtDebugMsg)
92 ++lvl;
94 if (lvl < m_appDebugOutputLevel && type != QtFatalMsg)
95 return;
97 #if defined(Q_OS_LINUX) && (QT_VERSION < QT_VERSION_CHECK(5, 3, 0))
98 // Filter out lots of QPainter warnings from undocked QDockWidgets... hackish but effective (only workaround found so far)
99 if (lvl == 2 && QString(context.function).contains("QPainter::"))
100 return;
101 #endif
103 QString msgPattern = QString("[%1] ").arg(symbols[type]);
105 if (m_showSourcePath) {
106 QString file = QString("%1::").arg(context.file);
107 file.replace(m_srcPathFilter, "\\1");
108 msgPattern.append(file);
110 if (m_showFunctionDeclarations)
111 msgPattern.append(context.function);
112 else
113 msgPattern.append("%{function}()");
115 msgPattern.append(":%{line} -%{if-category} [%{category}]%{endif} %{message}");
117 if (type == QtFatalMsg)
118 msgPattern.append("\nBACKTRACE:\n%{backtrace depth=12 separator=\"\n\"}");
120 qSetMessagePattern(msgPattern);
122 if (!m_defaultHandler || m_outputDevices.size() || receivers(SIGNAL(messageOutput(quint8, const QString &)))) {
123 #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
124 msgPattern = qFormatLogMessage(type, context, msg);
125 #else
126 msgPattern.replace("%{line}", QString::number(context.line));
127 msgPattern.replace("%{if-category} [%{category}]%{endif}", QString(context.category));
128 msgPattern.replace("%{message}", msg);
129 if (!m_showFunctionDeclarations) {
130 QString func = context.function;
131 msgPattern.replace("%{function}", func.replace(m_functionFilter, "\\1)"));
133 #endif
135 emit messageOutput(lvl, msgPattern);
137 foreach (QIODevice * d, m_outputDevices) {
138 if (d && d->isWritable() && (!d->property("level").isValid() || d->property("level").toInt() <= lvl)) {
139 d->write(qPrintable(msgPattern % "\n"));
140 if (QFileDevice * fd = qobject_cast<QFileDevice *>(d))
141 fd->flush();
146 // if (QThread::currentThread() == qApp->thread()) // gui thread
148 if (m_defaultHandler) {
149 m_defaultHandler(type, context, msg);
151 else {
152 fprintf(stderr, "%s", qPrintable(msgPattern));
153 if (type == QtFatalMsg)
154 abort();
158 // Message handler which is installed using qInstallMessageHandler. This needs to be global.
159 void g_appDebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
161 if (AppDebugMessageHandler::instance())
162 AppDebugMessageHandler::instance()->messageHandler(type, context, msg);