/* * Copyright (c) 2013 Mark Liversedge (liversedge@gmail.com) * * 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, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "GcCrashDialog.h" #include "Settings.h" #include "GcUpgrade.h" #include #include #include "DBAccess.h" #include "MetricAggregator.h" #include #include #define GCC_VERSION QString("%1.%2.%3").arg(__GNUC__).arg(__GNUC_MINOR__).arg(__GNUC_PATCHLEVEL__) #ifdef GC_HAVE_QWTPLOT3D #include "qwt3d_global.h" #endif #ifdef GC_HAVE_ICAL #include "ICalendar.h" #endif #ifdef GC_HAVE_D2XX #include "D2XX.h" #endif #ifdef GC_HAVE_SRMIO #include "srmio.h" #endif #ifdef GC_HAVE_LIBOAUTH #include #endif #ifdef GC_HAVE_LUCENE #include "Lucene.h" #endif #ifdef GC_HAVE_WFAPI #include "WFApi.h" #endif GcCrashDialog::GcCrashDialog(QDir home) : QDialog(NULL, Qt::Dialog), home(home) { setAttribute(Qt::WA_DeleteOnClose, true); // caller must delete me, once they've extracted the name setWindowTitle(QString(tr("%1 Crash Recovery").arg(home.dirName()))); QVBoxLayout *layout = new QVBoxLayout(this); QHBoxLayout *toprow = new QHBoxLayout; QPushButton *critical = new QPushButton(style()->standardIcon(QStyle::SP_MessageBoxCritical), "", this); critical->setFixedSize(128,128); critical->setFlat(true); critical->setIconSize(QSize(120,120)); critical->setAutoFillBackground(false); critical->setFocusPolicy(Qt::NoFocus); QLabel *header = new QLabel(this); header->setWordWrap(true); header->setTextFormat(Qt::RichText); header->setText(tr("GoldenCheetah appears to have PREVIOUSLY crashed for this athlete. " "

The report below gives some diagnostic information " "that will be useful to the developers. Feel free to post this with a " "short description of what was occurring when the crash happened to the " "" "GoldenCheetah forums
" "
We respect privacy - this log does NOT contain ids, passwords or personal information.

" "
When this dialog is closed the athlete will be opened.
")); toprow->addWidget(critical); toprow->addWidget(header); layout->addLayout(toprow); report = new QWebView(this); report->setContentsMargins(0,0,0,0); report->page()->view()->setContentsMargins(0,0,0,0); report->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); report->setAcceptDrops(false); QFont defaultFont; // mainwindow sets up the defaults.. we need to apply report->settings()->setFontSize(QWebSettings::DefaultFontSize, defaultFont.pointSize()+1); report->settings()->setFontFamily(QWebSettings::StandardFont, defaultFont.family()); layout->addWidget(report); QHBoxLayout *lastRow = new QHBoxLayout; QPushButton *saveAsButton = new QPushButton(tr("Save Crash Report..."), this); connect(saveAsButton, SIGNAL(clicked()), this, SLOT(saveAs())); QPushButton *OKButton = new QPushButton(tr("Close"), this); connect(OKButton, SIGNAL(clicked()), this, SLOT(accept())); lastRow->addWidget(saveAsButton); lastRow->addStretch(); lastRow->addWidget(OKButton); layout->addLayout(lastRow); setHTML(); } QString GcCrashDialog::versionHTML() { // -- OS ---- QString os = ""; #ifdef Q_OS_LINUX os = "Linux"; #endif #ifdef WIN32 os = "Win"; #endif #ifdef Q_OS_MAC os = QString("Mac OS X 10.%1").arg(QSysInfo::MacintoshVersion - 2); if (QSysInfo::MacintoshVersion == QSysInfo::MV_SNOWLEOPARD) os += " Snow Leopard"; else if (QSysInfo::MacintoshVersion == QSysInfo::MV_LION) os += " Lion"; else if (QSysInfo::MacintoshVersion == 10) os += " Mountain Lion"; #endif // -- SCHEMA VERSION ---- QString schemaVersion = QString("%1").arg(DBSchemaVersion); // -- SRMIO ---- QString srmio = "none"; #ifdef GC_HAVE_SRMIO #ifdef SRMIO_VERSION srmio = QString("%1 %2").arg(SRMIO_VERSION).arg(srmio_commit); #else srmio = "yes"; #endif #endif // -- D2XX ---- QString d2xx = "none"; #ifdef GC_HAVE_D2XX d2xx = "yes"; #endif // -- LIBOAUTH ---- QString oauth = "none"; #ifdef GC_HAVE_LIBOAUTH oauth = LIBOAUTH_VERSION; #endif // -- QWTPLOT3D ---- QString qwtplot3d = "none"; #ifdef GC_HAVE_QWTPLOT3D qwtplot3d = QString::number(QWT3D_MAJOR_VERSION) + "." + QString::number(QWT3D_MINOR_VERSION) + "." + QString::number(QWT3D_PATCH_VERSION); #endif // -- KML ---- QString kml = "none"; #ifdef GC_HAVE_KML kml = "yes"; #endif // -- ICAL ---- QString ical = "none"; #ifdef GC_HAVE_ICAL ical = ICAL_VERSION; #endif // -- USBXPRESS ---- QString usbxpress = "none"; #ifdef GC_HAVE_USBXPRESS usbxpress = "yes"; #endif // -- LIBUSB ---- QString libusb = "none"; #ifdef GC_HAVE_LIBUSB libusb = "yes"; #endif // -- VLC ---- QString vlc = "none"; #ifdef GC_HAVE_VLC vlc = "yes"; #endif // -- LUCENE ---- QString clucene = "none"; #ifdef GC_HAVE_LUCENE clucene = _CL_VERSION; #endif #ifdef GC_HAVE_WFAPI QString wfapi = WFApi::getInstance()->apiVersion(); #else QString wfapi = QString("none"); #endif QString gc_version = tr( "

Build date: %1 %2" "
Build id: %3" "
Version: %4" "
DB Schema: %5" "
OS: %6" "
") .arg(__DATE__) .arg(__TIME__) .arg(GcUpgrade::version()) #ifdef GC_VERSION .arg(GC_VERSION) #else .arg("(developer build)") #endif .arg(schemaVersion) .arg(os); QString lib_version = tr( "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
QT%1
QWT%2
GCC%3
SRMIO%4
OAUTH%5
D2XX%6
QWTPLOT3D%7
KML%8
ICAL%9
USBXPRESS%10
LIBUSB%11
Wahoo API%12
VLC%13
LUCENE%14
" ) .arg(QT_VERSION_STR) .arg(QWT_VERSION_STR) .arg(GCC_VERSION) .arg(srmio) .arg(oauth) .arg(d2xx) .arg(qwtplot3d) .arg(kml) .arg(ical) .arg(usbxpress) .arg(libusb) .arg(wfapi) .arg(vlc) .arg(clucene) ; QString versionText = QString("

" + gc_version + lib_version + "
"); return versionText; } void GcCrashDialog::setHTML() { QString text; // the cyclist... text += QString("

Cyclist: \"%1\"


").arg(home.dirName()); // version info text += "

Version Info

"; text += versionHTML(); // metric log... text += "

Metric Log

"; text += "
"; QFile metriclog(home.absolutePath() + "/" + "metric.log"); if (metriclog.open(QIODevice::ReadOnly)) { // read in line by line and add to diag file QTextStream in(&metriclog); while (!in.atEnd()) { QString lines = in.readLine(); foreach(QString line, lines.split('\r')) { text += ""; } } metriclog.close(); } text += "
" + line + "
"; // files... text += "

Athlete Directory

"; text += "
"; foreach(QString file, home.entryList(QDir::NoFilter, QDir::Time)) { text += QString("") .arg(file) .arg(QFileInfo(home.absolutePath() + "/" + file).lastModified().toString()); } text += "
%1%2
"; // settings... text += "

All Settings

"; text += "
"; foreach(QString key, appsettings->allKeys()) { // RESPECT PRIVACY // we do not disclose user names and passwords or key ids if (key.endsWith("/user") || key.endsWith("/pass") || key.endsWith("/key")) continue; // we do not disclose personally identifiable information if (key.endsWith("/dob") || key.endsWith("/weight") || key.endsWith("/sex") || key.endsWith("/bio")) continue; text += QString("") .arg(key) .arg(appsettings->value(NULL, key).toString().leftJustified(60, ' ', true)); } text += "
%1" "%2
"; report->page()->mainFrame()->setHtml(text); } void GcCrashDialog::saveAs() { QString fileName = QFileDialog::getSaveFileName( this, tr("Save Diagnostics"), QDir::homePath(), tr("Text File (*.txt)")); // now write to it QFile file(fileName); file.resize(0); QTextStream out(&file); out.setCodec("UTF-8"); if (file.open(QIODevice::WriteOnly)) { // write the texts out << report->page()->mainFrame()->toPlainText(); } file.close(); }