Files
GoldenCheetah/src/HistogramWindow.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

987 lines
29 KiB
C++

/*
* Copyright (c) 2009 Sean C. Rhea (srhea@srhea.net)
* 2011 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 "HistogramWindow.h"
// predefined deltas for each series
static const double wattsDelta = 1.0;
static const double wattsKgDelta = 0.01;
static const double nmDelta = 0.1;
static const double hrDelta = 1.0;
static const double kphDelta = 0.1;
static const double cadDelta = 1.0;
// digits for text entry validator
static const int wattsDigits = 0;
static const int wattsKgDigits = 2;
static const int nmDigits = 1;
static const int hrDigits = 0;
static const int kphDigits = 1;
static const int cadDigits = 0;
//
// Constructor
//
HistogramWindow::HistogramWindow(Context *context, bool rangemode) : GcChartWindow(context), context(context), stale(true), source(NULL), active(false), bactive(false), rangemode(rangemode), useCustom(false), useToToday(false), precision(99)
{
QWidget *c = new QWidget;
c->setContentsMargins(0,0,0,0);
QFormLayout *cl = new QFormLayout(c);
cl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
cl->setSpacing(5);
setControls(c);
//
// reveal controls widget
//
// reveal controls
rWidth = new QLabel(tr("Bin Width"));
rBinEdit = new QLineEdit();
rBinEdit->setFixedWidth(40);
rBinSlider = new QSlider(Qt::Horizontal);
rBinSlider->setTickPosition(QSlider::TicksBelow);
rBinSlider->setTickInterval(10);
rBinSlider->setMinimum(1);
rBinSlider->setMaximum(100);
rShade = new QCheckBox(tr("Shade zones"));
rZones = new QCheckBox(tr("Show in zones"));
// layout reveal controls
QHBoxLayout *r = new QHBoxLayout;
r->setContentsMargins(0,0,0,0);
r->addStretch();
r->addWidget(rWidth);
r->addWidget(rBinEdit);
r->addWidget(rBinSlider);
QVBoxLayout *v = new QVBoxLayout;
v->addWidget(rShade);
v->addWidget(rZones);
r->addSpacing(20);
r->addLayout(v);
r->addStretch();
setRevealLayout(r);
// plot
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->setSpacing(10);
powerHist = new PowerHist(context);
vlayout->addWidget(powerHist);
setChartLayout(vlayout);
#ifdef GC_HAVE_LUCENE
// search filter box
isfiltered = false;
searchBox = new SearchFilterBox(this, context);
connect(searchBox, SIGNAL(searchClear()), this, SLOT(clearFilter()));
connect(searchBox, SIGNAL(searchResults(QStringList)), this, SLOT(setFilter(QStringList)));
if (!rangemode) searchBox->hide();
else {
cl->addRow(new QLabel(tr("Filter")), searchBox);
cl->addWidget(new QLabel(""));
}
#endif
// date selection
dateSetting = new DateSettingsEdit(this);
if (rangemode) {
cl->addRow(new QLabel(tr("Date Range")), dateSetting);
cl->addWidget(new QLabel("")); // spacing
// default to data series!
data = new QRadioButton(tr("Ride Data Samples"));
metric = new QRadioButton(tr("Ride Metrics"));
data->setChecked(true);
metric->setChecked(false);
QHBoxLayout *radios = new QHBoxLayout;
radios->addWidget(data);
radios->addWidget(metric);
cl->addRow(new QLabel(tr("Plot")), radios);
connect(data, SIGNAL(toggled(bool)), this, SLOT(dataToggled(bool)));
connect(metric, SIGNAL(toggled(bool)), this, SLOT(metricToggled(bool)));
}
// data series
seriesCombo = new QComboBox();
addSeries();
if (rangemode) comboLabel = new QLabel("");
else comboLabel = new QLabel(tr("Data Series"));
cl->addRow(comboLabel, seriesCombo);
if (rangemode) {
// TOTAL METRIC
totalMetricTree = new QTreeWidget;
#ifdef Q_OS_MAC
totalMetricTree->setAttribute(Qt::WA_MacShowFocusRect, 0);
#endif
totalMetricTree->setColumnCount(2);
totalMetricTree->setColumnHidden(1, true);
totalMetricTree->setSelectionMode(QAbstractItemView::SingleSelection);
totalMetricTree->header()->hide();
//totalMetricTree->setFrameStyle(QFrame::NoFrame);
//totalMetricTree->setAlternatingRowColors (true);
totalMetricTree->setIndentation(5);
totalMetricTree->setContextMenuPolicy(Qt::CustomContextMenu);
// ALL METRIC
distMetricTree = new QTreeWidget;
#ifdef Q_OS_MAC
distMetricTree->setAttribute(Qt::WA_MacShowFocusRect, 0);
#endif
distMetricTree->setColumnCount(2);
distMetricTree->setColumnHidden(1, true);
distMetricTree->setSelectionMode(QAbstractItemView::SingleSelection);
distMetricTree->header()->hide();
//distMetricTree->setFrameStyle(QFrame::NoFrame);
distMetricTree->setIndentation(5);
distMetricTree->setContextMenuPolicy(Qt::CustomContextMenu);
// add them all
const RideMetricFactory &factory = RideMetricFactory::instance();
for (int i = 0; i < factory.metricCount(); ++i) {
const RideMetric *m = factory.rideMetric(factory.metricName(i));
QTextEdit processHTML(m->name()); // process html encoding of(TM)
QString processed = processHTML.toPlainText();
QTreeWidgetItem *add;
add = new QTreeWidgetItem(distMetricTree->invisibleRootItem());
add->setText(0, processed);
add->setText(1, m->symbol());
// we only want totalising metrics
if (m->type() != RideMetric::Total) continue;
add = new QTreeWidgetItem(totalMetricTree->invisibleRootItem());
add->setText(0, processed);
add->setText(1, m->symbol());
}
QHBoxLayout *labels = new QHBoxLayout;
metricLabel1 = new QLabel(tr("Total (x-axis)"));
labels->addWidget(metricLabel1);
metricLabel1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
metricLabel2 = new QLabel(tr("Distribution (y-axis)"));
metricLabel2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
labels->addWidget(metricLabel2);
cl->addRow((blankLabel1=new QLabel("")), labels);
QHBoxLayout *trees = new QHBoxLayout;
trees->addWidget(totalMetricTree);
trees->addWidget(distMetricTree);
cl->addRow((blankLabel2 = new QLabel("")), trees);
colorButton = new ColorButton(this, "Color", QColor(Qt::blue));
colorLabel = new QLabel(tr("Color"));
connect(colorButton, SIGNAL(colorChosen(QColor)), this, SLOT(updateChart()));
cl->addRow(colorLabel, colorButton);
// by default select number of rides by duration
// which are the metrics workout_time and ride_count
selectTotal("ride_count");
selectMetric("workout_time");
}
showSumY = new QComboBox();
showSumY->addItem(tr("Absolute Time"));
showSumY->addItem(tr("Percentage Time"));
showLabel = new QLabel(tr("Show"));
cl->addRow(showLabel, showSumY);
showLnY = new QCheckBox;
showLnY->setText(tr("Log Y"));
cl->addRow(blankLabel3 = new QLabel(""), showLnY);
showZeroes = new QCheckBox;
showZeroes->setText(tr("With zeros"));
cl->addRow(blankLabel4 = new QLabel(""), showZeroes);
shadeZones = new QCheckBox;
shadeZones->setText(tr("Shade zones"));
cl->addRow(blankLabel5 = new QLabel(""), shadeZones);
showInZones = new QCheckBox;
showInZones->setText(tr("Show in zones"));
cl->addRow(blankLabel6 = new QLabel(""), showInZones);
// bin width
QHBoxLayout *binWidthLayout = new QHBoxLayout;
QLabel *binWidthLabel = new QLabel(tr("Bin width"), this);
binWidthLineEdit = new QLineEdit(this);
binWidthLineEdit->setFixedWidth(40);
binWidthLayout->addWidget(binWidthLineEdit);
binWidthSlider = new QSlider(Qt::Horizontal);
binWidthSlider->setTickPosition(QSlider::TicksBelow);
binWidthSlider->setTickInterval(1);
binWidthSlider->setMinimum(1);
binWidthSlider->setMaximum(100);
binWidthLayout->addWidget(binWidthSlider);
cl->addRow(binWidthLabel, binWidthLayout);
// sort out default values
setBinEditors();
showLnY->setChecked(powerHist->islnY());
showZeroes->setChecked(powerHist->withZeros());
shadeZones->setChecked(powerHist->shade);
binWidthSlider->setValue(powerHist->binWidth());
rBinSlider->setValue(powerHist->binWidth());
rShade->setChecked(powerHist->shade);
// fixup series selected by default
seriesChanged();
// hide/show according to default mode
switchMode(); // does nothing if not in rangemode
// set the defaults etc
updateChart();
// the bin slider/input update each other
// only the input box triggers an update to the chart
connect(binWidthSlider, SIGNAL(valueChanged(int)), this, SLOT(setBinWidthFromSlider()));
connect(binWidthLineEdit, SIGNAL(editingFinished()), this, SLOT(setBinWidthFromLineEdit()));
connect(rBinSlider, SIGNAL(valueChanged(int)), this, SLOT(setrBinWidthFromSlider()));
connect(rBinEdit, SIGNAL(editingFinished()), this, SLOT(setrBinWidthFromLineEdit()));
connect(rZones, SIGNAL(stateChanged(int)), this, SLOT(setZoned(int)));
connect(rShade, SIGNAL(stateChanged(int)), this, SLOT(setShade(int)));
// when season changes we need to retrieve data from the cache then update the chart
if (rangemode) {
connect(this, SIGNAL(dateRangeChanged(DateRange)), this, SLOT(dateRangeChanged(DateRange)));
connect(dateSetting, SIGNAL(useCustomRange(DateRange)), this, SLOT(useCustomRange(DateRange)));
connect(dateSetting, SIGNAL(useThruToday()), this, SLOT(useThruToday()));
connect(dateSetting, SIGNAL(useStandardRange()), this, SLOT(useStandardRange()));
connect(distMetricTree, SIGNAL(itemSelectionChanged()), this, SLOT(treeSelectionChanged()));
connect(totalMetricTree, SIGNAL(itemSelectionChanged()), this, SLOT(treeSelectionChanged()));
lagger = new QTimer;
lagger->setSingleShot(true);
connect(lagger, SIGNAL(timeout()), this, SLOT(treeSelectionTimeout()));
} else {
dateSetting->hide();
connect(this, SIGNAL(rideItemChanged(RideItem*)), this, SLOT(rideSelected()));
connect(context, SIGNAL(intervalSelected()), this, SLOT(intervalSelected()));
}
// if any of the controls change we pass the chart everything
connect(showLnY, SIGNAL(stateChanged(int)), this, SLOT(updateChart()));
connect(showZeroes, SIGNAL(stateChanged(int)), this, SLOT(updateChart()));
connect(seriesCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(seriesChanged()));
connect(showInZones, SIGNAL(stateChanged(int)), this, SLOT(setZoned(int)));
connect(showInZones, SIGNAL(stateChanged(int)), this, SLOT(updateChart()));
connect(shadeZones, SIGNAL(stateChanged(int)), this, SLOT(setShade(int)));
connect(shadeZones, SIGNAL(stateChanged(int)), this, SLOT(updateChart()));
connect(showSumY, SIGNAL(currentIndexChanged(int)), this, SLOT(updateChart()));
connect(context->athlete, SIGNAL(zonesChanged()), this, SLOT(zonesChanged()));
connect(context, SIGNAL(configChanged()), powerHist, SLOT(configChanged()));
connect(context, SIGNAL(rideAdded(RideItem*)), this, SLOT(rideAddorRemove(RideItem*)));
connect(context, SIGNAL(rideDeleted(RideItem*)), this, SLOT(rideAddorRemove(RideItem*)));
connect(context, SIGNAL(filterChanged()), this, SLOT(forceReplot()));
connect(context, SIGNAL(homeFilterChanged()), this, SLOT(forceReplot()));
}
//
// Colors (used by metric plotting)
//
QString HistogramWindow::plotColor() const
{
if (!rangemode) return QColor(Qt::blue).name();
else {
return colorButton->getColor().name();
}
}
void HistogramWindow::setPlotColor(QString color)
{
if (rangemode) colorButton->setColor(QColor(color));
}
//
// Set Bin Width property by setting the slider
//
void HistogramWindow::setBin(double x)
{
if (bactive) return;
bactive = true;
binWidthSlider->setValue(x/getDelta());
rBinSlider->setValue(x/getDelta());
binWidthLineEdit->setText(QString("%1").arg(x, 0, 'f', getDigits()));
rBinEdit->setText(QString("%1").arg(x, 0, 'f', getDigits()));
powerHist->setBinWidth(x);
bactive = false;
// redraw
stale = true;
updateChart();
}
//
// Get/Set the metric selections
//
QString HistogramWindow::distMetric() const
{
if (!rangemode) return "workout_time";
else {
// get current selection
QList<QTreeWidgetItem *> select = distMetricTree->selectedItems();
if (select.count() == 0) return "workout_time";
else return select[0]->text(1);
}
}
void HistogramWindow::setDistMetric(QString value)
{
if (!rangemode) return;
selectMetric(value);
}
QString HistogramWindow::totalMetric() const
{
if (!rangemode) return "ride_count";
else {
// get current selection
QList<QTreeWidgetItem *> select = totalMetricTree->selectedItems();
if (select.count() == 0) return "ride_count";
else return select[0]->text(1);
}
}
void HistogramWindow::setTotalMetric(QString value)
{
if (!rangemode) return;
selectTotal(value);
}
void
HistogramWindow::selectTotal(QString symbol)
{
QList<QTreeWidgetItem *> found = totalMetricTree->findItems(symbol, Qt::MatchRecursive|Qt::MatchExactly, 1);
if (found.count() == 0) return;
// clear the current selection
foreach(QTreeWidgetItem *selected, totalMetricTree->selectedItems()) selected->setSelected(false);
// select the first one (there shouldn't be more than that!!!
found[0]->setSelected(true);
// make sure it is the current item and visible
totalMetricTree->setCurrentItem(found[0]);
totalMetricTree->scrollToItem(totalMetricTree->currentItem());
}
void
HistogramWindow::selectMetric(QString symbol)
{
QList<QTreeWidgetItem *> found = distMetricTree->findItems(symbol, Qt::MatchRecursive|Qt::MatchExactly, 1);
if (found.count() == 0) return;
// clear the current selection
foreach(QTreeWidgetItem *selected, distMetricTree->selectedItems()) selected->setSelected(false);
// select the first one (there shouldn't be more than that!!!
found[0]->setSelected(true);
// make sure it is the current item and visible
distMetricTree->setCurrentItem(found[0]);
distMetricTree->scrollToItem(distMetricTree->currentItem());
}
//
// get set mode (data series or metric?) -- only in rangemode
//
bool HistogramWindow::dataMode() const
{
if (!rangemode) return true;
else return data->isChecked();
}
void HistogramWindow::setDataMode(bool value)
{
if (!rangemode) return;
else {
active = true;
data->setChecked(value);
metric->setChecked(!value);
active = false;
switchMode();
}
}
//
// When user changes from data series to metric
//
void
HistogramWindow::dataToggled(bool x)
{
if (active) return;
active = true;
stale = true;
metric->setChecked(!x);
switchMode();
active = false;
}
void
HistogramWindow::metricToggled(bool x)
{
if (active) return;
active = true;
stale = true;
data->setChecked(!x);
switchMode();
active = false;
}
void
HistogramWindow::switchMode()
{
if (!rangemode) return; // ! only valid in rangemode
if (data->isChecked()) {
// hide all the metric controls
blankLabel1->hide();
blankLabel2->hide();
distMetricTree->hide();
totalMetricTree->hide();
metricLabel1->hide();
metricLabel2->hide();
colorLabel->hide();
colorButton->hide();
// show all the data series controls
comboLabel->show();
seriesCombo->show();
blankLabel3->show();
blankLabel4->show();
blankLabel5->show();
blankLabel6->show();
showSumY->show();
showLabel->show();
showLnY->show();
showZeroes->show();
shadeZones->show();
showInZones->show();
// select the series..
seriesChanged();
} else {
// hide all the data series controls
comboLabel->hide();
seriesCombo->hide();
blankLabel3->hide();
blankLabel4->hide();
blankLabel5->hide();
blankLabel6->hide();
showSumY->hide();
showLabel->hide();
showLnY->hide();
showZeroes->hide();
shadeZones->hide();
showInZones->hide();
// show all the metric controls
blankLabel1->show();
blankLabel2->show();
metricLabel1->show();
metricLabel2->show();
distMetricTree->show();
totalMetricTree->show();
colorLabel->show();
colorButton->show();
// select the series.. (but without the half second delay)
treeSelectionTimeout();
}
stale = true;
updateChart(); // to whatever is currently selected.
}
//
// When user selects a new metric
//
void
HistogramWindow::treeSelectionChanged()
{
stale = true;
lagger->start(500);
}
void
HistogramWindow::treeSelectionTimeout()
{
// new metric chosen, so set up all the bin width, line edit
// delta, precision etc
powerHist->setSeries(RideFile::none);
powerHist->setDelta(getDelta());
powerHist->setDigits(getDigits());
// now update the slider stepper and linedit
setBinEditors();
// initial value -- but only if need to
double minbinw = getDelta();
double maxbinw = getDelta() * 100;
double current = binWidthLineEdit->text().toDouble();
if (current < minbinw || current > maxbinw) setBin(getDelta());
// replot
updateChart();
}
//
// When user selects a different data series
//
void
HistogramWindow::seriesChanged()
{
// series changed so tell power hist
powerHist->setSeries(static_cast<RideFile::SeriesType>(seriesCombo->itemData(seriesCombo->currentIndex()).toInt()));
powerHist->setDelta(getDelta());
powerHist->setDigits(getDigits());
// now update the slider stepper and linedit
setBinEditors();
// set an initial bin width value
setBin(getDelta());
// replot
stale = true;
updateChart();
}
//
// We need to config / update the controls when data series/metrics change
//
void
HistogramWindow::setBinEditors()
{
// the line edit validator
QValidator *validator;
if (getDigits() == 0) {
validator = new QIntValidator(binWidthSlider->minimum() * getDelta(),
binWidthSlider->maximum() * getDelta(),
binWidthLineEdit);
} else {
validator = new QDoubleValidator(binWidthSlider->minimum() * getDelta(),
binWidthSlider->maximum() * getDelta(),
getDigits(),
binWidthLineEdit);
}
binWidthLineEdit->setValidator(validator);
rBinEdit->setValidator(validator);
}
//
// A new ride was selected
//
void
HistogramWindow::rideSelected()
{
if (!amVisible()) return;
RideItem *ride = myRideItem;
if (!ride || (rangemode && !stale)) return;
if (rangemode) {
// get range that applies to this ride
powerRange = context->athlete->zones()->whichRange(ride->dateTime.date());
hrRange = context->athlete->hrZones()->whichRange(ride->dateTime.date());
}
// update
updateChart();
}
//
// User selected a new interval
//
void
HistogramWindow::intervalSelected()
{
if (!amVisible()) return;
RideItem *ride = myRideItem;
// null? or not plotting current ride, ignore signal
if (!ride || rangemode) return;
// update
interval = true;
updateChart();
}
void
HistogramWindow::rideAddorRemove(RideItem *)
{
stale = true;
}
void
HistogramWindow::zonesChanged()
{
if (!amVisible()) return;
powerHist->refreshZoneLabels();
powerHist->replot();
}
void
HistogramWindow::useCustomRange(DateRange range)
{
// plot using the supplied range
useCustom = true;
useToToday = false;
custom = range;
dateRangeChanged(custom);
}
void
HistogramWindow::useStandardRange()
{
useToToday= useCustom = false;
dateRangeChanged(myDateRange);
}
void
HistogramWindow::useThruToday()
{
// plot using the supplied range
useCustom = false;
useToToday = true;
custom = myDateRange;
if (custom.to > QDate::currentDate()) custom.to = QDate::currentDate();
dateRangeChanged(custom);
}
void HistogramWindow::dateRangeChanged(DateRange dateRange)
{
// if we're using a custom one lets keep it
if (rangemode && (useCustom || useToToday)) dateRange = custom;
// has it changed?
if (dateRange.from != cfrom || dateRange.to != cto)
stale = true;
if (!amVisible() || !stale) return;
updateChart();
}
void HistogramWindow::addSeries()
{
// setup series list
seriesList << RideFile::watts
<< RideFile::wattsKg
<< RideFile::hr
<< RideFile::kph
<< RideFile::cad
<< RideFile::nm
<< RideFile::aPower;
foreach (RideFile::SeriesType x, seriesList)
seriesCombo->addItem(RideFile::seriesName(x), static_cast<int>(x));
}
void
HistogramWindow::setBinWidthFromSlider()
{
if (bactive) return;
setBin(binWidthSlider->value() * getDelta());
}
void
HistogramWindow::setrBinWidthFromSlider()
{
if (bactive) return;
setBin(rBinSlider->value() * getDelta());
}
void
HistogramWindow::setBinWidthFromLineEdit()
{
if (bactive) return;
setBin(binWidthLineEdit->text().toDouble());
}
void
HistogramWindow::setrBinWidthFromLineEdit()
{
if (bactive) return;
setBin(rBinEdit->text().toDouble());
}
void
HistogramWindow::setZoned(int x)
{
rZones->setCheckState((Qt::CheckState)x);
showInZones->setCheckState((Qt::CheckState)x);
}
void
HistogramWindow::setShade(int x)
{
rShade->setCheckState((Qt::CheckState)x);
shadeZones->setCheckState((Qt::CheckState)x);
}
void
HistogramWindow::forceReplot()
{
stale = true;
if (amVisible()) updateChart();
}
void
HistogramWindow::updateChart()
{
if (!amVisible()) {
stale = true;
return;
}
// What is the selected series?
RideFile::SeriesType series = static_cast<RideFile::SeriesType>(seriesCombo->itemData(seriesCombo->currentIndex()).toInt());
// If no data present show the blank state page
if (!rangemode) {
RideFile::SeriesType baseSeries = (series == RideFile::wattsKg) ? RideFile::watts : series;
if (rideItem() != NULL && rideItem()->ride()->isDataPresent(baseSeries))
setIsBlank(false);
else
setIsBlank(true);
} else {
setIsBlank(false);
}
// Lets get the data then
if (stale) {
RideFileCache *old = source;
if (rangemode) {
// set the date range to the appropiate selection
DateRange use;
if (useCustom) {
use = custom;
} else if (useToToday) {
use = myDateRange;
QDate today = QDate::currentDate();
if (use.to > today) use.to = today;
} else {
use = myDateRange;
}
if (data->isChecked()) {
// plotting a data series, so refresh the ridefilecache
#ifdef GC_HAVE_LUCENE
source = new RideFileCache(context, use.from, use.to, isfiltered, files, rangemode);
#else
source = new RideFileCache(context, use.from, use.to);
#endif
cfrom = use.from;
cto = use.to;
stale = false;
if (old) delete old; // guarantee source pointer changes
stale = false; // well we tried
// set the data on the plot
powerHist->setData(source);
// and which series to plot
powerHist->setSeries(series);
// and now the controls
powerHist->setShading(shadeZones->isChecked() ? true : false);
powerHist->setZoned(showInZones->isChecked() ? true : false);
powerHist->setlnY(showLnY->isChecked() ? true : false);
powerHist->setWithZeros(showZeroes->isChecked() ? true : false);
powerHist->setSumY(showSumY->currentIndex()== 0 ? true : false);
} else {
if (last.from != use.from || last.to != use.to) {
// remember the last lot we collected
last = use;
// plotting a metric, reread the metrics for the selected date range
results = context->athlete->metricDB->getAllMetricsFor(use);
}
if (results.count() == 0) setIsBlank(true);
else setIsBlank(false);
// setData using the summary metrics -- always reset since filters may
// have changed, or perhaps the bin width...
powerHist->setSeries(RideFile::none);
powerHist->setDelta(getDelta());
powerHist->setDigits(getDigits());
#ifdef GC_HAVE_LUCENE
powerHist->setData(results, totalMetric(), distMetric(), isfiltered, files);
#else
powerHist->setData(results, totalMetric(), distMetric(), false, QStringList());
#endif
powerHist->setColor(colorButton->getColor());
}
} else {
powerHist->setData(myRideItem, interval); // intervals selected forces data to
// be recomputed since interval selection
// has changed.
// and which series to plot
powerHist->setSeries(series);
// and now the controls
powerHist->setShading(shadeZones->isChecked() ? true : false);
powerHist->setZoned(showInZones->isChecked() ? true : false);
powerHist->setlnY(showLnY->isChecked() ? true : false);
powerHist->setWithZeros(showZeroes->isChecked() ? true : false);
powerHist->setSumY(showSumY->currentIndex()== 0 ? true : false);
}
powerHist->recalc(true); // interval changed? force recalc
powerHist->replot();
interval = false;// we force a recalc whem called coz intervals
// have been selected. The recalc routine in
// powerhist optimises out, but doesn't keep track
// of interval selection -- simplifies the setters
// and getters, so worth this 'hack'.
} // if stale
}
#ifdef GC_HAVE_LUCENE
void
HistogramWindow::clearFilter()
{
isfiltered = false;
files.clear();
stale = true;
updateChart();
repaint();
}
void
HistogramWindow::setFilter(QStringList list)
{
isfiltered = true;
files = list;
stale = true;
updateChart();
repaint();
}
#endif
double
HistogramWindow::getDelta()
{
if (rangemode && !data->isChecked()) {
// based upon the metric chosen
const RideMetricFactory &factory = RideMetricFactory::instance();
const RideMetric *m = factory.rideMetric(distMetric());
if (m) return 1.00F / pow(10, m->precision());
else return 1;
} else {
// use the predefined delta
switch (seriesCombo->currentIndex()) {
case 0: return wattsDelta;
case 1: return wattsKgDelta;
case 2: return hrDelta;
case 3: return kphDelta;
case 4: return cadDelta;
case 5: return nmDelta;
case 6: return wattsDelta; //aPower
default: return 1;
}
}
}
int
HistogramWindow::getDigits()
{
if (rangemode && !data->isChecked()) {
// based upon the metric chosen
const RideMetricFactory &factory = RideMetricFactory::instance();
const RideMetric *m = factory.rideMetric(distMetric());
if (m) return m->precision();
else return 0;
} else {
// use predefined for data series
switch (seriesCombo->currentIndex()) {
case 0: return wattsDigits;
case 1: return wattsKgDigits;
case 2: return hrDigits;
case 3: return kphDigits;
case 4: return cadDigits;
case 5: return nmDigits;
case 6: return wattsDigits; // aPower
default: return 1;
}
}
}