mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-15 00:49:55 +00:00
* Initial implementation of Python data processors * Add RideEditor to PyFIx script editor * Enable write-access to activity data for python fixes * Add GC.deleteActivitySample method * Add GC.deleteSeries method * Check for python fix for changes before close * Build python fixes menu dynamically * Make python fixes first class data processors * Add GC.postProcess method * Check GC_WANT_PYTHON and "Enable Python" setting for python fixes * Add GC.createXDataSeries method * Clean up ScriptContext ctor mess * Support editing xdata series * PDP: Implement xdata append/remove methods
226 lines
5.6 KiB
C++
226 lines
5.6 KiB
C++
#include <QDir>
|
|
#include <QFile>
|
|
#include <QTextStream>
|
|
#include <QSettings>
|
|
|
|
#include "FixPySettings.h"
|
|
#include "Settings.h"
|
|
#include "MainWindow.h"
|
|
#include "FixPyDataProcessor.h"
|
|
|
|
FixPySettings::FixPySettings()
|
|
: isInitialied(false), scripts()
|
|
{
|
|
}
|
|
|
|
FixPySettings::~FixPySettings()
|
|
{
|
|
qDeleteAll(scripts);
|
|
}
|
|
|
|
QList<FixPyScript *> FixPySettings::getScripts()
|
|
{
|
|
if (!isInitialied) {
|
|
initialize();
|
|
}
|
|
|
|
return scripts;
|
|
}
|
|
|
|
FixPyScript *FixPySettings::getScript(QString name)
|
|
{
|
|
foreach (FixPyScript *s, getScripts()) {
|
|
if (s->name == name) {
|
|
return s;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
FixPyScript *FixPySettings::createScript(QString name)
|
|
{
|
|
FixPyScript *script = new FixPyScript;
|
|
script->name = name;
|
|
FixPyDataProcessor *fixPyDp = new FixPyDataProcessor(script);
|
|
DataProcessorFactory::instance().registerProcessor(name, fixPyDp);
|
|
scripts.append(script);
|
|
return script;
|
|
}
|
|
|
|
void FixPySettings::deleteScript(QString name)
|
|
{
|
|
QList<FixPyScript *> scripts = getScripts();
|
|
for (int i = 0; i < scripts.size(); i++) {
|
|
FixPyScript *script = scripts[i];
|
|
if (script->name == name) {
|
|
this->scripts.removeAt(i);
|
|
|
|
QSettings iniSettings(gcroot + "/" + PYFIXES_DIR_NAME + "/" + PYFIXES_SETTINGS_FILE_NAME, QSettings::IniFormat);
|
|
iniSettings.remove(script->iniKey);
|
|
iniSettings.sync();
|
|
|
|
QFile pyFile(gcroot + "/" + PYFIXES_DIR_NAME + "/" + script->path);
|
|
pyFile.remove();
|
|
|
|
delete script;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FixPySettings::save()
|
|
{
|
|
QSettings iniSettings(gcroot + "/" + PYFIXES_DIR_NAME + "/" + PYFIXES_SETTINGS_FILE_NAME, QSettings::IniFormat);
|
|
|
|
// delete old py files first
|
|
foreach (FixPyScript *script, getScripts()) {
|
|
if (!script->oldPath.isEmpty()) {
|
|
QFile oldPyFixFile(gcroot + "/" + PYFIXES_DIR_NAME + "/" + script->oldPath);
|
|
oldPyFixFile.remove();
|
|
script->oldPath = QString();
|
|
}
|
|
}
|
|
|
|
int key = getMaxKey();
|
|
foreach (FixPyScript *script, getScripts()) {
|
|
if (script->iniKey.isEmpty()) {
|
|
script->iniKey = QString("f%1").arg(++key);
|
|
script->changed = true;
|
|
}
|
|
|
|
if (script->changed) {
|
|
iniSettings.setValue(script->iniKey + "/name", script->name);
|
|
iniSettings.setValue(script->iniKey + "/path", script->path);
|
|
|
|
QFile pyFile(gcroot + "/" + PYFIXES_DIR_NAME + "/" + script->path);
|
|
if (!pyFile.open(QIODevice::WriteOnly | QIODevice::Text)){
|
|
continue;
|
|
}
|
|
|
|
QTextStream out(&pyFile);
|
|
out << script->source;
|
|
|
|
script->changed = false;
|
|
}
|
|
}
|
|
|
|
iniSettings.sync();
|
|
}
|
|
|
|
void FixPySettings::initialize()
|
|
{
|
|
if (isInitialied || !appsettings->value(nullptr, GC_EMBED_PYTHON, true).toBool()) {
|
|
return;
|
|
}
|
|
|
|
isInitialied = true;
|
|
|
|
QDir gcPath(gcroot);
|
|
if (!gcPath.exists(PYFIXES_DIR_NAME)) {
|
|
gcPath.mkpath(PYFIXES_DIR_NAME);
|
|
}
|
|
|
|
QSettings iniSettings(gcroot + "/" + PYFIXES_DIR_NAME + "/" + PYFIXES_SETTINGS_FILE_NAME, QSettings::IniFormat);
|
|
iniSettings.sync();
|
|
|
|
QDir pyfixesDir(gcroot + "/" + PYFIXES_DIR_NAME);
|
|
QStringList pyFilters;
|
|
pyFilters << "*.py";
|
|
QStringList pyFixFiles = pyfixesDir.entryList(pyFilters, QDir::Files);
|
|
foreach (QString group, iniSettings.childGroups()) {
|
|
QString fixName = iniSettings.value(group + "/name").toString();
|
|
QString fixPath = iniSettings.value(group + "/path").toString();
|
|
if (fixName.isNull() || fixName.isEmpty()) {
|
|
fixName = fixPath;
|
|
}
|
|
|
|
int pyFixFileIdx = pyFixFiles.indexOf(fixPath);
|
|
if (pyFixFileIdx == -1) {
|
|
continue;
|
|
}
|
|
|
|
if (!readPyFixFile(fixName, fixPath, group)) {
|
|
pyFixFiles.removeAt(pyFixFileIdx);
|
|
continue;
|
|
}
|
|
|
|
pyFixFiles.removeAt(pyFixFileIdx);
|
|
}
|
|
|
|
// read remaining files not listed in ini
|
|
foreach (QString pyFixFile, pyFixFiles) {
|
|
QString fixName(pyFixFile);
|
|
fixName.chop(3);
|
|
|
|
// find unique name
|
|
for (int i = 0; i < scripts.size(); i++) {
|
|
if (scripts[i]->name == fixName) {
|
|
fixName = "_" + fixName;
|
|
i = 0;
|
|
}
|
|
}
|
|
|
|
readPyFixFile(fixName, pyFixFile, QString());
|
|
}
|
|
|
|
save();
|
|
}
|
|
|
|
void FixPySettings::disableFixPy()
|
|
{
|
|
if (!isInitialied) return;
|
|
isInitialied = false;
|
|
|
|
foreach (FixPyScript *s, scripts) {
|
|
DataProcessorFactory::instance().unregisterProcessor(s->name);
|
|
}
|
|
|
|
qDeleteAll(scripts);
|
|
scripts.clear();
|
|
}
|
|
|
|
bool FixPySettings::readPyFixFile(QString fixName, QString fixPath, QString iniKey)
|
|
{
|
|
QFile pyFile(gcroot + "/" + PYFIXES_DIR_NAME + "/" + fixPath);
|
|
if (!pyFile.open(QIODevice::ReadOnly | QIODevice::Text)){
|
|
return false;
|
|
}
|
|
|
|
QTextStream in(&pyFile);
|
|
QString fixSource = in.readAll();
|
|
|
|
FixPyScript *script = createScript(fixName);
|
|
script->path = fixPath;
|
|
script->source = fixSource;
|
|
script->iniKey = iniKey;
|
|
return true;
|
|
}
|
|
|
|
int FixPySettings::getMaxKey()
|
|
{
|
|
int maxKey = -1;
|
|
foreach (FixPyScript *fixScript, getScripts()) {
|
|
QString iniKey = fixScript->iniKey;
|
|
if (iniKey.length() < 2) {
|
|
continue;
|
|
}
|
|
|
|
QString keyStr = iniKey.remove(0, 1);
|
|
|
|
bool ok;
|
|
int keyNo = keyStr.toInt(&ok);
|
|
if (!ok) {
|
|
continue;
|
|
}
|
|
|
|
if (keyNo > maxKey) {
|
|
maxKey = keyNo;
|
|
}
|
|
}
|
|
|
|
return maxKey;
|
|
}
|
|
|
|
FixPySettings *fixPySettings = new FixPySettings;
|