Show workout for planned activity in TrainView (#4686)

New option in context menu for planned activities in AnalysisSidebar to
show matching workouts in TrainView
See https://github.com/GoldenCheetah/GoldenCheetah/pull/4686#issuecomment-3194511746
This commit is contained in:
Joachim Kohlhammer
2025-08-17 23:25:45 +02:00
committed by GitHub
parent 81ba70ee3f
commit a1008db76a
10 changed files with 184 additions and 79 deletions

View File

@@ -207,6 +207,7 @@ class Context : public QObject
void notifyMediaSelected( QString x) { videoFilename = x; mediaSelected(x); }
void notifySelectVideo(QString x) { selectMedia(x); }
void notifySelectWorkout(QString x) { selectWorkout(x); }
void notifySelectWorkout(int idx ) { selectWorkout(idx); }
void notifySelectVideoSync(QString x) { selectVideoSync(x); }
void notifySetNow(long x) { now = x; setNow(x); }
long getNow() { return now; }
@@ -330,6 +331,7 @@ class Context : public QObject
void videoSyncFileSelected(VideoSyncFile *);
void mediaSelected(QString);
void selectWorkout(QString); // ask traintool to select this
void selectWorkout(int idx); // ask traintool to select this
void selectMedia(QString); // ask traintool to select this
void selectVideoSync(QString); // ask traintool to select this
void setNow(long);

View File

@@ -39,6 +39,9 @@
// the ride cache
#include "RideCache.h"
// Show in Train Mode
#include "WorkoutFilter.h"
AnalysisSidebar::AnalysisSidebar(Context *context) : QWidget(context->mainWindow), context(context)
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
@@ -408,6 +411,20 @@ AnalysisSidebar::showActivityMenu(const QPoint &pos)
QAction *actFindBest = new QAction(tr("Find Intervals..."), intervalItem);
connect(actFindBest, SIGNAL(triggered(void)), this, SLOT(addIntervals(void)));
menu.addAction(actFindBest);
if (rideItem->planned && rideItem->sport == "Bike") {
QString filter = buildWorkoutFilter(rideItem);
if (! filter.isEmpty()) {
QAction *actStartWorkout = new QAction(tr("Show in Train Mode..."), rideNavigator);
connect(actStartWorkout, &QAction::triggered, [=]() {
context->mainWindow->fillinWorkoutFilterBox(filter);
context->mainWindow->selectTrain();
context->notifySelectWorkout(0);
});
menu.addAction(actStartWorkout);
}
}
menu.addSeparator();
// ride navigator stuff
@@ -1064,5 +1081,3 @@ AnalysisSidebar::backInterval()
#endif
}

View File

@@ -2380,6 +2380,19 @@ MainWindow::importWorkout()
Library::importFiles(currentAthleteTab->context, fileNamesCopy);
}
}
void
MainWindow::clearWorkoutFilterBox()
{
workoutFilterBox->clear();
}
void
MainWindow::fillinWorkoutFilterBox(const QString &filterText)
{
workoutFilterBox->setText(filterText);
}
/*----------------------------------------------------------------------
* TrainerDay
*--------------------------------------------------------------------*/

View File

@@ -237,6 +237,8 @@ class MainWindow : public QMainWindow
void manageLibrary();
void showWorkoutWizard();
void importWorkout();
void clearWorkoutFilterBox();
void fillinWorkoutFilterBox(const QString &filterText);
// Measures
void setMeasuresMenu();

View File

@@ -362,6 +362,7 @@ TrainSidebar::TrainSidebar(Context *context) : GcWindow(context), context(contex
#endif //GC_VIDEO_NONE
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
connect(context, SIGNAL(selectWorkout(QString)), this, SLOT(selectWorkout(QString)));
connect(context, SIGNAL(selectWorkout(int)), this, SLOT(selectWorkout(int)));
connect(trainDB, SIGNAL(dataChanged()), this, SLOT(refresh()));
connect(workoutTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(workoutTreeWidgetSelectionChanged()));
@@ -3263,6 +3264,12 @@ TrainSidebar::selectWorkout(QString fullpath)
}
}
void
TrainSidebar::selectWorkout(int idx)
{
workoutTree->setCurrentIndex(workoutTree->model()->index(idx, TdbWorkoutModelIdx::filepath));
}
// got a remote control command
void
TrainSidebar::remoteControl(uint16_t command)

