From a1008db76a17969b20f2797617be89a33f462404 Mon Sep 17 00:00:00 2001 From: Joachim Kohlhammer Date: Sun, 17 Aug 2025 23:25:45 +0200 Subject: [PATCH] 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 --- src/Core/Context.h | 2 + src/Gui/AnalysisSidebar.cpp | 19 ++++- src/Gui/MainWindow.cpp | 13 ++++ src/Gui/MainWindow.h | 2 + src/Train/TrainSidebar.cpp | 7 ++ src/Train/TrainSidebar.h | 1 + src/Train/WorkoutFilter.cpp | 59 ++++++++++++++ src/Train/WorkoutFilter.h | 3 +- src/Train/WorkoutFilter.l | 9 ++- src/Train/WorkoutFilter.y | 148 ++++++++++++++++++------------------ 10 files changed, 184 insertions(+), 79 deletions(-) diff --git a/src/Core/Context.h b/src/Core/Context.h index 406a5653d..7aa59112b 100644 --- a/src/Core/Context.h +++ b/src/Core/Context.h @@ -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); diff --git a/src/Gui/AnalysisSidebar.cpp b/src/Gui/AnalysisSidebar.cpp index 230687dd5..e2e5f0430 100644 --- a/src/Gui/AnalysisSidebar.cpp +++ b/src/Gui/AnalysisSidebar.cpp @@ -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 } - - diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index c5d40fd21..b5d8e7a13 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -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 *--------------------------------------------------------------------*/ diff --git a/src/Gui/MainWindow.h b/src/Gui/MainWindow.h index 7b7140b1b..772d5373c 100644 --- a/src/Gui/MainWindow.h +++ b/src/Gui/MainWindow.h @@ -237,6 +237,8 @@ class MainWindow : public QMainWindow void manageLibrary(); void showWorkoutWizard(); void importWorkout(); + void clearWorkoutFilterBox(); + void fillinWorkoutFilterBox(const QString &filterText); // Measures void setMeasuresMenu(); diff --git a/src/Train/TrainSidebar.cpp b/src/Train/TrainSidebar.cpp index 8b74ef097..3314b8543 100644 --- a/src/Train/TrainSidebar.cpp +++ b/src/Train/TrainSidebar.cpp @@ -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) diff --git a/src/Train/TrainSidebar.h b/src/Train/TrainSidebar.h index dfbca8fdd..fc520f5c6 100644 --- a/src/Train/TrainSidebar.h +++ b/src/Train/TrainSidebar.h @@ -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(); diff --git a/src/Train/WorkoutFilter.cpp b/src/Train/WorkoutFilter.cpp index fde918b7b..af57a5f4a 100644 --- a/src/Train/WorkoutFilter.cpp +++ b/src/Train/WorkoutFilter.cpp @@ -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 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 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; +} diff --git a/src/Train/WorkoutFilter.h b/src/Train/WorkoutFilter.h index e723339be..b75d4b22d 100644 --- a/src/Train/WorkoutFilter.h +++ b/src/Train/WorkoutFilter.h @@ -24,10 +24,11 @@ #include #include "ModelFilter.h" +#include "RideItem.h" extern QList parseWorkoutFilter(QString text, bool &ok, QString &msg); extern QStringList workoutFilterCommands(int numZones = 7); - +extern QString buildWorkoutFilter(RideItem * const rideItem); #endif diff --git a/src/Train/WorkoutFilter.l b/src/Train/WorkoutFilter.l index 1b861a441..b602953fc 100644 --- a/src/Train/WorkoutFilter.l +++ b/src/Train/WorkoutFilter.l @@ -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]; } %% diff --git a/src/Train/WorkoutFilter.y b/src/Train/WorkoutFilter.y index 4a663bc21..ef0b0d709 100644 --- a/src/Train/WorkoutFilter.y +++ b/src/Train/WorkoutFilter.y @@ -61,11 +61,11 @@ extern QString workoutModelErrorMsg; %token RATING %token RANGESYMBOL %token SEPARATOR -%token FLOAT -%token NUMBER ZONE PERCENT DAYS TIME MINPOWER MAXPOWER AVGPOWER ISOPOWER POWER LASTRUN CREATED DISTANCE ELEVATION GRADE -%token WORD +%token WF_FLOAT +%token WF_NUMBER ZONE PERCENT DAYS TIME MINPOWER MAXPOWER AVGPOWER ISOPOWER POWER LASTRUN CREATED DISTANCE ELEVATION GRADE +%token WF_WORD FILEPATH -%type zone dominantzone duration stress intensity vi xpower ri bikescore svi rating minpower maxpower avgpower isopower lastrun created distance elevation grade +%type zone dominantzone duration stress intensity vi xpower ri bikescore svi rating minpower maxpower avgpower isopower lastrun created distance elevation grade filepath %type power %type word words %type 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(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2, $4), - new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2, $4)); } - | POWER RANGESYMBOL NUMBER { $$ = new std::pair(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, 0, $3), - new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, 0, $3)); } - | POWER NUMBER RANGESYMBOL { $$ = new std::pair(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2), - new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2)); } +power: POWER WF_NUMBER RANGESYMBOL WF_NUMBER { $$ = new std::pair(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, $2, $4), + new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, $2, $4)); } + | POWER RANGESYMBOL WF_NUMBER { $$ = new std::pair(new ModelNumberRangeFilter(TdbWorkoutModelIdx::minPower, 0, $3), + new ModelNumberRangeFilter(TdbWorkoutModelIdx::maxPower, 0, $3)); } + | POWER WF_NUMBER RANGESYMBOL { $$ = new std::pair(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; } ; %%