Imported Upstream version 1.1.0
[gammaray-debian.git] / tools / messagehandler / messagehandler.cpp
blob9e7acd5069c10050a507274f8153c94bc8b06f36
1 /*
2 messagehandler.cpp
4 This file is part of GammaRay, the Qt application inspection and
5 manipulation tool.
7 Copyright (C) 2010-2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8 Author: Milian Wolff <milian.wolff@kdab.com>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
13 (at your option) any later version.
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.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "messagehandler.h"
26 #include "ui_messagehandler.h"
28 #include "messagemodel.h"
30 #include <QSortFilterProxyModel>
31 #include <QtCore/QMutex>
32 #include <QDebug>
33 #include <QMessageBox>
34 #include <QListWidget>
35 #include <QLabel>
36 #include <QDialogButtonBox>
37 #include <QThread>
39 static QTextStream cerr(stdout);
41 using namespace GammaRay;
43 static MessageModel *s_model = 0;
44 static QtMsgHandler s_handler = 0;
45 static bool s_handlerDisabled = false;
46 static QMutex s_mutex(QMutex::Recursive);
48 void handleMessage(QtMsgType type, const char *msg)
50 ///WARNING: do not trigger *any* kind of debug output here
51 /// this would trigger an infinite loop and hence crash!
53 MessageModel::Message message;
54 message.type = type;
55 message.message = QString::fromLocal8Bit(msg);
56 message.time = QTime::currentTime();
58 if (type == QtCriticalMsg || type == QtFatalMsg || type == QtWarningMsg) {
59 message.backtrace = getBacktrace(50);
60 // remove trailing internal functions
61 // be a bit careful and first make sure that we find this function...
62 // TODO: go even higher until qWarning/qFatal/qDebug/... ?
63 int removeUntil = -1;
64 for (int i = 0; i < message.backtrace.size(); ++i) {
65 if (message.backtrace.at(i).contains(QLatin1String("handleMessage"))) {
66 removeUntil = i;
67 break;
70 if (removeUntil != -1) {
71 message.backtrace = message.backtrace.mid(removeUntil + 1);
75 if (type == QtFatalMsg && qgetenv("GAMMARAY_GDB") != "1" && qgetenv("GAMMARAY_UNITTEST") != "1" &&
76 QThread::currentThread() == QApplication::instance()->thread()) {
77 foreach (QWidget *w, qApp->topLevelWidgets()) {
78 w->setEnabled(false);
80 QDialog dlg;
81 dlg.setWindowTitle(QObject::tr("QFatal in %1").
82 arg(qApp->applicationName().isEmpty() ?
83 qApp->applicationFilePath() :
84 qApp->applicationName()));
85 QGridLayout *layout = new QGridLayout;
86 QLabel *iconLabel = new QLabel;
87 QIcon icon = dlg.style()->standardIcon(QStyle::SP_MessageBoxCritical, 0, &dlg);
88 int iconSize = dlg.style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, &dlg);
89 iconLabel->setPixmap(icon.pixmap(iconSize, iconSize));
90 iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
91 layout->addWidget(iconLabel, 0, 0);
92 QLabel *errorLabel = new QLabel;
93 errorLabel->setTextFormat(Qt::PlainText);
94 errorLabel->setText(message.message);
95 layout->addWidget(errorLabel, 0, 1);
96 if (!message.backtrace.isEmpty()) {
97 QListWidget *backtrace = new QListWidget;
98 foreach (const QString &frame, message.backtrace) {
99 backtrace->addItem(frame);
101 layout->addWidget(backtrace, 1, 0, 1, 2);
103 QDialogButtonBox *buttons = new QDialogButtonBox;
104 buttons->addButton(QDialogButtonBox::Close);
105 QObject::connect(buttons, SIGNAL(accepted()),
106 &dlg, SLOT(accept()));
107 QObject::connect(buttons, SIGNAL(rejected()),
108 &dlg, SLOT(reject()));
109 layout->addWidget(buttons, 2, 0, 1, 2);
110 dlg.setLayout(layout);
111 dlg.adjustSize();
112 dlg.exec();
113 } else if (!message.backtrace.isEmpty() &&
114 (qgetenv("GAMMARAY_UNITTEST") == "1" || type == QtFatalMsg)) {
115 cerr << "START BACKTRACE:" << endl;
116 int i = 0;
117 foreach (const QString &frame, message.backtrace) {
118 cerr << (++i) << "\t" << frame << endl;
120 cerr << "END BACKTRACE" << endl;
123 // reset msg handler so the app still works as usual
124 // but make sure we don't let other threads bypass our
125 // handler during that time
126 QMutexLocker lock(&s_mutex);
127 s_handlerDisabled = true;
128 qInstallMsgHandler(s_handler);
129 qt_message_output(type, msg);
130 qInstallMsgHandler(handleMessage);
131 s_handlerDisabled = false;
132 lock.unlock();
134 if (s_model) {
135 // add directly from foreground thread, delay from background thread
136 QMetaObject::invokeMethod(s_model, "addMessage", Qt::AutoConnection,
137 Q_ARG(MessageModel::Message, message));
141 MessageHandler::MessageHandler(ProbeInterface * /*probe*/, QWidget *parent)
142 : QWidget(parent),
143 ui(new Ui::MessageHandler),
144 m_messageModel(0),
145 m_messageProxy(new QSortFilterProxyModel(this))
147 ui->setupUi(this);
149 ui->messageSearchLine->setProxy(m_messageProxy);
150 ui->messageView->setModel(m_messageProxy);
151 ui->messageView->setIndentation(0);
152 ui->messageView->setSortingEnabled(true);
154 ///FIXME: implement this
155 ui->backtraceView->hide();
158 void MessageHandler::setModel(MessageModel *model)
160 m_messageModel = model;
161 m_messageProxy->setSourceModel(m_messageModel);
164 MessageHandlerFactory::MessageHandlerFactory(QObject *parent)
165 : QObject(parent),
166 m_messageModel(new MessageModel(this))
168 Q_ASSERT(s_model == 0);
169 s_model = m_messageModel;
171 // install handler directly, catches most cases,
172 // i.e. user has no special handler or the handler
173 // is created before the QApplication
174 ensureHandlerInstalled();
175 // recheck when eventloop is entered, if the user
176 // installs a handler after QApp but before .exec()
177 QMetaObject::invokeMethod(this, "ensureHandlerInstalled", Qt::QueuedConnection);
180 void MessageHandlerFactory::ensureHandlerInstalled()
182 QMutexLocker lock(&s_mutex);
184 if (s_handlerDisabled) {
185 return;
188 QtMsgHandler prevHandler = qInstallMsgHandler(handleMessage);
190 if (prevHandler != handleMessage) {
191 s_handler = prevHandler;
195 MessageHandlerFactory::~MessageHandlerFactory()
197 QMutexLocker lock(&s_mutex);
199 s_model = 0;
200 QtMsgHandler oldHandler = qInstallMsgHandler(s_handler);
201 if (oldHandler != handleMessage) {
202 // ups, the app installed it's own handler after ours...
203 qInstallMsgHandler(oldHandler);
205 s_handler = 0;
208 QWidget *MessageHandlerFactory::createWidget(ProbeInterface *probe, QWidget *parentWidget)
210 QWidget *widget =
211 StandardToolFactory<QObject, MessageHandler >::createWidget(probe, parentWidget);
213 MessageHandler *handler = qobject_cast<MessageHandler*>(widget);
214 Q_ASSERT(handler);
215 handler->setModel(m_messageModel);
216 return widget;
219 #include "messagehandler.moc"