SXXXXXXX_PyBusMonitor1553/cpp/GrifoScope/QgScope/qgpythonsandbox.cpp
2025-12-17 07:59:30 +01:00

400 lines
9.5 KiB
C++

#include "qgpythonsandbox.h"
#include <QLibrary>
#include <QDir>
#include <QSettings>
#include <QMessageBox>
#include <QDebug>
#include <QCoreApplication>
#include "qgpythoninterface.h"
//typedef QWidget* (*qgp_create_console_t)(QWidget*);
typedef QgPythonInterface* (*qgp_instance_t)(void);
class QDialog;
class StubPython: public QgPythonInterface
{
public:
class StubWidgets: public QgPythonWidgets
{
public:
virtual QWidget* createConsole(QWidget*) override
{
return 0;
}
virtual QDialog* createEditDialog(QWidget*) override
{
return 0;
}
};
virtual QgPythonWidgets* pythonWidgets()
{
static StubWidgets stub;
return &stub;
}
virtual PythonQtObjectPtr* mainModule() override
{
return 0;
}
virtual PythonQtObjectPtr* createModule(const QString& /*module_name*/) override
{
return 0;
}
virtual PythonQtObjectPtr* createModuleFromScript(const QString& , const QString& ) override
{
return 0;
}
virtual PythonQtObjectPtr* createModuleFromFile(const QString& , const QString& ) override
{
return 0;
}
virtual bool addObject(const QString& , QObject*, PythonQtObjectPtr* /*module*/) override
{
return 0;
}
virtual bool evalScript(const QString& , PythonQtObjectPtr* ) override
{
return 0;
}
virtual bool evalFile(const QString& , PythonQtObjectPtr* ) override
{
return 0;
}
};
class SandboxContext
{
public:
StubPython stubs;
bool enable;
QWidget* consoleWidget;
QDialog* editDialog;
QgPythonInterface* pyif;
PythonQtObjectPtr* appModule;
qgp_instance_t create_instance;
QString qglib_name;
QString qglib_version;
QString qglib_dbg;
QString pyhome;
QString pylib;
QStringList pSymb;
SandboxContext():
enable(true),
consoleWidget(0),
editDialog(0),
pyif(&stubs),
appModule(0),
qglib_name("QgPython"),
qglib_version("36"),
#if !defined(QT_NO_DEBUG)
qglib_dbg("_d")
#else
qglib_dbg("")
#endif
{
}
void py_sethome(const QString s)
{
pyhome=QDir::toNativeSeparators(s);
qputenv("PYTHONHOME", s.toLatin1().constData());
qDebug()<<"PYENV:"<<"PYTHONHOME"<<"="<<s;
qDebug()<<"LIBPATH:"<<QCoreApplication::libraryPaths();
}
void py_setenv(const char* vname, const QString s)
{
if (s.isEmpty())
{
return;
}
static const QString pattern("${pythonhome}");
QString value=s;
QStringList tmp=s.split(';');
if (tmp.size()>1)
{
value=tmp.at(0);
value.replace(pattern, pyhome, Qt::CaseInsensitive);
value=QDir::toNativeSeparators(value);
for(int i=1; i<tmp.size(); ++i)
{
QString ns=tmp.at(i);
ns.replace(pattern, pyhome, Qt::CaseInsensitive);
value+=';';
value+=QDir::toNativeSeparators(ns);
}
}
else
{
value.replace(pattern, pyhome, Qt::CaseInsensitive);
value=QDir::toNativeSeparators(value);
}
qputenv(vname, value.toLatin1().constData());
qDebug()<<"PYENV:"<<vname<<"="<<value;
}
};
static SandboxContext sbcx;
typedef const char* (*qgp_create_t)(unsigned int flags);
class SandboxInitializer
{
public:
bool success;
SandboxInitializer():
success(false)
{
success=init();
}
bool init()
{
if (!sbcx.enable)
return 0;
unsigned int flags=0;
QString pydll=sbcx.qglib_name;
pydll=pydll+sbcx.qglib_version+sbcx.qglib_dbg;
QLibrary pyl(pydll);
bool ok=pyl.load();
if (!ok)
{
QMessageBox::warning(0, "QgPython", QString("Load FAILED: %1").arg(pyl.errorString()));
qWarning()<<"QgPython:"<<"Load FAILED -"<<pyl.errorString();
sbcx.enable=false;
return false;
}
qDebug()<<"QgPython: loaded"<<pyl.fileName();
QgPythonLib_Initialize_function_t qgp_create=(qgp_create_t)pyl.resolve(QGPYTHON_LIB_INITIALIZE_FUNCTION_NAME); //"qgp_create");
if (!qgp_create)
{
QMessageBox::warning(0, "QgPython", QString("FAIL: Cannot resolve: %1").arg(pyl.errorString()));
qWarning()<<"QgPython:"<<"FAIL: Cannot resolve -"<<pyl.errorString();
sbcx.enable=false;
return false;
}
const char* msg=qgp_create(flags);
if (msg)
{
QMessageBox::warning(0, "QgPython", QString("FAIL: %1").arg(pyl.errorString()));
qWarning()<<"QgPython:"<<"FAIL:"<<pyl.errorString();
sbcx.enable=false;
return false;
}
sbcx.create_instance=(QgPythonLib_Instance_function_t)pyl.resolve(QGPYHON_LIB_INSTANCE_FUNCTION_NAME); //"qgp_instance");
if (!sbcx.create_instance)
{
QMessageBox::warning(0, "QgPython", QString("FAIL: Cannot resolve: %1").arg(pyl.errorString()));
qWarning()<<"QgPython:"<<"FAIL: Cannot resolve -"<<pyl.errorString();
sbcx.enable=false;
return false;
}
sbcx.pyif=sbcx.create_instance();
sbcx.appModule=sbcx.pyif->mainModule();
return true;
}
};
QgPythonSandbox::QgPythonSandbox(QObject *parent) : QObject(parent)
{
initialize();
}
void QgPythonSandbox::loadSettings(const QString &file)
{
QString iniFile=file.isEmpty() ? "./qgpy.ini" : file;
QSettings s(iniFile, QSettings::IniFormat);
s.beginGroup("qgpy");
if (s.value("enable").isValid())
{
bool enable=s.value("enable").toBool();
if (!enable)
{
sbcx.enable=false;
qDebug()<<"QgPy Setting: Python disabled";
}
}
qDebug()<<"QgPy Settings:"<<s.fileName();
QString tmp=s.value("pythonhome").toString(); //env "PYTHONHOME"
if (!tmp.isEmpty())
setPythonHome(tmp);
tmp=s.value("qgpydll").toString();
if (!tmp.isEmpty())
sbcx.qglib_name=tmp;
tmp=s.value("qgpyver").toString();
if (!tmp.isEmpty())
sbcx.qglib_version=tmp;
tmp=s.value("pythonlib").toString(); //env "PYTHONLIB"
if (!tmp.isEmpty())
setPythonLib(tmp);
tmp=s.value("path").toString(); //append to env "PATH"
if (!tmp.isEmpty())
addPythonPath(tmp);
tmp=s.value("pythonpath").toString(); //append to env "PATH"
if (!tmp.isEmpty())
{
sbcx.py_setenv("PYTHONPATH", tmp); //SandboxContext::setEnvPath("PYTHONPATH", tmp, false);
}
s.endGroup();
}
void QgPythonSandbox::setPythonVersion(const QString& v)
{
sbcx.qglib_version=v;
}
void QgPythonSandbox::setPythonDll(const QString &name)
{
sbcx.qglib_name=name;
}
void QgPythonSandbox::setPythonHome(const QString& home, bool precedence)
{
//SandboxContext::setEnvPath("PYTHONHOME", home, precedence);
//sbcx.pyhome=home;
sbcx.py_sethome(home);
}
void QgPythonSandbox::setPythonLib(const QString& home, bool precedence)
{
//SandboxContext::setEnvPath("PYTHONLIB", sbcx.expandPath(home), precedence);
sbcx.py_setenv("PYTHONLIB", home);
}
void QgPythonSandbox::addPythonPath(const QString& path)
{
if (path.isEmpty())
return;
auto e=qgetenv("PATH");
QString syspath=QString::fromLatin1(e.data());
syspath=path+";"+syspath;
sbcx.py_setenv("PATH", syspath);
#if 0
QString nativePath=QDir::toNativeSeparators(sbcx.expandPath(path));
syspath=nativePath+";"+syspath;
qputenv("PATH", syspath.toLatin1().constData());
qDebug()<<"PATH:"<<syspath;
#endif
}
void QgPythonSandbox::enable(bool ena)
{
sbcx.enable=ena;
}
bool QgPythonSandbox::isEnabled()
{
return sbcx.enable;
}
bool QgPythonSandbox::initialize()
{
static SandboxInitializer sbinit;
return sbinit.success;
}
QgPythonInterface* QgPythonSandbox::pythonInterface()
{
return sbcx.pyif;
}
QgPythonWidgets* QgPythonSandbox::pyhtonStdWidgets()
{
return sbcx.pyif->pythonWidgets();
}
QWidget* QgPythonSandbox::createConsoleWidget(QWidget* parent)
{
if (sbcx.consoleWidget)
return sbcx.consoleWidget;
if (!initialize())
return 0;
sbcx.consoleWidget=sbcx.pyif->pythonWidgets()->createConsole(parent); //create_console(parent);
return sbcx.consoleWidget;
}
QDialog* QgPythonSandbox::createEditDialog(QWidget* parent)
{
if (sbcx.editDialog)
return sbcx.editDialog;
if (!initialize())
return 0;
sbcx.editDialog=sbcx.pyif->pythonWidgets()->createEditDialog(parent); //create_console(parent);
return sbcx.editDialog;
}
void QgPythonSandbox::addObject(const QString& name, QObject* obj)
{
sbcx.pyif->addObject(name, obj, sbcx.appModule);
}
void QgPythonSandbox::addAppObject(const QString& name, QObject* obj)
{
sbcx.pyif->addObject(name, obj, sbcx.appModule);
}
//PythonQtObjectPtr QgPython::createMainApplicationModule(const QString& module_name)
bool QgPythonSandbox::createModule(const QString& module_name, const QString& file)
{
sbcx.pyif->createModuleFromFile(module_name, file);
return true;
}
bool QgPythonSandbox::createAppModule(const QString& module_name, const QString& file)
{
sbcx.appModule=sbcx.pyif->createModuleFromFile(module_name, file);
return true;
}
void QgPythonSandbox::evalScript(const QString& script)
{
sbcx.pyif->evalScript(script, 0);
}
void QgPythonSandbox::evalFile(const QString& file)
{
sbcx.pyif->evalFile(file, 0);
}