View File

@@ -161,6 +161,7 @@ class TrainSidebar : public GcWindow
void selectVideo(QString fullpath);
void selectVideoSync(QString fullpath);
void selectWorkout(QString fullpath);
void selectWorkout(int idx);
void removeInvalidVideoSync();
void removeInvalidWorkout();

View File

@@ -84,3 +84,62 @@ workoutFilterCommands
filterCommands.sort(Qt::CaseInsensitive);
return filterCommands;
}
extern QString
buildWorkoutFilter
(RideItem * const rideItem)
{
QString filter;
QString filename = rideItem->getText("WorkoutFilename", "").trimmed();
if (! filename.isEmpty()) {
filter = QString("file \"%1\"").arg(filename);
} else {
QHash<QString, int> ergMetrics;
ergMetrics["duration"] = rideItem->getForSymbol("workout_time");
ergMetrics["avgpower"] = rideItem->getForSymbol("average_pwer");
ergMetrics["stress"] = rideItem->getForSymbol("coggan_tss");
ergMetrics["isopower"] = rideItem->getForSymbol("coggan_np");
ergMetrics["bikescore"] = rideItem->getForSymbol("skiba_bike_score");
ergMetrics["xpower"] = rideItem->getForSymbol("skiba_xpower");
QHash<QString, int> slpMetrics;
slpMetrics["distance"] = rideItem->getForSymbol("total_distance");
slpMetrics["elevation"] = rideItem->getForSymbol("elevation_gain");
for (const QString &key : ergMetrics.keys()) {
if (ergMetrics[key] == 0) {
ergMetrics.remove(key);
}
}
for (const QString &key : slpMetrics.keys()) {
if (slpMetrics[key] == 0) {
slpMetrics.remove(key);
}
}
if (! filename.isEmpty()) {
} else if (ergMetrics.count() > 0) {
bool first = true;
for (const QString &key : ergMetrics.keys()) {
if (! first) {
filter += ", ";
}
if (key == "duration") {
filter += QString("%1 %2:%3").arg(key).arg(ergMetrics[key] / 3600).arg(ergMetrics[key] % 3600 / 60, 2, 10, QChar('0'));
} else {
filter += QString("%1 %2").arg(key).arg(ergMetrics[key]);
}
first = false;
}
} else if (slpMetrics.count() > 0) {
bool first = true;
for (const QString &key : slpMetrics.keys()) {
if (! first) {
filter += ", ";
}
filter += QString("%1 %2").arg(key).arg(slpMetrics[key]);
first = false;
}
}
}
return filter;
}

View File

@@ -24,10 +24,11 @@
#include <QList>
#include "ModelFilter.h"
#include "RideItem.h"
extern QList<ModelFilter*> parseWorkoutFilter(QString text, bool &ok, QString &msg);
extern QStringList workoutFilterCommands(int numZones = 7);
extern QString buildWorkoutFilter(RideItem * const rideItem);
#endif

View File

