Files
GoldenCheetah/src/PerformanceManagerWindow.cpp
Mark Liversedge aa8605e8d5 QT5 -- 1 of 3
Porting the codebase to QT 5 (5.2) to get the
latest bug fixes, performance and improved platform
support.

This first part is to fixup the codebase to compile
on Qt 5, but some aspects have been broken (video).

The second part is to migrate from Qwt 6.0.1 to the
latest Qwt for multiaxis support.

The third part will be to fixup any platform specific
issues or issues identified at runtime.
2013-12-09 09:57:13 +00:00

309 lines
9.7 KiB
C++

#include "PerformanceManagerWindow.h"
#include "MainWindow.h"
#include "Context.h"
#include "Athlete.h"
#include "PerfPlot.h"
#include "Colors.h"
#include "StressCalculator.h"
#include "RideItem.h"
#include <qwt_picker_machine.h>
PerformanceManagerWindow::PerformanceManagerWindow(Context *context) :
GcWindow(context), context(context), active(false), isfiltered(false)
{
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");
metricCombo->addItem(tr("Use TRIMP 100"), "trimp_100_points");
metricCombo->addItem(tr("Use Trimp Zonal"), "trimp_zonal_points");
metricCombo->addItem(tr("Use Work (Kj)"), "total_work");
metricCombo->addItem(tr("Use Distance (km/mi)"), "total_distance");
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::VLineRubberBand,
QwtPicker::AlwaysOff, perfplot->canvas());
PMpicker->setStateMachine(new QwtPickerDragPointMachine);
PMpicker->setRubberBandPen(GColor(CPLOTSELECT));
connect(PMpicker, SIGNAL(moved(const QPoint &)),
SLOT(PMpickerMoved(const QPoint &)));
connect(metricCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(metricChanged()));
connect(context, SIGNAL(configChanged()), this, SLOT(configChanged()));
connect(context, SIGNAL(configChanged()), perfplot, SLOT(configUpdate()));
connect(context, SIGNAL(rideAdded(RideItem*)), this, SLOT(replot()));
connect(context, SIGNAL(rideDeleted(RideItem*)), this, SLOT(replot()));
connect(this, SIGNAL(rideItemChanged(RideItem*)), this, SLOT(rideSelected()));
#ifdef GC_HAVE_LUCENE
connect(context, SIGNAL(filterChanged()), this, SLOT(filterChanged()));
#endif
}
PerformanceManagerWindow::~PerformanceManagerWindow()
{
if (sc)
delete sc;
}
#ifdef GC_HAVE_LUCENE
void
PerformanceManagerWindow::filterChanged()
{
filter = context->filters;
isfiltered = context->isfiltered;
days = 0; // force it
replot();
repaint();
}
#endif
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 QTreeWidgetItem *allRides = context->athlete->allRideItems();
int newdays, rightIndex, 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) {
int lookahead = (appsettings->cvalue(context->athlete->cyclist, GC_STS_DAYS,7)).toInt();
QDateTime endTime = std::max(lastRideItem->dateTime, now.currentDateTime());
endTime = endTime.addDays( lookahead );
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(
context->athlete->cyclist,
firstRideItem->dateTime,
endTime,
(appsettings->cvalue(context->athlete->cyclist, GC_STS_DAYS,7)).toInt(),
(appsettings->cvalue(context->athlete->cyclist, GC_LTS_DAYS,42)).toInt());
#ifdef GC_HAVE_LUCENE
sc->calculateStress(context,context->athlete->home.absolutePath(),newMetric,isfiltered,filter);
#else
sc->calculateStress(context,context->athlete->home.absolutePath(),newMetric);
#endif
perfplot->setStressCalculator(sc);
endIndex = sc->n();
rightIndex = std::max(0,endIndex-lookahead);
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(rightIndex);
}
perfplot->resize(PMleftSlider->value(),PMrightSlider->value());
days = newdays;
metric = newMetric;
count = allRides->childCount();
}
perfplot->plot();
}
repaint();
}
// 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")));
}