diff --git a/src/Charts/PythonChart.cpp b/src/Charts/PythonChart.cpp index f47065a49..1c9b1442f 100644 --- a/src/Charts/PythonChart.cpp +++ b/src/Charts/PythonChart.cpp @@ -202,7 +202,7 @@ void PythonConsole::keyPressEvent(QKeyEvent *e) bool readOnly = pythonHost->readOnly(); QList editedRideFiles; python->cancelled = false; - python->runline(ScriptContext(context, nullptr, true, readOnly, &editedRideFiles), line); + python->runline(ScriptContext(context, nullptr, nullptr, true, readOnly, &editedRideFiles), line); // finish up commands on edited rides foreach (RideFile *f, editedRideFiles) { diff --git a/src/FileIO/FixPyDataProcessor.cpp b/src/FileIO/FixPyDataProcessor.cpp index b965cefbe..61504fbd7 100644 --- a/src/FileIO/FixPyDataProcessor.cpp +++ b/src/FileIO/FixPyDataProcessor.cpp @@ -1,5 +1,6 @@ #include "FixPyDataProcessor.h" #include "FixPyRunner.h" +#include "Athlete.h" // Config widget used by the Preferences/Options config panes class FixPyDataProcessorConfig : public DataProcessorConfig @@ -24,7 +25,17 @@ bool FixPyDataProcessor::postProcess(RideFile *rideFile, DataProcessorConfig *se QString errText; bool useNewThread = op != "PYTHON"; Context* context = (rideFile) ? rideFile->context : nullptr; - FixPyRunner pyRunner(context, rideFile, useNewThread); + RideItem* rideItem = nullptr; + if (context && rideFile) { + // get RideItem from RideFile for Python functions using it + foreach(RideItem *item, context->athlete->rideCache->rides()) { + if (item->dateTime == rideFile->startTime()) { + rideItem = item; + break; + } + } + } + FixPyRunner pyRunner(context, rideFile, rideItem, useNewThread); return pyRunner.run(pyScript->source, pyScript->iniKey, errText) == 0; } diff --git a/src/FileIO/FixPyRunner.cpp b/src/FileIO/FixPyRunner.cpp index 8afb89246..2afe47d42 100644 --- a/src/FileIO/FixPyRunner.cpp +++ b/src/FileIO/FixPyRunner.cpp @@ -5,8 +5,8 @@ #include "PythonEmbed.h" #include "RideFileCommand.h" -FixPyRunner::FixPyRunner(Context *context, RideFile *rideFile, bool useNewThread) - : context(context), rideFile(rideFile), useNewThread(useNewThread) +FixPyRunner::FixPyRunner(Context *context, RideFile *rideFile, RideItem *rideItem, bool useNewThread) + : context(context), rideFile(rideFile), rideItem(rideItem), useNewThread(useNewThread) { } @@ -34,6 +34,7 @@ int FixPyRunner::run(QString source, QString scriptKey, QString &errText) FixPyRunParams params; params.context = context; params.rideFile = rideFile; + params.rideItem = rideItem; params.script = QString(line); if (useNewThread) { @@ -75,7 +76,7 @@ void FixPyRunner::execScript(FixPyRunParams *params) QList editedRideFiles; python->canvas = NULL; python->chart = NULL; - python->runline(ScriptContext(params->context, params->rideFile, false, + python->runline(ScriptContext(params->context, params->rideFile, params->rideItem, false, false, &editedRideFiles), params->script); // finish up commands on edited rides diff --git a/src/FileIO/FixPyRunner.h b/src/FileIO/FixPyRunner.h index 3fb125317..431b2b457 100644 --- a/src/FileIO/FixPyRunner.h +++ b/src/FileIO/FixPyRunner.h @@ -11,6 +11,7 @@ struct FixPyRunParams { Context *context; RideFile *rideFile; + RideItem *rideItem; QString script; }; @@ -19,7 +20,7 @@ class FixPyRunner : public QObject Q_OBJECT public: - FixPyRunner(Context *context = nullptr, RideFile *rideFile = nullptr, bool useNewThread = true); + FixPyRunner(Context *context = nullptr, RideFile *rideFile = nullptr, RideItem *rideItem = nullptr, bool useNewThread = true); int run(QString source, QString scriptKey, QString &errText); static void execScript(FixPyRunParams *params); @@ -27,6 +28,7 @@ public: private: Context *context; RideFile *rideFile; + RideItem *rideItem; bool useNewThread; }; diff --git a/src/Python/PythonEmbed.h b/src/Python/PythonEmbed.h index bfb9c8ec9..e69ab6807 100644 --- a/src/Python/PythonEmbed.h +++ b/src/Python/PythonEmbed.h @@ -43,9 +43,9 @@ class ScriptContext { interactiveShell(interactiveShell), readOnly(true), editedRideFiles(NULL) {} // read/write ctor - ScriptContext(Context *context, RideFile *rideFile, bool interactiveShell, + ScriptContext(Context *context, RideFile *rideFile, RideItem *item, bool interactiveShell, bool readOnly, QList *editedRideFiles) - : context(context), item(NULL), rideFile(rideFile), metrics(NULL), spec(), + : context(context), item(item), rideFile(rideFile), metrics(NULL), spec(), interactiveShell(interactiveShell), readOnly(readOnly), editedRideFiles(editedRideFiles) {} // default ctor diff --git a/src/Python/SIP/Bindings.cpp b/src/Python/SIP/Bindings.cpp index d777b0c02..5daa9706c 100644 --- a/src/Python/SIP/Bindings.cpp +++ b/src/Python/SIP/Bindings.cpp @@ -1630,11 +1630,7 @@ Bindings::setTag(QString name, QString value, PyObject *activity) const Context *context = python->contexts.value(threadid()).context; if (context == nullptr) return false; - RideItem* m = fromDateTime(activity); - if (m == nullptr) m = const_cast(context->currentRideItem()); - if (m == nullptr) return false; - - RideFile *f = m->ride(); + RideFile *f = selectRideFile(activity); if (f == nullptr) return false; name = name.replace("_"," "); @@ -1656,10 +1652,16 @@ Bindings::setTag(QString name, QString value, PyObject *activity) const f->setTag(name, value); } - // rideFile is now dirty! - m->setDirty(true); - // get refresh done, coz overrides state has changed - m->notifyRideMetadataChanged(); + // Notify changes if activity is already in rideCache + RideItem* m = fromDateTime(activity); + if (m == nullptr) m = python->contexts.value(threadid()).item; + if (m == nullptr) m = context->rideItem(); + if (m && m->dateTime == f->startTime()) { + // rideFile is now dirty! + m->setDirty(true); + // get refresh done, coz overrides state has changed + m->notifyRideMetadataChanged(); + } return true; } @@ -1673,23 +1675,25 @@ Bindings::delTag(QString name, PyObject *activity) const Context *context = python->contexts.value(threadid()).context; if (context == nullptr) return false; - RideItem* m = fromDateTime(activity); - if (m == nullptr) m = const_cast(context->currentRideItem()); - if (m == nullptr) return false; - - RideFile *f = m->ride(); + RideFile *f = selectRideFile(activity); if (f == nullptr) return false; + RideItem* m = fromDateTime(activity); + if (m == nullptr) m = python->contexts.value(threadid()).item; + if (m == nullptr) m = context->rideItem(); + name = name.replace("_"," "); if (GlobalContext::context()->specialFields.isMetric(name)) { if (f->metricOverrides.remove(GlobalContext::context()->specialFields.metricSymbol(name))) { - // rideFile is now dirty! - m->setDirty(true); - // get refresh done, coz overrides state has changed - m->notifyRideMetadataChanged(); - + // Notify changes if activity is already in rideCache + if (m && m->dateTime == f->startTime()) { + // rideFile is now dirty! + m->setDirty(true); + // get refresh done, coz overrides state has changed + m->notifyRideMetadataChanged(); + } return true; } return false; @@ -1698,11 +1702,13 @@ Bindings::delTag(QString name, PyObject *activity) const if (f->removeTag(name)) { - // rideFile is now dirty! - m->setDirty(true); - // get refresh done, coz overrides state has changed - m->notifyRideMetadataChanged(); - + // Notify changes if activity is already in rideCache + if (m && m->dateTime == f->startTime()) { + // rideFile is now dirty! + m->setDirty(true); + // get refresh done, coz overrides state has changed + m->notifyRideMetadataChanged(); + } return true; } return false; @@ -1715,15 +1721,31 @@ Bindings::hasTag(QString name, PyObject *activity) const Context *context = python->contexts.value(threadid()).context; if (context == nullptr) return false; - RideItem* m = fromDateTime(activity); - if (m == nullptr) m = const_cast(context->currentRideItem()); - if (m == nullptr) return false; + RideFile *f = selectRideFile(activity); + if (f == nullptr) return false; name = name.replace("_"," "); if (GlobalContext::context()->specialFields.isMetric(name)) { - return m->overrides_.contains(GlobalContext::context()->specialFields.metricSymbol(name)); + return f->metricOverrides.contains(GlobalContext::context()->specialFields.metricSymbol(name)); } else { - return m->hasText(name); + return f->tags().contains(name); + } +} + +QString +Bindings::getTag(QString name, PyObject *activity) const +{ + Context *context = python->contexts.value(threadid()).context; + if (context == nullptr) return QString(); + + RideFile *f = selectRideFile(activity); + if (f == nullptr) return QString(); + + name = name.replace("_"," "); + if (GlobalContext::context()->specialFields.isMetric(name)) { + return f->metricOverrides[GlobalContext::context()->specialFields.metricSymbol(name)]["value"]; + } else { + return f->getTag(name, ""); } } diff --git a/src/Python/SIP/Bindings.h b/src/Python/SIP/Bindings.h index 78be092ca..24679ca65 100644 --- a/src/Python/SIP/Bindings.h +++ b/src/Python/SIP/Bindings.h @@ -119,6 +119,7 @@ class Bindings { bool setTag(QString name, QString value, PyObject *activity = NULL) const; bool delTag(QString name, PyObject *activity = NULL) const; bool hasTag(QString name, PyObject *activity = NULL) const; + QString getTag(QString name, PyObject *activity = NULL) const; // working with charts bool configChart(QString title, int type, bool animate, int pos, bool stack, int orientation) const; diff --git a/src/Python/SIP/goldencheetah.sip b/src/Python/SIP/goldencheetah.sip index 78e68049a..5b64db02d 100644 --- a/src/Python/SIP/goldencheetah.sip +++ b/src/Python/SIP/goldencheetah.sip @@ -390,6 +390,7 @@ public: bool setTag(QString name, QString value, PyObject *activity = NULL) const; bool delTag(QString name, PyObject *activity = NULL) const; bool hasTag(QString name, PyObject *activity = NULL) const; + QString getTag(QString name, PyObject *activity = NULL) const; // working with qt charts bool configChart(QString title, int type, bool animate, int legpos, bool stack, int orientation) const; diff --git a/src/Python/SIP/sipAPIgoldencheetah.h b/src/Python/SIP/sipAPIgoldencheetah.h index 036a07cea..bbe12ccd8 100644 --- a/src/Python/SIP/sipAPIgoldencheetah.h +++ b/src/Python/SIP/sipAPIgoldencheetah.h @@ -139,76 +139,78 @@ #define sipName_labels &sipStrings_goldencheetah[410] #define sipNameNr_legpos 688 #define sipName_legpos &sipStrings_goldencheetah[688] -#define sipNameNr_hasTag 695 -#define sipName_hasTag &sipStrings_goldencheetah[695] -#define sipNameNr_delTag 702 -#define sipName_delTag &sipStrings_goldencheetah[702] -#define sipNameNr_setTag 709 -#define sipName_setTag &sipStrings_goldencheetah[709] -#define sipNameNr_metric 716 -#define sipName_metric &sipStrings_goldencheetah[716] +#define sipNameNr_getTag 695 +#define sipName_getTag &sipStrings_goldencheetah[695] +#define sipNameNr_hasTag 702 +#define sipName_hasTag &sipStrings_goldencheetah[702] +#define sipNameNr_delTag 709 +#define sipName_delTag &sipStrings_goldencheetah[709] +#define sipNameNr_setTag 716 +#define sipName_setTag &sipStrings_goldencheetah[716] +#define sipNameNr_metric 723 +#define sipName_metric &sipStrings_goldencheetah[723] #define sipNameNr_series 565 #define sipName_series &sipStrings_goldencheetah[565] -#define sipNameNr_season 723 -#define sipName_season &sipStrings_goldencheetah[723] -#define sipNameNr_filter 730 -#define sipName_filter &sipStrings_goldencheetah[730] -#define sipNameNr_result 737 -#define sipName_result &sipStrings_goldencheetah[737] -#define sipNameNr_remove 744 -#define sipName_remove &sipStrings_goldencheetah[744] -#define sipNameNr_append 751 -#define sipName_append &sipStrings_goldencheetah[751] -#define sipNameNr_align 758 -#define sipName_align &sipStrings_goldencheetah[758] +#define sipNameNr_season 730 +#define sipName_season &sipStrings_goldencheetah[730] +#define sipNameNr_filter 737 +#define sipName_filter &sipStrings_goldencheetah[737] +#define sipNameNr_result 744 +#define sipName_result &sipStrings_goldencheetah[744] +#define sipNameNr_remove 751 +#define sipName_remove &sipStrings_goldencheetah[751] +#define sipNameNr_append 758 +#define sipName_append &sipStrings_goldencheetah[758] +#define sipNameNr_align 765 +#define sipName_align &sipStrings_goldencheetah[765] #define sipNameNr_color 400 #define sipName_color &sipStrings_goldencheetah[400] -#define sipNameNr_yname 764 -#define sipName_yname &sipStrings_goldencheetah[764] -#define sipNameNr_xname 770 -#define sipName_xname &sipStrings_goldencheetah[770] -#define sipNameNr_stack 776 -#define sipName_stack &sipStrings_goldencheetah[776] -#define sipNameNr_title 782 -#define sipName_title &sipStrings_goldencheetah[782] -#define sipNameNr_index 788 -#define sipName_index &sipStrings_goldencheetah[788] -#define sipNameNr_group 794 -#define sipName_group &sipStrings_goldencheetah[794] -#define sipNameNr_xdata 800 -#define sipName_xdata &sipStrings_goldencheetah[800] -#define sipNameNr_sport 806 -#define sipName_sport &sipStrings_goldencheetah[806] -#define sipNameNr_value 812 -#define sipName_value &sipStrings_goldencheetah[812] -#define sipNameNr_build 818 -#define sipName_build &sipStrings_goldencheetah[818] -#define sipNameNr_fill 824 -#define sipName_fill &sipStrings_goldencheetah[824] -#define sipNameNr_line 829 -#define sipName_line &sipStrings_goldencheetah[829] -#define sipNameNr_join 834 -#define sipName_join &sipStrings_goldencheetah[834] -#define sipNameNr_name 765 -#define sipName_name &sipStrings_goldencheetah[765] -#define sipNameNr_type 839 -#define sipName_type &sipStrings_goldencheetah[839] -#define sipNameNr_date 844 -#define sipName_date &sipStrings_goldencheetah[844] -#define sipNameNr_log 849 -#define sipName_log &sipStrings_goldencheetah[849] +#define sipNameNr_yname 771 +#define sipName_yname &sipStrings_goldencheetah[771] +#define sipNameNr_xname 777 +#define sipName_xname &sipStrings_goldencheetah[777] +#define sipNameNr_stack 783 +#define sipName_stack &sipStrings_goldencheetah[783] +#define sipNameNr_title 789 +#define sipName_title &sipStrings_goldencheetah[789] +#define sipNameNr_index 795 +#define sipName_index &sipStrings_goldencheetah[795] +#define sipNameNr_group 801 +#define sipName_group &sipStrings_goldencheetah[801] +#define sipNameNr_xdata 807 +#define sipName_xdata &sipStrings_goldencheetah[807] +#define sipNameNr_sport 813 +#define sipName_sport &sipStrings_goldencheetah[813] +#define sipNameNr_value 819 +#define sipName_value &sipStrings_goldencheetah[819] +#define sipNameNr_build 825 +#define sipName_build &sipStrings_goldencheetah[825] +#define sipNameNr_fill 831 +#define sipName_fill &sipStrings_goldencheetah[831] +#define sipNameNr_line 836 +#define sipName_line &sipStrings_goldencheetah[836] +#define sipNameNr_join 841 +#define sipName_join &sipStrings_goldencheetah[841] +#define sipNameNr_name 772 +#define sipName_name &sipStrings_goldencheetah[772] +#define sipNameNr_type 846 +#define sipName_type &sipStrings_goldencheetah[846] +#define sipNameNr_date 851 +#define sipName_date &sipStrings_goldencheetah[851] +#define sipNameNr_log 856 +#define sipName_log &sipStrings_goldencheetah[856] #define sipNameNr_max 120 #define sipName_max &sipStrings_goldencheetah[120] -#define sipNameNr_min 853 -#define sipName_min &sipStrings_goldencheetah[853] -#define sipNameNr_all 857 -#define sipName_all &sipStrings_goldencheetah[857] -#define sipNameNr_url 861 -#define sipName_url &sipStrings_goldencheetah[861] -#define sipNameNr_s2 865 -#define sipName_s2 &sipStrings_goldencheetah[865] -#define sipNameNr_s1 868 -#define sipName_s1 &sipStrings_goldencheetah[868] +#define sipNameNr_min 860 +#define sipName_min &sipStrings_goldencheetah[860] +#define sipNameNr_all 864 +#define sipName_all &sipStrings_goldencheetah[864] +#define sipNameNr_url 868 +#define sipName_url &sipStrings_goldencheetah[868] +#define sipNameNr_s2 872 +#define sipName_s2 &sipStrings_goldencheetah[872] +#define sipNameNr_s1 875 +#define sipName_s1 &sipStrings_goldencheetah[875] #define sipMalloc sipAPI_goldencheetah->api_malloc #define sipFree sipAPI_goldencheetah->api_free diff --git a/src/Python/SIP/sipgoldencheetahBindings.cpp b/src/Python/SIP/sipgoldencheetahBindings.cpp index e65dfeb9a..3d73aab4a 100644 --- a/src/Python/SIP/sipgoldencheetahBindings.cpp +++ b/src/Python/SIP/sipgoldencheetahBindings.cpp @@ -1182,6 +1182,40 @@ static PyObject *meth_Bindings_hasTag(PyObject *sipSelf, PyObject *sipArgs, PyOb } +extern "C" {static PyObject *meth_Bindings_getTag(PyObject *, PyObject *, PyObject *);} +static PyObject *meth_Bindings_getTag(PyObject *sipSelf, PyObject *sipArgs, PyObject *sipKwds) +{ + PyObject *sipParseErr = NULL; + + { + ::QString* a0; + int a0State = 0; + PyObject * a1 = 0; + const ::Bindings *sipCpp; + + static const char *sipKwdList[] = { + sipName_name, + sipName_activity, + }; + + if (sipParseKwdArgs(&sipParseErr, sipArgs, sipKwds, sipKwdList, NULL, "BJ1|P0", &sipSelf, sipType_Bindings, &sipCpp, sipType_QString,&a0, &a0State, &a1)) + { + ::QString*sipRes; + + sipRes = new ::QString(sipCpp->getTag(*a0,a1)); + sipReleaseType(a0,sipType_QString,a0State); + + return sipConvertFromNewType(sipRes,sipType_QString,NULL); + } + } + + /* Raise an exception if the arguments couldn't be parsed. */ + sipNoMethod(sipParseErr, sipName_Bindings, sipName_getTag, NULL); + + return NULL; +} + + extern "C" {static PyObject *meth_Bindings_configChart(PyObject *, PyObject *, PyObject *);} static PyObject *meth_Bindings_configChart(PyObject *sipSelf, PyObject *sipArgs, PyObject *sipKwds) { @@ -1482,6 +1516,7 @@ static PyMethodDef methods_Bindings[] = { {SIP_MLNAME_CAST(sipName_delTag), (PyCFunction)meth_Bindings_delTag, METH_VARARGS|METH_KEYWORDS, NULL}, {SIP_MLNAME_CAST(sipName_deleteActivitySample), (PyCFunction)meth_Bindings_deleteActivitySample, METH_VARARGS|METH_KEYWORDS, NULL}, {SIP_MLNAME_CAST(sipName_deleteSeries), (PyCFunction)meth_Bindings_deleteSeries, METH_VARARGS|METH_KEYWORDS, NULL}, + {SIP_MLNAME_CAST(sipName_getTag), (PyCFunction)meth_Bindings_getTag, METH_VARARGS|METH_KEYWORDS, NULL}, {SIP_MLNAME_CAST(sipName_hasTag), (PyCFunction)meth_Bindings_hasTag, METH_VARARGS|METH_KEYWORDS, NULL}, {SIP_MLNAME_CAST(sipName_intervalType), (PyCFunction)meth_Bindings_intervalType, METH_VARARGS|METH_KEYWORDS, NULL}, {SIP_MLNAME_CAST(sipName_metrics), (PyCFunction)meth_Bindings_metrics, METH_VARARGS|METH_KEYWORDS, NULL}, @@ -1522,7 +1557,7 @@ sipClassTypeDef sipTypeDef_goldencheetah_Bindings = { { sipNameNr_Bindings, {0, 0, 1}, - 39, methods_Bindings, + 40, methods_Bindings, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, diff --git a/src/Python/SIP/sipgoldencheetahcmodule.cpp b/src/Python/SIP/sipgoldencheetahcmodule.cpp index c19d337fa..335318156 100644 --- a/src/Python/SIP/sipgoldencheetahcmodule.cpp +++ b/src/Python/SIP/sipgoldencheetahcmodule.cpp @@ -80,6 +80,7 @@ const char sipStrings_goldencheetah[] = { 's', 'y', 'm', 'b', 'o', 'l', 0, 'c', 'o', 'l', 'o', 'r', 's', 0, 'l', 'e', 'g', 'p', 'o', 's', 0, + 'g', 'e', 't', 'T', 'a', 'g', 0, 'h', 'a', 's', 'T', 'a', 'g', 0, 'd', 'e', 'l', 'T', 'a', 'g', 0, 's', 'e', 't', 'T', 'a', 'g', 0,