Files
GoldenCheetah/src/FileIO/FixPySettings.cpp
riccioclista 9f1187390f Python data processors (#2951)
* 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
2019-12-19 22:05:51 -03:00

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;