/******************************************************************* * drkonqidialog.cpp * Copyright 2009 Dario Andres Rodriguez * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ******************************************************************/ #include "drkonqidialog.h" #include #include #include #include #include #include #include #include #include #include "drkonqi.h" #include "backtracegenerator.h" #include "backtracewidget.h" #include "parser/backtraceparser.h" #include "crashedapplication.h" #include "debuggermanager.h" #include "debuggerlaunchers.h" #include "drkonqi_globals.h" #include "systeminformation.h" static const char ABOUT_BUG_REPORTING_URL[] = "#aboutbugreporting"; DrKonqiDialog::DrKonqiDialog(QWidget * parent) : KDialog(parent), m_backtraceWidget(0) { KGlobal::ref(); setAttribute(Qt::WA_DeleteOnClose, true); //Setting dialog title and icon setCaption(DrKonqi::crashedApplication()->name()); setWindowIcon(KIcon("tools-report-bug")); m_tabWidget = new KTabWidget(this); setMainWidget(m_tabWidget); buildIntroWidget(); m_tabWidget->addTab(m_introWidget, i18nc("@title:tab general information", "&General")); m_backtraceWidget = new BacktraceWidget(DrKonqi::debuggerManager()->backtraceGenerator(), this); m_backtraceWidget->setMinimumSize(QSize(575, 240)); m_tabWidget->addTab(m_backtraceWidget, i18nc("@title:tab", "&Developer Information")); buildDialogButtons(); setMinimumSize(QSize(640,320)); resize(minimumSize()); KConfigGroup config(KGlobal::config(), "General"); restoreDialogSize(config); m_backtraceWidget->generateBacktrace(); } DrKonqiDialog::~DrKonqiDialog() { KConfigGroup config(KGlobal::config(), "General"); saveDialogSize(config); KGlobal::deref(); } void DrKonqiDialog::buildIntroWidget() { const CrashedApplication *crashedApp = DrKonqi::crashedApplication(); m_introWidget = new QWidget(this); ui.setupUi(m_introWidget); ui.titleLabel->setText(i18nc("@info", "We are sorry, %1 " "closed unexpectedly.", crashedApp->name())); QString reportMessage; if (!crashedApp->bugReportAddress().isEmpty()) { if (crashedApp->fakeExecutableBaseName() == QLatin1String("drkonqi")) { //Handle own crashes reportMessage = i18nc("@info", "As the Crash Handler itself has failed, the " "automatic reporting process is disabled to reduce the " "risks of failing again." "Please, manually report this error " "to the KDE bug tracking system. Do not forget to include " "the backtrace from the Developer Information " "tab.", QLatin1String(BUG_REPORT_URL)); } else if (KCmdLineArgs::parsedArgs()->isSet("safer")) { reportMessage = i18nc("@info", "The reporting assistant is disabled because " "the crash handler dialog was started in safe mode." "You can manually report this bug to %1 " "(including the backtrace from the " "Developer Information " "tab.)", crashedApp->bugReportAddress()); } else { reportMessage = i18nc("@info", "You can help us improve KDE Software by reporting " "this error.Learn " "more about bug reporting.It is " "safe to close this dialog if you do not want to report " "this bug.", QLatin1String(ABOUT_BUG_REPORTING_URL) ); } } else { reportMessage = i18nc("@info", "You cannot report this error, because " "%1 does not provide a bug reporting " "address.", crashedApp->name() ); } ui.infoLabel->setText(reportMessage); ui.iconLabel->setPixmap( QPixmap(KStandardDirs::locate("appdata", QLatin1String("pics/crash.png")))); ui.detailsTitleLabel->setText(QString("%1").arg(i18nc("@label","Details:"))); ui.detailsLabel->setText(i18nc("@info Note the time information is divided into date and time parts", "Executable: %1" " PID: %2 Signal: %3 (%4) " "Time: %5 %6", crashedApp->fakeExecutableBaseName(), crashedApp->pid(), crashedApp->signalName(), crashedApp->signalNumber(), KGlobal::locale()->formatDate(crashedApp->datetime().date(), KLocale::ShortDate), KGlobal::locale()->formatTime(crashedApp->datetime().time(), true) )); } void DrKonqiDialog::buildDialogButtons() { const CrashedApplication *crashedApp = DrKonqi::crashedApplication(); //Set kdialog buttons setButtons(KDialog::User3 | KDialog::User2 | KDialog::User1 | KDialog::Close); //Report bug button setButtonGuiItem(KDialog::User1, KGuiItem2(i18nc("@action:button", "Report &Bug"), KIcon("tools-report-bug"), i18nc("@info:tooltip", "Starts the bug report assistant."))); bool enableReportAssistant = !crashedApp->bugReportAddress().isEmpty() && crashedApp->fakeExecutableBaseName() != QLatin1String("drkonqi") && !KCmdLineArgs::parsedArgs()->isSet("safer"); enableButton(KDialog::User1, enableReportAssistant); connect(this, SIGNAL(user1Clicked()), this, SLOT(startBugReportAssistant())); //Default debugger button and menu (only for developer mode) DebuggerManager *debuggerManager = DrKonqi::debuggerManager(); setButtonGuiItem(KDialog::User2, KGuiItem2(i18nc("@action:button this is the debug menu button " "label which contains the debugging applications", "&Debug"), KIcon("applications-development"), i18nc("@info:tooltip", "Starts a program to debug " "the crashed application."))); showButton(KDialog::User2, debuggerManager->showExternalDebuggers()); m_debugMenu = new KMenu(this); setButtonMenu(KDialog::User2, m_debugMenu); QList debuggers = debuggerManager->availableExternalDebuggers(); foreach(AbstractDebuggerLauncher *launcher, debuggers) { addDebugger(launcher); } connect(debuggerManager, SIGNAL(externalDebuggerAdded(AbstractDebuggerLauncher*)), SLOT(addDebugger(AbstractDebuggerLauncher*))); connect(debuggerManager, SIGNAL(externalDebuggerRemoved(AbstractDebuggerLauncher*)), SLOT(removeDebugger(AbstractDebuggerLauncher*))); connect(debuggerManager, SIGNAL(debuggerRunning(bool)), SLOT(enableDebugMenu(bool))); //Restart application button setButtonGuiItem(KDialog::User3, KGuiItem2(i18nc("@action:button", "&Restart Application"), KIcon("system-reboot"), i18nc("@info:tooltip", "Use this button to restart " "the crashed application."))); enableButton(KDialog::User3, !crashedApp->hasBeenRestarted() && crashedApp->fakeExecutableBaseName() != QLatin1String("drkonqi")); connect(this, SIGNAL(user3Clicked()), crashedApp, SLOT(restart())); connect(crashedApp, SIGNAL(restarted(bool)), this, SLOT(applicationRestarted(bool))); //Close button QString tooltipText = i18nc("@info:tooltip", "Close this dialog (you will lose the crash information.)"); setButtonToolTip(KDialog::Close, tooltipText); setButtonWhatsThis(KDialog::Close, tooltipText); setDefaultButton(KDialog::Close); setButtonFocus(KDialog::Close); } void DrKonqiDialog::addDebugger(AbstractDebuggerLauncher *launcher) { QAction *action = new QAction(KIcon("applications-development"), i18nc("@action:inmenu 1 is the debugger name", "Debug in %1", launcher->name()), m_debugMenu); m_debugMenu->addAction(action); connect(action, SIGNAL(triggered()), launcher, SLOT(start())); m_debugMenuActions.insert(launcher, action); } void DrKonqiDialog::removeDebugger(AbstractDebuggerLauncher *launcher) { QAction *action = m_debugMenuActions.take(launcher); if ( action ) { m_debugMenu->removeAction(action); action->deleteLater(); } else { kError() << "Invalid launcher"; } } void DrKonqiDialog::enableDebugMenu(bool debuggerRunning) { enableButton(KDialog::User2, !debuggerRunning); } void DrKonqiDialog::startBugReportAssistant() { const CrashedApplication *crashedApp = DrKonqi::crashedApplication(); QString appReportAddress = crashedApp->bugReportAddress(); SystemInformation *sysinfo = new SystemInformation(this); QString backtrace = DrKonqi::debuggerManager()->backtraceGenerator()->parser()->parsedBacktrace(); QString query; // KDE applications use the email address by default if (appReportAddress == BUG_REPORT_EMAIL) { // black magic - report is done in Markdown syntax with new lines preserved // but invokeBrowser() can call external browser and at this point KDE // application can not be trused not to crash again (konqueror, rekonq, etc.). query = QString("%1/new").arg(BUG_REPORT_URL); query.append(QString("?title=%1 %2 %3").arg(crashedApp->name(), crashedApp->version(), crashedApp->signalName())); query.append(QString("&body=%1\nOS: %2\nRelease: %3\nKDE: %4\nQt: %5\n%6").arg( QUrl::toPercentEncoding("## Platform"), sysinfo->system(), sysinfo->release(), sysinfo->kdeVersion(), sysinfo->qtVersion(), QUrl::toPercentEncoding("## Backtrace\nPlease, copy-paste it from the DrKonqi window\n"))); } else { query = QString(appReportAddress); } KToolInvocation::invokeBrowser(query); } void DrKonqiDialog::applicationRestarted(bool success) { enableButton(KDialog::User3, !success); }