Files
GoldenCheetah/src/PerformanceManagerWindow.cpp
Mark Liversedge 4ab96e16d1 Sidebar, Ride List and Aeshetics
An update to the ride list on the left hand side
to enable the user to choose and sort or group-by
metrics, metadata fields and ride information.

In addition, the sidebar has been 'improved'
cosmetically and to require less screen estate.

Also, the ticks and frames on plots have been
adjusted to be more aesthtically appealling.

There is more to come on the look-and-feel front,
but this patch heralds some work on the sidebar
which needs to be resolved.
2011-06-01 16:34:24 +01:00

285 lines
8.8 KiB
C++

#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;
RideItem *lastRideItem;
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")));
}