mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
Migrate TreeMap LTMPopup to use RideCache
.. the other half, LTMWindow using LTMPopup is now commented out and will need to be fixed when LTMWindow migrates to RideCache
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
#include "LTMPopup.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Athlete.h"
|
||||
#include "Specification.h"
|
||||
#include "RideCache.h"
|
||||
|
||||
LTMPopup::LTMPopup(Context *context) : QWidget(context->mainWindow), context(context)
|
||||
{
|
||||
@@ -108,7 +110,7 @@ LTMPopup::setTitle(QString s)
|
||||
}
|
||||
|
||||
void
|
||||
LTMPopup::setData(QList<SummaryMetrics>data, const RideMetric *metric, QString title)
|
||||
LTMPopup::setData(Specification spec, const RideMetric *metric, QString title)
|
||||
{
|
||||
// create the ride list
|
||||
int count = 0;
|
||||
@@ -129,15 +131,15 @@ LTMPopup::setData(QList<SummaryMetrics>data, const RideMetric *metric, QString t
|
||||
rides->setHorizontalHeaderItem(1,h);
|
||||
|
||||
// now add rows to the table for each entry
|
||||
foreach(SummaryMetrics x, data) {
|
||||
foreach(RideItem *item, context->athlete->rideCache->rides()) {
|
||||
|
||||
QDateTime rideDate = x.getRideDate();
|
||||
if (!spec.pass(item)) continue;
|
||||
|
||||
// we'll select it for summary aggregation
|
||||
selected << x;
|
||||
// what rides were selected ?
|
||||
selected << item->fileName;
|
||||
|
||||
// date/time
|
||||
QTableWidgetItem *t = new QTableWidgetItem(rideDate.toString(tr("ddd, dd MMM yy hh:mmA")));
|
||||
QTableWidgetItem *t = new QTableWidgetItem(item->dateTime.toString(tr("ddd, dd MMM yy hh:mmA")));
|
||||
t->setFlags(t->flags() & (~Qt::ItemIsEditable));
|
||||
t->setTextAlignment(Qt::AlignHCenter);
|
||||
rides->setRowCount(count+1);
|
||||
@@ -145,13 +147,15 @@ LTMPopup::setData(QList<SummaryMetrics>data, const RideMetric *metric, QString t
|
||||
rides->setRowHeight(count, 14);
|
||||
|
||||
// metrics
|
||||
QString value = x.getStringForSymbol(metric->symbol(), context->athlete->useMetricUnits);
|
||||
double d = item->getForSymbol(metric->symbol());
|
||||
const_cast<RideMetric *>(metric)->setValue(d);
|
||||
QString value = metric->toString(context->athlete->useMetricUnits);
|
||||
|
||||
h = new QTableWidgetItem(value,QTableWidgetItem::Type);
|
||||
h->setFlags(t->flags() & (~Qt::ItemIsEditable));
|
||||
h->setTextAlignment(Qt::AlignHCenter);
|
||||
rides->setItem(count, 1, h);
|
||||
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -184,8 +188,9 @@ LTMPopup::setData(QList<SummaryMetrics>data, const RideMetric *metric, QString t
|
||||
}
|
||||
|
||||
void
|
||||
LTMPopup::setData(LTMSettings &settings, QDate start, QDate end, QTime time)
|
||||
LTMPopup::setData(LTMSettings &, QDate, QDate, QTime)
|
||||
{
|
||||
#if 0 // DISABLED IN LTM WINDOW UNTIL IT IS MIGRATED TO RIDECACHE
|
||||
// set the title
|
||||
QString _title;
|
||||
switch (settings.groupBy) {
|
||||
@@ -342,12 +347,12 @@ LTMPopup::setData(LTMSettings &settings, QDate start, QDate end, QTime time)
|
||||
if (nonRideMetrics) _title += QString(tr(" / non ride-related metrics skipped"));
|
||||
|
||||
setTitle(_title);
|
||||
|
||||
rideSelected();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString
|
||||
LTMPopup::setSummaryHTML(SummaryMetrics &results)
|
||||
LTMPopup::setSummaryHTML(RideItem *item)
|
||||
{
|
||||
// where we construct the text
|
||||
QString summaryText("");
|
||||
@@ -435,12 +440,13 @@ LTMPopup::setSummaryHTML(SummaryMetrics &results)
|
||||
|
||||
const RideMetric *metric = RideMetricFactory::instance().rideMetric(metricname);
|
||||
|
||||
QStringList empty; // filter list not used at present
|
||||
QList<SummaryMetrics> resultList1;
|
||||
resultList1 << results;
|
||||
|
||||
// use getAggregated even if it's only 1 file to have consistent value treatment
|
||||
QString value = SummaryMetrics::getAggregated(context, metricname, resultList1, empty, false, context->athlete->useMetricUnits);
|
||||
// use getAggregate even if it's only 1 file to have consistent value treatment
|
||||
double d = item->getForSymbol(metricname, true);
|
||||
QString value;
|
||||
if (metric) {
|
||||
const_cast<RideMetric*>(metric)->setValue(d);
|
||||
value = metric->toString(context->athlete->useMetricUnits);
|
||||
}
|
||||
|
||||
// Maximum Max and Average Average looks nasty, remove from name for display
|
||||
QString s = metric ? metric->name().replace(QRegExp(tr("^(Average|Max) ")), "") : "unknown";
|
||||
@@ -475,21 +481,30 @@ LTMPopup::setSummaryHTML(SummaryMetrics &results)
|
||||
|
||||
|
||||
return summaryText;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
LTMPopup::rideSelected()
|
||||
{
|
||||
// which ride is selected
|
||||
int index = 0;
|
||||
foreach (QTableWidgetItem *item, rides->selectedItems())
|
||||
index = item->row();
|
||||
if (rides->selectedItems().count())
|
||||
index = rides->selectedItems().first()->row();
|
||||
|
||||
// do we have any rides and is the index within bounds
|
||||
if (selected.count() > index) {
|
||||
|
||||
// update summary
|
||||
metrics->setText(setSummaryHTML(selected[index]));
|
||||
notes->setText(selected[index].getText("Notes", ""));
|
||||
RideItem *have = context->athlete->rideCache->getRide(selected[index]);
|
||||
|
||||
if (have) {
|
||||
|
||||
// update summary
|
||||
metrics->setText(""); //! stop crash (?)
|
||||
metrics->setText(setSummaryHTML(have));
|
||||
|
||||
notes->setText(""); //! stop crash (?)
|
||||
notes->setText(have->getText("Notes", ""));
|
||||
}
|
||||
}
|
||||
resizeEvent(NULL);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <QTableWidget>
|
||||
#include <QTableWidgetItem>
|
||||
|
||||
class Specification;
|
||||
class LTMPopup : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -52,7 +53,7 @@ class LTMPopup : public QWidget
|
||||
void setData(LTMSettings &settings, QDate start, QDate end, QTime time);
|
||||
|
||||
// when called from a TreeMap chart
|
||||
void setData(QList<SummaryMetrics>data, const RideMetric *metric, QString title);
|
||||
void setData(Specification spec, const RideMetric *metric, QString title);
|
||||
|
||||
signals:
|
||||
|
||||
@@ -69,11 +70,9 @@ class LTMPopup : public QWidget
|
||||
QTextEdit *metrics;
|
||||
QTextEdit *notes;
|
||||
|
||||
QList<SummaryMetrics> selected;
|
||||
|
||||
// builds HTML text for the selected ride
|
||||
QString setSummaryHTML(SummaryMetrics &results);
|
||||
|
||||
// builds HTML text for the selected ride(s)
|
||||
QString setSummaryHTML(RideItem*);
|
||||
QStringList selected; // filenames
|
||||
};
|
||||
|
||||
// some geometry stuff to make Mac displays nice
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Context.h"
|
||||
#include "Athlete.h"
|
||||
#include "RideFileCache.h"
|
||||
#include "Specification.h"
|
||||
|
||||
#include "Route.h"
|
||||
#include "RouteWindow.h"
|
||||
@@ -325,6 +326,92 @@ RideCache::refresh()
|
||||
}
|
||||
}
|
||||
|
||||
QString
|
||||
RideCache::getAggregate(QString name, Specification spec, bool useMetricUnits, bool nofmt)
|
||||
{
|
||||
// get the metric details, so we can convert etc
|
||||
const RideMetric *metric = RideMetricFactory::instance().rideMetric(name);
|
||||
if (!metric) return QString("%1 unknown").arg(name);
|
||||
|
||||
// what we will return
|
||||
double rvalue = 0;
|
||||
double rcount = 0; // using double to avoid rounding issues with int when dividing
|
||||
|
||||
// loop through and aggregate
|
||||
foreach (RideItem *item, rides()) {
|
||||
|
||||
// skip filtered rides
|
||||
if (!spec.pass(item)) continue;
|
||||
|
||||
// get this value
|
||||
double value = item->getForSymbol(name);
|
||||
double count = item->getForSymbol("workout_time"); // for averaging
|
||||
|
||||
// check values are bounded, just in case
|
||||
if (isnan(value) || isinf(value)) value = 0;
|
||||
|
||||
// imperial / metric conversion
|
||||
if (useMetricUnits == false) {
|
||||
value *= metric->conversion();
|
||||
value += metric->conversionSum();
|
||||
}
|
||||
|
||||
// do we aggregate zero values ?
|
||||
bool aggZero = metric->aggregateZero();
|
||||
|
||||
// set aggZero to false and value to zero if is temperature and -255
|
||||
if (metric->symbol() == "average_temp" && value == RideFile::NoTemp) {
|
||||
value = 0;
|
||||
aggZero = false;
|
||||
}
|
||||
|
||||
switch (metric->type()) {
|
||||
case RideMetric::Total:
|
||||
rvalue += value;
|
||||
break;
|
||||
case RideMetric::Average:
|
||||
{
|
||||
// average should be calculated taking into account
|
||||
// the duration of the ride, otherwise high value but
|
||||
// short rides will skew the overall average
|
||||
if (value || aggZero) {
|
||||
rvalue += value*count;
|
||||
rcount += count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RideMetric::Low:
|
||||
{
|
||||
if (value < rvalue) rvalue = value;
|
||||
break;
|
||||
}
|
||||
case RideMetric::Peak:
|
||||
{
|
||||
if (value > rvalue) rvalue = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now compute the average
|
||||
if (metric->type() == RideMetric::Average) {
|
||||
if (rcount) rvalue = rvalue / rcount;
|
||||
}
|
||||
|
||||
// Format appropriately
|
||||
QString result;
|
||||
if (metric->units(useMetricUnits) == "seconds" ||
|
||||
metric->units(useMetricUnits) == tr("seconds")) {
|
||||
if (nofmt) result = QString("%1").arg(rvalue);
|
||||
else result = time_to_string(rvalue);
|
||||
|
||||
} else result = QString("%1").arg(rvalue, 0, 'f', metric->precision());
|
||||
|
||||
// 0 temp from aggregate means no values
|
||||
if ((metric->symbol() == "average_temp" || metric->symbol() == "max_temp") && result == "0.0") result = "-";
|
||||
return result;
|
||||
}
|
||||
|
||||
class RollingBests {
|
||||
private:
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
class Context;
|
||||
class RideCacheBackgroundRefresh;
|
||||
class Specification;
|
||||
|
||||
class RideCache : public QObject
|
||||
{
|
||||
@@ -53,6 +54,9 @@ class RideCache : public QObject
|
||||
QList<QDateTime> getAllDates();
|
||||
QStringList getAllFilenames();
|
||||
|
||||
// get an aggregate applying the passed spec
|
||||
QString getAggregate(QString name, Specification spec, bool useMetricUnits, bool nofmt=false);
|
||||
|
||||
// metadata
|
||||
QHash<QString,int> getRankedValues(QString name); // metadata
|
||||
QStringList getDistinctValues(QString name); // metadata
|
||||
|
||||
@@ -70,7 +70,7 @@ RideMetric::computeMetrics(const Context *context, const RideFile *ride, const Z
|
||||
}
|
||||
|
||||
QString
|
||||
RideMetric::toString(bool useMetricUnits)
|
||||
RideMetric::toString(bool useMetricUnits) const
|
||||
{
|
||||
if (isTime()) return time_to_string(value(useMetricUnits));
|
||||
return QString("%1").arg(value(useMetricUnits), 0, 'f', precision());
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
virtual bool isTime() const { return false; }
|
||||
|
||||
// Convert value to string, taking into account metric pref
|
||||
virtual QString toString(bool useMetricUnits);
|
||||
virtual QString toString(bool useMetricUnits) const;
|
||||
|
||||
// Fill in the value of the ride metric using the mapping provided. For
|
||||
// example, average speed might be specified by the mapping
|
||||
|
||||
@@ -72,6 +72,9 @@ class Specification
|
||||
void setDateRange(DateRange dr);
|
||||
void setFilterSet(FilterSet fs);
|
||||
|
||||
DateRange dateRange() { return dr; }
|
||||
FilterSet filterSet() { return fs; }
|
||||
|
||||
private:
|
||||
DateRange dr;
|
||||
FilterSet fs;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "LTMSettings.h"
|
||||
#include "Context.h"
|
||||
#include "Athlete.h"
|
||||
#include "RideCache.h"
|
||||
#include "Settings.h"
|
||||
#include "math.h"
|
||||
#include "Units.h" // for MILES_PER_KM
|
||||
@@ -270,27 +271,40 @@ TreeMapWindow::fieldSelected(int)
|
||||
void
|
||||
TreeMapWindow::cellClicked(QString f1, QString f2)
|
||||
{
|
||||
QList<SummaryMetrics> cell;
|
||||
QStringList match;
|
||||
|
||||
// create a list of activities in this cell
|
||||
int count = 0;
|
||||
foreach(SummaryMetrics x, results) {
|
||||
foreach(RideItem *item, context->athlete->rideCache->rides()) {
|
||||
|
||||
// honour the settings
|
||||
if (!settings.specification.pass(item)) continue;
|
||||
|
||||
// text may either not exists, then "unknown" or just be "" but f1, f2 don't know ""
|
||||
QString x1 = x.getText(settings.field1, tr("(unknown)"));
|
||||
QString x2 = x.getText(settings.field2, tr("(unknown)"));
|
||||
QString x1 = item->getText(settings.field1, tr("(unknown)"));
|
||||
QString x2 = item->getText(settings.field2, tr("(unknown)"));
|
||||
if (x1 == "") x1 = tr("(unknown)");
|
||||
if (x2 == "") x2 = tr("(unknown)");
|
||||
// now we can compare and append
|
||||
|
||||
// match !
|
||||
if (x1 == f1 && x2 == f2) {
|
||||
cell.append(x);
|
||||
match << item->fileName;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// create a specification for ours
|
||||
Specification spec;
|
||||
spec.setDateRange(settings.specification.dateRange());
|
||||
FilterSet fs = settings.specification.filterSet();
|
||||
fs.addFilter(true, match);
|
||||
spec.setFilterSet(fs);
|
||||
|
||||
// and the metric to display
|
||||
const RideMetricFactory &factory = RideMetricFactory::instance();
|
||||
const RideMetric *metric = factory.rideMetric(settings.symbol);
|
||||
|
||||
ltmPopup->setData(cell, metric, QString(tr("%1 ride%2")).arg(count).arg(count == 1 ? "" : tr("s")));
|
||||
ltmPopup->setData(spec, metric, QString(tr("%1 ride%2")).arg(count).arg(count == 1 ? "" : tr("s")));
|
||||
popup->show();
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user