#include "PerformanceManagerWindow.h" #include "MainWindow.h" #include "PerfPlot.h" #include "Colors.h" #include "StressCalculator.h" #include "RideItem.h" PerformanceManagerWindow::PerformanceManagerWindow(MainWindow *mainWindow) : GcWindow(mainWindow), mainWindow(mainWindow), active(false) { setInstanceName("PM Window"); setControls(NULL); days = count = 0; sc = NULL; QVBoxLayout *vlayout = new QVBoxLayout; QHBoxLayout *PMPickerLayout = new QHBoxLayout; QLabel *PMSTSLabel = new QLabel(appsettings->value(this, GC_STS_ACRONYM,"STS").toString() + ":", this); PMSTSValue = new QLineEdit("0"); PMSTSValue->setReadOnly(true); PMSTSValue->setValidator(new QDoubleValidator(0,500,1,PMSTSValue)); PMPickerLayout->addWidget(PMSTSLabel); PMPickerLayout->addWidget(PMSTSValue); QLabel *PMLTSLabel = new QLabel(appsettings->value(this, GC_LTS_ACRONYM,"LTS").toString() + ":", this); PMLTSValue = new QLineEdit("0"); PMLTSValue->setReadOnly(true); PMLTSValue->setValidator(new QDoubleValidator(0,500,1,PMLTSValue)); PMPickerLayout->addWidget(PMLTSLabel); PMPickerLayout->addWidget(PMLTSValue); QLabel *PMSBLabel = new QLabel(appsettings->value(this, GC_SB_ACRONYM,"SB").toString() + ":", this); PMSBValue = new QLineEdit("0"); PMSBValue->setReadOnly(true); PMSBValue->setValidator(new QDoubleValidator(-500,500,1,PMSBValue)); PMPickerLayout->addWidget(PMSBLabel); PMPickerLayout->addWidget(PMSBValue); QLabel *PMDayLabel = new QLabel(tr("Day:"), this); PMDayValue = new QLineEdit(tr("no data")); PMPickerLayout->addWidget(PMDayLabel); PMPickerLayout->addWidget(PMDayValue); metricCombo = new QComboBox(this); metricCombo->addItem(tr("Use TSS"), "coggan_tss"); metricCombo->addItem(tr("Use BikeScore"), "skiba_bike_score"); metricCombo->addItem(tr("Use DanielsPoints"), "daniels_points"); metricCombo->addItem(tr("Use TRIMP"), "trimp_points"); QString metricName = appsettings->value(this, GC_PERF_MAN_METRIC, "skiba_bike_score").toString(); for (int i = 0; i < metricCombo->count(); ++i) { if (metricCombo->itemData(i).toString() == metricName) metricCombo->setCurrentIndex(i); } metric = metricCombo->itemData(metricCombo->currentIndex()).toString(); PMPickerLayout->addWidget(metricCombo); // date range QHBoxLayout *dateRangeLayout = new QHBoxLayout; PMdateRangefrom = new QLineEdit("0"); dateRangeLayout->addWidget(PMdateRangefrom); PMleftSlider = new QSlider(Qt::Horizontal); PMleftSlider->setTickPosition(QSlider::TicksBelow); PMleftSlider->setTickInterval(1); PMleftSlider->setMinimum(0); dateRangeLayout->addWidget(PMleftSlider); QLabel *dateRangeLabel = new QLabel(tr("to"),this); dateRangeLayout->addWidget(dateRangeLabel); PMrightSlider = new QSlider(Qt::Horizontal); PMrightSlider->setTickPosition(QSlider::TicksBelow); PMrightSlider->setTickInterval(1); PMrightSlider->setMinimum(0); dateRangeLayout->addWidget(PMrightSlider); PMdateRangeto = new QLineEdit("0"); dateRangeLayout->addWidget(PMdateRangeto); perfplot = new PerfPlot(); vlayout->addWidget(perfplot); vlayout->addLayout(dateRangeLayout); vlayout->addLayout(PMPickerLayout); setLayout(vlayout); PMpicker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft, QwtPicker::PointSelection, QwtPicker::VLineRubberBand, QwtPicker::AlwaysOff, perfplot->canvas()); PMpicker->setRubberBandPen(GColor(CPLOTSELECT)); connect(PMpicker, SIGNAL(moved(const QPoint &)), SLOT(PMpickerMoved(const QPoint &))); connect(metricCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(metricChanged())); connect(mainWindow, SIGNAL(configChanged()), this, SLOT(configChanged())); connect(mainWindow, SIGNAL(configChanged()), perfplot, SLOT(configUpdate())); //connect(mainWindow, SIGNAL(rideSelected()), this, SLOT(rideSelected())); connect(this, SIGNAL(rideItemChanged(RideItem*)), this, SLOT(rideSelected())); } PerformanceManagerWindow::~PerformanceManagerWindow() { if (sc) delete sc; } void PerformanceManagerWindow::configChanged() { if (active) { days = 0; // force replot replot(); } PMpicker->setRubberBandPen(GColor(CPLOTSELECT)); } void PerformanceManagerWindow::metricChanged() { QString newMetric = metricCombo->itemData(metricCombo->currentIndex()).toString(); appsettings->setValue(GC_PERF_MAN_METRIC, newMetric); replot(); } void PerformanceManagerWindow::rideSelected() { bool wasActive = active; active = amVisible(); if (!wasActive && active) replot(); } void PerformanceManagerWindow::replot() { const QDir &home = mainWindow->home; const QTreeWidgetItem *allRides = mainWindow->allRideItems(); int newdays, endIndex; RideItem *firstRideItem = NULL; RideItem *lastRideItem = NULL; QDateTime now; // calculate the number of days to look at... for now // use first ride in allRides to today. When Season stuff is hooked // up, maybe use that, or will allRides reflect only current season? if (allRides->childCount()) { firstRideItem = (RideItem*) allRides->child(0); lastRideItem = (RideItem*) allRides->child(allRides->childCount()-1); } if (firstRideItem) { QDateTime endTime = std::max(lastRideItem->dateTime, now.currentDateTime()); newdays = firstRideItem->dateTime.daysTo(endTime); QString newMetric = metricCombo->itemData(metricCombo->currentIndex()).toString(); if (newdays != days || allRides->childCount() != count || newMetric != metric) { // days in allRides changed, so recalculate stress // bool firstrun = false; /* fprintf(stderr, "PerformanceManagerWindow::replot: %d days from %s to %s\n", newdays,firstRideItem->dateTime.toString().toAscii().data(), now.currentDateTime().toString().toAscii().data()); */ if (days == 0) firstrun = true; if (sc) delete sc; sc = new StressCalculator( mainWindow->cyclist, firstRideItem->dateTime, endTime, (appsettings->cvalue(mainWindow->cyclist, GC_INITIAL_STS)).toInt(), (appsettings->cvalue(mainWindow->cyclist, GC_INITIAL_LTS)).toInt(), (appsettings->cvalue(mainWindow->cyclist, GC_STS_DAYS,7)).toInt(), (appsettings->cvalue(mainWindow->cyclist, GC_LTS_DAYS,42)).toInt()); sc->calculateStress(mainWindow,home.absolutePath(),newMetric); perfplot->setStressCalculator(sc); endIndex = sc->n(); PMleftSlider->setMaximum(endIndex); PMrightSlider->setMaximum(endIndex); PMdateRangefrom->setValidator(new QIntValidator(PMleftSlider->minimum(), PMleftSlider->maximum(),PMleftSlider)); PMdateRangeto->setValidator(new QIntValidator(PMrightSlider->minimum(), PMrightSlider->maximum(),PMrightSlider)); setPMSliderDates(); if (firstrun) { // connect slider change handlers only once connect(PMleftSlider, SIGNAL(valueChanged(int)), this, SLOT(setPMSizeFromSlider())); connect(PMrightSlider, SIGNAL(valueChanged(int)), this, SLOT(setPMSizeFromSlider())); // set slider values only on the first time // set left slider to last 6 months if (newdays > 182) PMleftSlider->setValue(newdays - 182); else PMleftSlider->setValue(0); PMrightSlider->setValue(endIndex); } perfplot->resize(PMleftSlider->value(),PMrightSlider->value()); days = newdays; metric = newMetric; count = allRides->childCount(); } perfplot->plot(); } } // performance manager picker callback void PerformanceManagerWindow::PMpickerMoved(const QPoint &pos) { double day = perfplot->invTransform(QwtPlot::xBottom, pos.x()); QDateTime date; double sts, lts, sb; if (day >= perfplot->min() && day < perfplot->max()) { // set the date string PMDayValue->setText(perfplot->getStartDate().addDays(day).toString(tr("MMM d yyyy"))); sts = perfplot->getSTS(day); QString STSlabel = QString("%1").arg(sts,0,'f',1,0); PMSTSValue->setText(STSlabel); lts = perfplot->getLTS(day); QString LTSlabel = QString("%1").arg(lts,0,'f',1,0); PMLTSValue->setText(LTSlabel); sb = perfplot->getSB(day); QString SBlabel = QString("%1").arg(sb,0,'f',1,0); PMSBValue->setText(SBlabel); } } void PerformanceManagerWindow::setPMSizeFromSlider() { perfplot->resize(PMleftSlider->value(),PMrightSlider->value()); setPMSliderDates(); } void PerformanceManagerWindow::setPMSliderDates() { PMdateRangefrom->setText( perfplot->getStartDate().addDays(PMleftSlider->value()).toString(tr("MMM d yyyy"))); PMdateRangeto->setText( perfplot->getEndDate().addDays(PMrightSlider->value() - perfplot->n()).toString(tr("MMM d yyyy"))); }