@@ -46,8 +46,8 @@ extern YYSTYPE yylval;
[0-9]+m { yytext[strlen(yytext) - 1] = '\0'; WorkoutFilterlval.numValue = atoi(yytext) * 30; return DAYS; }
[0-9]+y { yytext[strlen(yytext) - 1] = '\0'; WorkoutFilterlval.numValue = atoi(yytext) * 365; return DAYS; }
[0-9]+:[0-6][0-9] { int minutes = atoi(yytext + strlen(yytext) - 2); yytext[strlen(yytext) - 2] = '\0'; WorkoutFilterlval.numValue = atoi(yytext) * 60 + minutes; return TIME; }
[0-9]+\.[0-9]+ { WorkoutFilterlval.floatValue = QString(yytext).toFloat(); return FLOAT; }
[0-9]+ { WorkoutFilterlval.numValue = atoi(yytext); return NUMBER; }
[0-9]+\.[0-9]+ { WorkoutFilterlval.floatValue = QString(yytext).toFloat(); return WF_FLOAT; }
[0-9]+ { WorkoutFilterlval.numValue = atoi(yytext); return WF_NUMBER; }
[ \t] ; /* ignore white space */
@@ -71,9 +71,10 @@ extern YYSTYPE yylval;
[Dd][Ii][Ss][Tt][Aa][Nn][Cc][Ee] { return DISTANCE; }
[Ee][Ll][Ee][Vv][Aa][Tt][Ii][Oo][Nn] { return ELEVATION; }
[Gg][Rr][Aa][Dd][Ee] { return GRADE; }
[Ff][Ii][Ll][Ee] { return FILEPATH; }
[zZ]([1-9]|10) { yytext += 1; WorkoutFilterlval.numValue = atoi(yytext); return ZONE; }
\"[^\"]+\" { yytext[strlen(yytext) - 1] = '\0'; WorkoutFilterlval.word = yytext + 1; return WORD; }
[^ ,.]+ { WorkoutFilterlval.word = yytext; return WORD; }
\"[^\"]+\" { yytext[strlen(yytext) - 1] = '\0'; WorkoutFilterlval.word = yytext + 1; return WF_WORD; }
[^ ,.]+ { WorkoutFilterlval.word = yytext; return WF_WORD; }
. { return yytext[0]; }
%%

View File

