/**********************************************************************
PythonEngine - Engine for python scripts
Copyright (C) 2008,2009 Tim Vandermeersch
This file is part of the Avogadro molecular editor project.
For more information, see
Avogadro is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Avogadro is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
**********************************************************************/
#include "pythonengine.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace Eigen;
using namespace boost::python;
namespace Avogadro {
class PythonEnginePrivate
{
public:
PythonEnginePrivate() : script(0), settingsWidget(0)
{}
PythonInterpreter interpreter;
PythonScript *script;
boost::python::object instance;
QWidget *settingsWidget;
};
PythonEngine::PythonEngine(QObject *parent, const QString &filename) : Engine(parent), d(new PythonEnginePrivate)
{
setDescription(tr("Python script rendering")); // FIXME
loadScript(filename);
}
PythonEngine::~PythonEngine()
{
delete d;
}
Engine* PythonEngine::clone() const
{
PythonEngine* engine = new PythonEngine(parent());
engine->setAlias(alias());
engine->setEnabled(isEnabled());
return engine;
}
QString PythonEngine::identifier() const
{
if (!PyObject_HasAttrString(d->instance.ptr(), "identifier"))
return "Unknown Python Engine";
try {
prepareToCatchError();
const char *name = extract(d->instance.attr("identifier")());
return QString(name);
} catch(error_already_set const &) {
catchError();
return "Unknown Python Engine";
}
}
QString PythonEngine::name() const
{
if (!PyObject_HasAttrString(d->instance.ptr(), "name"))
return tr("Unknown Python Engine");
try {
prepareToCatchError();
const char *name = extract(d->instance.attr("name")());
return QString(name);
} catch(error_already_set const &) {
catchError();
return tr("Unknown Python Engine");
}
}
QString PythonEngine::description() const
{
if (!PyObject_HasAttrString(d->instance.ptr(), "description"))
return tr("N/A");
try {
prepareToCatchError();
const char *desc = extract(d->instance.attr("description")());
return QString(desc);
} catch(error_already_set const &) {
catchError();
return tr("N/A");
}
}
bool PythonEngine::renderOpaque(PainterDevice *pd)
{
if (!d->script)
return false; // nothing we can do
try {
prepareToCatchError();
boost::python::reference_existing_object::apply::type converter;
PyObject *obj = converter(pd);
object real_obj = object(handle<>(obj));
d->instance.attr("renderOpaque")(real_obj);
} catch(error_already_set const &) {
catchError();
}
return true;
}
QWidget* PythonEngine::settingsWidget()
{
if (!d->script)
return 0; // nothing we can do
if(!d->settingsWidget)
{
d->settingsWidget = new QWidget();
d->settingsWidget->setLayout( new QVBoxLayout() );
if (PyObject_HasAttrString(d->instance.ptr(), "settingsWidget")) {
try {
prepareToCatchError();
QWidget *widget = extract(d->instance.attr("settingsWidget")());
if (widget)
d->settingsWidget->layout()->addWidget(widget);
} catch (error_already_set const &) {
catchError();
}
}
connect(d->settingsWidget, SIGNAL(destroyed()), this, SLOT(settingsWidgetDestroyed()));
}
return d->settingsWidget;
}
void PythonEngine::settingsWidgetDestroyed()
{
d->settingsWidget = 0;
}
void PythonEngine::writeSettings(QSettings &settings) const
{
Engine::writeSettings(settings);
if (!d->script)
return;
if (!PyObject_HasAttrString(d->instance.ptr(), "readSettings"))
return;
try {
prepareToCatchError();
boost::python::return_by_value::apply::type qconverter;
PyObject *qobj = qconverter(&settings);
object real_qobj = object(handle<>(qobj));
d->instance.attr("readSettings")(real_qobj);
} catch(error_already_set const &) {
catchError();
}
}
void PythonEngine::readSettings(QSettings &settings)
{
Engine::readSettings(settings);
if (!d->script)
return;
if (!PyObject_HasAttrString(d->instance.ptr(), "writeSettings"))
return;
try {
prepareToCatchError();
boost::python::return_by_value::apply::type qconverter;
PyObject *qobj = qconverter(&settings);
object real_qobj = object(handle<>(qobj));
d->instance.attr("writeSettings")(real_qobj);
} catch(error_already_set const &) {
catchError();
}
}
void PythonEngine::loadScript(const QString &filename)
{
QFileInfo info(filename);
d->interpreter.addSearchPath(info.canonicalPath());
PythonScript *script = new PythonScript(filename);
if(script->module()) {
// make sure there is an Engine class defined
if (PyObject_HasAttrString(script->module().ptr(), "Engine")) {
try {
prepareToCatchError();
// instatiate the new Engine
d->instance = script->module().attr("Engine")();
} catch (error_already_set const &) {
catchError();
return;
}
d->script = script;
} else {
delete script;
pythonError()->append(tr("PythonEngine: checking ") + filename + "...");
pythonError()->append(tr(" - script has no 'Engine' class defined"));
}
} else {
delete script;
pythonError()->append(tr("PythonEngine: checking ") + filename + "...");
pythonError()->append(tr(" - no module"));
}
}
Engine::Layers PythonEngine::layers() const
{
if (!d->script)
return Engine::Opaque; // nothing we can do
try {
prepareToCatchError();
// return layers from python script if the function is defined
if (PyObject_HasAttrString(d->instance.ptr(), "layers"))
return extract(d->instance.attr("layers")());
} catch(error_already_set const &) {
catchError();
}
// return NoFlags, don't print an error, don't want to overwhelm new users with errors
return Engine::Opaque;
}
double PythonEngine::transparencyDepth() const
{
if (!d->script)
return 0.0; // nothing we can do
try {
prepareToCatchError();
// return transparencyDepth from python script if the function is defined
if (PyObject_HasAttrString(d->instance.ptr(), "transparencyDepth"))
return extract(d->instance.attr("transparencyDepth")());
} catch(error_already_set const &) {
catchError();
}
return 0.0;
}
}
#include "pythonengine.moc"