400 lines
9.5 KiB
C++
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);
|
|
}
|