@@ -61,11 +61,11 @@ extern QString workoutModelErrorMsg;
%token RATING
%token RANGESYMBOL
%token SEPARATOR
%token <floatValue> FLOAT
%token <numValue> NUMBER ZONE PERCENT DAYS TIME MINPOWER MAXPOWER AVGPOWER ISOPOWER POWER LASTRUN CREATED DISTANCE ELEVATION GRADE
%token <word> WORD
%token <floatValue> WF_FLOAT
%token <numValue> WF_NUMBER ZONE PERCENT DAYS TIME MINPOWER MAXPOWER AVGPOWER ISOPOWER POWER LASTRUN CREATED DISTANCE ELEVATION GRADE
%token <word> WF_WORD FILEPATH
%type <filter> zone dominantzone duration stress intensity vi xpower ri bikescore svi rating minpower maxpower avgpower isopower lastrun created distance elevation grade
%type <filter> zone dominantzone duration stress intensity vi xpower ri bikescore svi rating minpower maxpower avgpower isopower lastrun created distance elevation grade filepath
%type <filterPair> power
%type <wordList> word words
%type <floatValue> mixedNumValue
@@ -98,6 +98,7 @@ statement: dominantzone { workoutModelFilters << $1; }
| distance { workoutModelFilters << $1; }
| elevation { workoutModelFilters << $1; }
| grade { workoutModelFilters << $1; }
| filepath { workoutModelFilters << $1; }
| words { workoutModelFilters << new ModelStringContainsFilter(TdbWorkoutModelIdx::fulltext, *$1); }
;
@@ -123,78 +124,78 @@ duration: DURATION minuteValue { $$ = new ModelNumberEq
| DURATION minuteValue RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::duration, $2 * 60000); }
;
intensity: INTENSITY mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::intensity, $2, 0.05); }
| INTENSITY mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::intensity, $2, $4); }
| INTENSITY RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::intensity, 0, $3); }
| INTENSITY mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::intensity, $2); }
intensity: INTENSITY mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::intensity, $2, 0.05); }
| INTENSITY mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::intensity, $2, $4); }
| INTENSITY RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::intensity, 0, $3); }
| INTENSITY mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::intensity, $2); }
;
vi: VI mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::vi, $2, 0.05); }
| VI mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::vi, $2, $4); }
| VI RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::vi, 0, $3); }
| VI mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::vi, $2); }
vi: VI mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::vi, $2, 0.05); }
| VI mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::vi, $2, $4); }
| VI RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::vi, 0, $3); }
| VI mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::vi, $2); }
;
xpower: XPOWER mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::xp, $2, 0.05); }
| XPOWER mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::xp, $2, $4); }
| XPOWER RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::xp, 0, $3); }
| XPOWER mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::xp, $2); }
xpower: XPOWER mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::xp, $2, 0.05); }
| XPOWER mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::xp, $2, $4); }
| XPOWER RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::xp, 0, $3); }
| XPOWER mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::xp, $2); }
;
ri: RI mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::ri, $2, 0.05); }
| RI mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::ri, $2, $4); }
| RI RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::ri, 0, $3); }
| RI mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::ri, $2); }
ri: RI mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::ri, $2, 0.05); }
| RI mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::ri, $2, $4); }
| RI RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::ri, 0, $3); }
| RI mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::ri, $2); }
;
bikescore: BIKESCORE mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::bs, $2, 0.05); }
| BIKESCORE mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::bs, $2, $4); }
| BIKESCORE RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::bs, 0, $3); }
| BIKESCORE mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::bs, $2); }
bikescore: BIKESCORE mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::bs, $2, 0.05); }
| BIKESCORE mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::bs, $2, $4); }
| BIKESCORE RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::bs, 0, $3); }
| BIKESCORE mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::bs, $2); }
;
svi: SVI mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::svi, $2, 0.05); }
| SVI mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::svi, $2, $4); }
| SVI RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::svi, 0, $3); }
| SVI mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::svi, $2); }
svi: SVI mixedNumValue { $$ = new ModelFloatEqualFilter(TdbWorkoutModelIdx::svi, $2, 0.05); }
| SVI mixedNumValue RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::svi, $2, $4); }
| SVI RANGESYMBOL mixedNumValue { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::svi, 0, $3); }
| SVI mixedNumValue RANGESYMBOL { $$ = new ModelFloatRangeFilter(TdbWorkoutModelIdx::svi, $2); }
;
stress: STRESS NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::bikestress, $2); }
| STRESS NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::bikestress, $2, $4); }
| STRESS RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::bikestress, 0, $3); }
| STRESS NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::bikestress, $2); }
stress: STRESS WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::bikestress, $2); }
| STRESS WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::bikestress, $2, $4); }
| STRESS RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::bikestress, 0, $3); }
| STRESS WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::bikestress, $2); }
;
minpower: MINPOWER NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::minPower, $2); }
| MINPOWER NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2, $4); }
| MINPOWER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, 0, $3); }
| MINPOWER NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2); }
minpower: MINPOWER WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::minPower, $2); }
| MINPOWER WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2, $4); }
| MINPOWER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, 0, $3); }
| MINPOWER WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2); }
;
maxpower: MAXPOWER NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::maxPower, $2); }
| MAXPOWER NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2, $4); }
| MAXPOWER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, 0, $3); }
| MAXPOWER NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2); }
maxpower: MAXPOWER WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::maxPower, $2); }
| MAXPOWER WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2, $4); }
| MAXPOWER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, 0, $3); }
| MAXPOWER WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2); }
;
avgpower: AVGPOWER NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::avgPower, $2, 5); }
| AVGPOWER NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::avgPower, $2, $4); }
| AVGPOWER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::avgPower, 0, $3); }
| AVGPOWER NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::avgPower, $2); }
avgpower: AVGPOWER WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::avgPower, $2, 5); }
| AVGPOWER WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::avgPower, $2, $4); }
| AVGPOWER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::avgPower, 0, $3); }
| AVGPOWER WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::avgPower, $2); }
;
isopower: ISOPOWER NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::isoPower, $2, 5); }
| ISOPOWER NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::isoPower, $2, $4); }
| ISOPOWER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::isoPower, 0, $3); }
| ISOPOWER NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::isoPower, $2); }
isopower: ISOPOWER WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::isoPower, $2, 5); }
| ISOPOWER WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::isoPower, $2, $4); }
| ISOPOWER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::isoPower, 0, $3); }
| ISOPOWER WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::isoPower, $2); }
;
power: POWER NUMBER RANGESYMBOL NUMBER { $$ = new std::pair<ModelFilter*, ModelFilter*>(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2, $4),
new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2, $4)); }
| POWER RANGESYMBOL NUMBER { $$ = new std::pair<ModelFilter*, ModelFilter*>(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, 0, $3),
new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, 0, $3)); }
| POWER NUMBER RANGESYMBOL { $$ = new std::pair<ModelFilter*, ModelFilter*>(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2),
new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2)); }
power: POWER WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new std::pair<ModelFilter*, ModelFilter*>(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2, $4),
new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2, $4)); }
| POWER RANGESYMBOL WF_NUMBER { $$ = new std::pair<ModelFilter*, ModelFilter*>(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, 0, $3),
new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, 0, $3)); }
| POWER WF_NUMBER RANGESYMBOL { $$ = new std::pair<ModelFilter*, ModelFilter*>(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2),
new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2)); }
lastrun: LASTRUN DAYS RANGESYMBOL DAYS { long now = QDateTime::currentDateTime().toSecsSinceEpoch();
$$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::lastRun, now - $4 * 86400, now - $2 * 86400); }
@@ -212,22 +213,22 @@ created: CREATED DAYS RANGESYMBOL DAYS { long now = QDateTime::currentDateTime(
$$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::created, 0, now - $2 * 86400); }
;
rating: RATING NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::rating, $2); }
| RATING NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::rating, $2, $4); }
| RATING RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::rating, 1, $3); }
| RATING NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::rating, $2, 5); }
rating: RATING WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::rating, $2); }
| RATING WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::rating, $2, $4); }
| RATING RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::rating, 1, $3); }
| RATING WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::rating, $2, 5); }
;
distance: DISTANCE NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::distance, $2 * 1000, 5000); }
| DISTANCE NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::distance, $2 * 1000, $4 * 1000); }
| DISTANCE RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::distance, 0, $3 * 1000); }
| DISTANCE NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::distance, $2 * 1000); }
distance: DISTANCE WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::distance, $2 * 1000, 5000); }
| DISTANCE WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::distance, $2 * 1000, $4 * 1000); }
| DISTANCE RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::distance, 0, $3 * 1000); }
| DISTANCE WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::distance, $2 * 1000); }
;
elevation: ELEVATION NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::elevation, $2, 5); }
| ELEVATION NUMBER RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::elevation, $2, $4); }
| ELEVATION RANGESYMBOL NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::elevation, 0, $3); }
| ELEVATION NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::elevation, $2); }
elevation: ELEVATION WF_NUMBER { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::elevation, $2, 5); }
| ELEVATION WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::elevation, $2, $4); }
| ELEVATION RANGESYMBOL WF_NUMBER { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::elevation, 0, $3); }
| ELEVATION WF_NUMBER RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::elevation, $2); }
;
grade: GRADE PERCENT { $$ = new ModelNumberEqualFilter(TdbWorkoutModelIdx::avgGrade, $2, 5); }
@@ -236,20 +237,23 @@ grade: GRADE PERCENT { $$ = new ModelNumberEqualFilter(TdbW
| GRADE PERCENT RANGESYMBOL { $$ = new ModelNumberRangeFilter(TdbWorkoutModelIdx::avgGrade, $2); }
;
filepath: FILEPATH word { $$ = new ModelStringContainsFilter(TdbWorkoutModelIdx::filepath, *$2); }
;
words: word words { *$1 << *$2; delete $2; $$ = $1; }
| word { $$ = $1; }
;
word: WORD { $$ = new QStringList($1); }
| NUMBER { $$ = new QStringList(QString::number($1)); }
word: WF_WORD { $$ = new QStringList($1); }
| WF_NUMBER { $$ = new QStringList(QString::number($1)); }
;
mixedNumValue: FLOAT { $$ = $1; }
| NUMBER { $$ = $1; }
mixedNumValue: WF_FLOAT { $$ = $1; }
| WF_NUMBER { $$ = $1; }
;
minuteValue: NUMBER { $$ = $1; }
| TIME { $$ = $1; }
minuteValue: WF_NUMBER { $$ = $1; }
| TIME { $$ = $1; }
;
%%