mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
@@ -0,0 +1,494 @@
|
||||
#ifndef PYTHON_CONVERTERS_HPP
|
||||
#define PYTHON_CONVERTERS_HPP
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QWidget>
|
||||
|
||||
// sip and qt slots seems to conflict
|
||||
#include <sip.h>
|
||||
|
||||
// Include the container converters from utils:
|
||||
#include "pythonutils.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
namespace bpy = boost::python;
|
||||
|
||||
namespace QString_converter {
|
||||
|
||||
/**
|
||||
* We need this since sip does not expose QString but uses standard python str.
|
||||
*/
|
||||
struct QString_to_python_str
|
||||
{
|
||||
static PyObject* convert(const QString& str) {
|
||||
// It's safer to explicitly convert to unicode as if we don't, this can return
|
||||
// either str or unicode without it being easy to know which to expect
|
||||
bpy::object pyStr = bpy::object(qUtf8Printable(str));
|
||||
if (SIPBytes_Check(pyStr.ptr()))
|
||||
pyStr = pyStr.attr("decode")("utf-8");
|
||||
return bpy::incref(pyStr.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
struct QString_from_python_str
|
||||
{
|
||||
|
||||
static void* convertible(PyObject* objPtr) {
|
||||
return SIPBytes_Check(objPtr) || PyUnicode_Check(objPtr) ? objPtr : nullptr;
|
||||
}
|
||||
|
||||
static void construct(PyObject* objPtr, bpy::converter::rvalue_from_python_stage1_data* data) {
|
||||
// Ensure the string uses 8-bit characters
|
||||
PyObject* strPtr = PyUnicode_Check(objPtr) ? PyUnicode_AsUTF8String(objPtr) : objPtr;
|
||||
|
||||
// Extract the character data from the python string
|
||||
const char* value = SIPBytes_AsString(strPtr);
|
||||
assert(value != nullptr);
|
||||
|
||||
// allocate storage
|
||||
void* storage = ((bpy::converter::rvalue_from_python_storage<QString>*)data)->storage.bytes;
|
||||
|
||||
// construct QString in the allocated memory
|
||||
new (storage) QString(value);
|
||||
|
||||
data->convertible = storage;
|
||||
|
||||
// Deallocate local copy if one was made
|
||||
if (strPtr != objPtr)
|
||||
Py_DecRef(strPtr);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace QFlags_converter {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
struct QFlags_to_int
|
||||
{
|
||||
static PyObject* convert(const QFlags<T>& flags) {
|
||||
return bpy::incref(bpy::object(static_cast<int>(flags)).ptr());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QFlags_from_python_obj
|
||||
{
|
||||
|
||||
static void* convertible(PyObject* objPtr) {
|
||||
return SIPLong_Check(objPtr) ? objPtr : nullptr;
|
||||
}
|
||||
|
||||
static void construct(PyObject* objPtr, bpy::converter::rvalue_from_python_stage1_data* data) {
|
||||
int intVersion = (int)SIPLong_AsLong(objPtr);
|
||||
T tVersion = (T)intVersion;
|
||||
void* storage = ((bpy::converter::rvalue_from_python_storage<QFlags<T>>*)data)->storage.bytes;
|
||||
new (storage) QFlags<T>(tVersion);
|
||||
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace QVariant_converter {
|
||||
|
||||
struct QVariant_to_python_obj
|
||||
{
|
||||
static PyObject* convert(const QVariant& var) {
|
||||
switch (var.type()) {
|
||||
case QVariant::Invalid: return bpy::incref(Py_None);
|
||||
case QVariant::Int: return SIPLong_FromLong(var.toInt());
|
||||
case QVariant::UInt: return PyLong_FromUnsignedLong(var.toUInt());
|
||||
case QVariant::Bool: return PyBool_FromLong(var.toBool());
|
||||
case QVariant::String: return bpy::incref(bpy::object(var.toString()).ptr());
|
||||
// We need to check for StringList here because these are not considered List
|
||||
// since List is QList<QVariant> will StringList is QList<QString>:
|
||||
case QVariant::StringList: return bpy::incref(bpy::object(var.toStringList()).ptr());
|
||||
case QVariant::List: {
|
||||
return bpy::incref(bpy::object(var.toList()).ptr());
|
||||
} break;
|
||||
case QVariant::Map: {
|
||||
return bpy::incref(bpy::object(var.toMap()).ptr());
|
||||
} break;
|
||||
default: {
|
||||
PyErr_Format(PyExc_TypeError, "type unsupported: %d", var.type());
|
||||
throw bpy::error_already_set();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct QVariant_from_python_obj
|
||||
{
|
||||
|
||||
static void* convertible(PyObject* objPtr) {
|
||||
if (!SIPBytes_Check(objPtr) && !PyUnicode_Check(objPtr) && !PyLong_Check(objPtr) &&
|
||||
!PyBool_Check(objPtr) && !PyList_Check(objPtr) && !PyDict_Check(objPtr) &&
|
||||
objPtr != Py_None) {
|
||||
return nullptr;
|
||||
}
|
||||
return objPtr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void constructVariant(const T& value, bpy::converter::rvalue_from_python_stage1_data* data) {
|
||||
void* storage = ((bpy::converter::rvalue_from_python_storage<QVariant>*)data)->storage.bytes;
|
||||
|
||||
new (storage) QVariant(value);
|
||||
|
||||
data->convertible = storage;
|
||||
}
|
||||
|
||||
static void constructVariant(bpy::converter::rvalue_from_python_stage1_data* data) {
|
||||
void* storage = ((bpy::converter::rvalue_from_python_storage<QVariant>*)data)->storage.bytes;
|
||||
|
||||
new (storage) QVariant();
|
||||
|
||||
data->convertible = storage;
|
||||
}
|
||||
|
||||
static void construct(PyObject* objPtr, bpy::converter::rvalue_from_python_stage1_data* data) {
|
||||
if (PyList_Check(objPtr)) {
|
||||
// We could check if all the elements can be converted to QString and store a QStringList
|
||||
// in the QVariant but I am not sure that is really useful.
|
||||
constructVariant(bpy::extract<QVariantList>(objPtr)(), data);
|
||||
}
|
||||
else if (objPtr == Py_None) {
|
||||
constructVariant(data);
|
||||
}
|
||||
else if (PyDict_Check(objPtr)) {
|
||||
constructVariant(bpy::extract<QVariantMap>(objPtr)(), data);
|
||||
}
|
||||
else if (SIPBytes_Check(objPtr) || PyUnicode_Check(objPtr)) {
|
||||
constructVariant(bpy::extract<QString>(objPtr)(), data);
|
||||
}
|
||||
// PyBools will also return true for SIPLong_Check but not the other way around, so the order
|
||||
// here is relevant.
|
||||
else if (PyBool_Check(objPtr)) {
|
||||
constructVariant(bpy::extract<bool>(objPtr)(), data);
|
||||
}
|
||||
else if (SIPLong_Check(objPtr)) {
|
||||
// QVariant doesn't have long. It has int or long long. Given that on m/s,
|
||||
// long is 32 bits for 32- and 64- bit code...
|
||||
constructVariant(bpy::extract<int>(objPtr)(), data);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "type unsupported");
|
||||
throw bpy::error_already_set();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace QClass_converter {
|
||||
|
||||
template <typename T> struct MetaData;
|
||||
|
||||
template <> struct MetaData<QObject> { static const char* className() { return "QObject"; } };
|
||||
template <> struct MetaData<QWidget> { static const char* className() { return "QWidget"; } };
|
||||
template <> struct MetaData<QDateTime> { static const char* className() { return "QDateTime"; } };
|
||||
template <> struct MetaData<QDir> { static const char* className() { return "QDir"; } };
|
||||
template <> struct MetaData<QFileInfo> { static const char* className() { return "QFileInfo"; } };
|
||||
template <> struct MetaData<QIcon> { static const char* className() { return "QIcon"; } };
|
||||
template <> struct MetaData<QSize> { static const char* className() { return "QSize"; } };
|
||||
template <> struct MetaData<QStringList> { static const char* className() { return "QStringList"; } };
|
||||
template <> struct MetaData<QUrl> { static const char* className() { return "QUrl"; } };
|
||||
template <> struct MetaData<QVariant> { static const char* className() { return "QVariant"; } };
|
||||
|
||||
template <typename T>
|
||||
struct QClass_converters
|
||||
{
|
||||
struct QClass_to_PyQt
|
||||
{
|
||||
template <typename Q>
|
||||
static typename std::enable_if_t<std::is_copy_constructible_v<Q>, T*> getSafeCopy(T* qClass)
|
||||
{
|
||||
return new T(*qClass);
|
||||
}
|
||||
|
||||
template <typename Q>
|
||||
static typename std::enable_if_t<!std::is_copy_constructible_v<Q>, T*> getSafeCopy(T* qClass)
|
||||
{
|
||||
return qClass;
|
||||
}
|
||||
|
||||
static PyObject* convert(const T& object) {
|
||||
const sipTypeDef* type = sipAPIAccess::sipAPI()->api_find_type(MetaData<T>::className());
|
||||
if (type == nullptr) {
|
||||
return bpy::incref(Py_None);
|
||||
}
|
||||
|
||||
PyObject* sipObj = sipAPIAccess::sipAPI()->api_convert_from_type((void*)getSafeCopy<T>((T*)&object), type, 0);
|
||||
if (sipObj == nullptr) {
|
||||
return bpy::incref(Py_None);
|
||||
}
|
||||
|
||||
if (std::is_copy_constructible_v<T>)
|
||||
// Ensure Python deletes the C++ component
|
||||
sipAPIAccess::sipAPI()->api_transfer_back(sipObj);
|
||||
|
||||
return bpy::incref(sipObj);
|
||||
}
|
||||
|
||||
static PyObject* convert(T* object) {
|
||||
if (object == nullptr) {
|
||||
return bpy::incref(Py_None);
|
||||
}
|
||||
|
||||
const sipTypeDef* type = sipAPIAccess::sipAPI()->api_find_type(MetaData<T>::className());
|
||||
if (type == nullptr) {
|
||||
return bpy::incref(Py_None);
|
||||
}
|
||||
|
||||
PyObject* sipObj = sipAPIAccess::sipAPI()->api_convert_from_type(getSafeCopy<T>(object), type, 0);
|
||||
if (sipObj == nullptr) {
|
||||
return bpy::incref(Py_None);
|
||||
}
|
||||
|
||||
if (std::is_copy_constructible_v<T>)
|
||||
// Ensure Python deletes the C++ component
|
||||
sipAPIAccess::sipAPI()->api_transfer_back(sipObj);
|
||||
|
||||
return bpy::incref(sipObj);
|
||||
}
|
||||
|
||||
static PyObject* convert(const T* object) {
|
||||
return convert((T*)object);
|
||||
}
|
||||
|
||||
static PyTypeObject const* get_pytype() {
|
||||
const sipTypeDef* type = sipAPIAccess::sipAPI()->api_find_type(MetaData<T>::className());
|
||||
if (type == nullptr) {
|
||||
return bpy::incref(Py_None);
|
||||
}
|
||||
return bpy::incref(type->td_py_type);
|
||||
}
|
||||
};
|
||||
|
||||
static void* QClass_from_PyQt(PyObject* objPtr)
|
||||
{
|
||||
// This would transfer responsibility for deconstructing the object to C++, but Boost assumes l-value converters (such as this) don't do that
|
||||
// Instead, this should be called within the wrappers for functions which return deletable pointers.
|
||||
//sipAPI()->api_transfer_to(objPtr, Py_None);
|
||||
if (PyObject_TypeCheck(objPtr, sipAPIAccess::sipAPI()->api_simplewrapper_type)) {
|
||||
sipSimpleWrapper* wrapper;
|
||||
wrapper = reinterpret_cast<sipSimpleWrapper*>(objPtr);
|
||||
return wrapper->data;
|
||||
}
|
||||
else if (PyObject_TypeCheck(objPtr, sipAPIAccess::sipAPI()->api_wrapper_type)) {
|
||||
sipWrapper* wrapper;
|
||||
wrapper = reinterpret_cast<sipWrapper*>(objPtr);
|
||||
return wrapper->super.data;
|
||||
}
|
||||
else {
|
||||
if constexpr (std::is_same_v<T, QStringList>)
|
||||
{
|
||||
// QStringLists aren't wrapped by PyQt - regular Python string/unicode lists are used instead
|
||||
bpy::extract<QList<QString>> extractor(objPtr);
|
||||
if (extractor.check())
|
||||
return new QStringList(extractor());
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, "type not wrapped");
|
||||
bpy::throw_error_already_set();
|
||||
}
|
||||
return new void*;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool has_arity(PyObject* object, std::size_t arity) {
|
||||
// Mostly from https://stackoverflow.com/a/36143796/2666289
|
||||
bpy::object fn(bpy::handle<>(bpy::borrowed(object)));
|
||||
|
||||
auto inspect = bpy::import("inspect");
|
||||
auto arg_spec = inspect.attr("getfullargspec")(fn);
|
||||
bpy::object args = arg_spec.attr("args"),
|
||||
varargs = arg_spec.attr("varargs"),
|
||||
defaults = arg_spec.attr("defaults");
|
||||
|
||||
auto args_count = args ? bpy::len(args) : 0;
|
||||
auto defaults_count = defaults ? bpy::len(defaults) : 0;
|
||||
|
||||
if (static_cast<bool>(inspect.attr("ismethod")(fn)) && fn.attr("__self__")) {
|
||||
--args_count;
|
||||
}
|
||||
|
||||
auto required_count = args_count - defaults_count;
|
||||
|
||||
return required_count <= arity // Cannot require more parameters than given,
|
||||
&& (args_count >= arity || varargs); // Must accept enough parameters.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a python callable to a valid C++ Callable object. Also works
|
||||
* for None.
|
||||
*/
|
||||
template <typename>
|
||||
struct Functor_converter;
|
||||
|
||||
template <typename RET, typename... PARAMS>
|
||||
struct Functor_converter<RET(PARAMS...)>
|
||||
{
|
||||
|
||||
struct FunctorWrapper
|
||||
{
|
||||
FunctorWrapper(boost::python::object callable) : m_Callable(callable) {
|
||||
}
|
||||
|
||||
~FunctorWrapper() {
|
||||
GILock lock;
|
||||
m_Callable = bpy::object();
|
||||
}
|
||||
|
||||
RET operator()(const PARAMS&...params) {
|
||||
GILock lock;
|
||||
if constexpr (std::is_same_v<RET, void>) {
|
||||
m_Callable(params...);
|
||||
}
|
||||
else {
|
||||
return bpy::extract<RET>(m_Callable(params...));
|
||||
}
|
||||
}
|
||||
|
||||
boost::python::object m_Callable;
|
||||
};
|
||||
|
||||
static void* convertible(PyObject* object)
|
||||
{
|
||||
// We allow None here, we will just default-construct a std::function:
|
||||
if (object == Py_None) {
|
||||
return object;
|
||||
}
|
||||
|
||||
// Otherwize we check that we have a callable object:
|
||||
if (!PyCallable_Check(object) || !has_arity(object, sizeof...(PARAMS))) {
|
||||
return nullptr;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
static void construct(PyObject* object, bpy::converter::rvalue_from_python_stage1_data* data)
|
||||
{
|
||||
bpy::object callable(bpy::handle<>(bpy::borrowed(object)));
|
||||
void* storage =((bpy::converter::rvalue_from_python_storage<std::function<RET(PARAMS...)>>*)data)->storage.bytes;
|
||||
if (callable.is_none()) {
|
||||
new (storage) std::function<RET(PARAMS...)>{};
|
||||
}
|
||||
else {
|
||||
new (storage) std::function<RET(PARAMS...)>(FunctorWrapper(callable));
|
||||
}
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Call policy that automatically downcast shared pointer of type FromType
|
||||
* to shared pointer of type ToType.
|
||||
*/
|
||||
template <class FromType, class ToType>
|
||||
struct DowncastConverter {
|
||||
|
||||
bool convertible() const { return true; }
|
||||
|
||||
inline PyObject* operator()(std::shared_ptr<FromType> p) const {
|
||||
if (p == nullptr) {
|
||||
return bpy::detail::none();
|
||||
}
|
||||
else {
|
||||
auto downcast_p = std::dynamic_pointer_cast<ToType>(p);
|
||||
bpy::object p_value = downcast_p == nullptr ? bpy::object{ p } : bpy::object{ downcast_p };
|
||||
return bpy::incref(p_value.ptr());
|
||||
}
|
||||
}
|
||||
|
||||
inline PyTypeObject const* get_pytype() const {
|
||||
return bpy::converter::registered_pytype<FromType>::get_pytype();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class FromType, class ToType>
|
||||
struct downcast_return {
|
||||
|
||||
template <class T>
|
||||
struct apply_;
|
||||
|
||||
template <class T>
|
||||
struct apply_<std::shared_ptr<T>> {
|
||||
static_assert(std::is_convertible_v<std::shared_ptr<T>, std::shared_ptr<FromType>>);
|
||||
using type = DowncastConverter<FromType, ToType>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using apply = apply_<std::decay_t<T>>;
|
||||
|
||||
};
|
||||
|
||||
// Functions:
|
||||
inline void register_qstring_converter() {
|
||||
using namespace QString_converter;
|
||||
bpy::to_python_converter<QString, QString_to_python_str>();
|
||||
bpy::converter::registry::push_back(
|
||||
&QString_from_python_str::convertible,
|
||||
&QString_from_python_str::construct,
|
||||
bpy::type_id<QString>());
|
||||
}
|
||||
|
||||
inline void register_qvariant_converter() {
|
||||
using namespace QVariant_converter;
|
||||
bpy::to_python_converter<QVariant, QVariant_to_python_obj>();
|
||||
bpy::converter::registry::push_back(
|
||||
&QVariant_from_python_obj::convertible,
|
||||
&QVariant_from_python_obj::construct,
|
||||
bpy::type_id<QVariant>());
|
||||
}
|
||||
|
||||
template <class Flags>
|
||||
inline void register_qflags_converter() {
|
||||
using T = typename Flags::enum_type;
|
||||
using namespace QFlags_converter;
|
||||
bpy::to_python_converter<Flags, QFlags_to_int<T>>();
|
||||
bpy::converter::registry::push_back(
|
||||
&QFlags_from_python_obj<T>::convertible,
|
||||
&QFlags_from_python_obj<T>::construct,
|
||||
bpy::type_id<Flags>());
|
||||
}
|
||||
|
||||
template <class QClass>
|
||||
inline void register_qclass_converter() {
|
||||
using Converter = QClass_converter::QClass_converters<QClass>;
|
||||
bpy::converter::registry::insert(&Converter::QClass_from_PyQt, bpy::type_id<QClass>());
|
||||
bpy::to_python_converter<const QClass*, typename Converter::QClass_to_PyQt>();
|
||||
bpy::to_python_converter<QClass*, typename Converter::QClass_to_PyQt>();
|
||||
bpy::to_python_converter<QClass, typename Converter::QClass_to_PyQt>();
|
||||
}
|
||||
|
||||
template <class Fn>
|
||||
inline void register_functor_converter() {
|
||||
using Converter = Functor_converter<Fn>;
|
||||
bpy::converter::registry::push_back(
|
||||
&Converter::convertible,
|
||||
&Converter::construct,
|
||||
bpy::type_id<std::function<Fn>>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8,23 +8,6 @@
|
||||
using namespace MOBase;
|
||||
namespace bpy = boost::python;
|
||||
|
||||
void reportPythonError()
|
||||
{
|
||||
if (PyErr_Occurred()) {
|
||||
ErrWrapper &errWrapper = ErrWrapper::instance();
|
||||
|
||||
errWrapper.startRecordingExceptionMessage();
|
||||
PyErr_Print();
|
||||
errWrapper.stopRecordingExceptionMessage();
|
||||
|
||||
QString errMsg = errWrapper.getLastExceptionMessage();
|
||||
|
||||
throw MyException(errMsg);
|
||||
} else {
|
||||
throw MyException("An unexpected C++ exception was thrown in python code");
|
||||
}
|
||||
}
|
||||
|
||||
ErrWrapper & ErrWrapper::instance()
|
||||
{
|
||||
static ErrWrapper err;
|
||||
|
||||
+104
-7
@@ -1,16 +1,18 @@
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
#include <QString>
|
||||
#include <sstream>
|
||||
|
||||
// turn an error from the python interpreter into an exception
|
||||
void reportPythonError();
|
||||
#include <QString>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <utility.h>
|
||||
|
||||
struct ErrWrapper
|
||||
{
|
||||
static ErrWrapper & instance();
|
||||
|
||||
void write(const char * message);
|
||||
static ErrWrapper& instance();
|
||||
|
||||
void write(const char* message);
|
||||
|
||||
void startRecordingExceptionMessage();
|
||||
|
||||
@@ -23,4 +25,99 @@ struct ErrWrapper
|
||||
std::stringstream lastException;
|
||||
};
|
||||
|
||||
namespace pyexcept {
|
||||
|
||||
/**
|
||||
* @brief Exception to throw when a python implementation does not implement
|
||||
* a pure virtual function.
|
||||
*/
|
||||
class MissingImplementation : public MOBase::MyException {
|
||||
public:
|
||||
MissingImplementation(std::string const& className, std::string const& methodName) :
|
||||
MyException(QString::fromStdString(
|
||||
fmt::format("Python class implementing \"{}\" has no implementation of method \"{}\".",
|
||||
className, methodName))) { }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Exception to throw when a python error occurs.
|
||||
*/
|
||||
class PythonError : public MOBase::MyException {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create a new PythonError, fetching the error message from python. If the message
|
||||
* cannot be retrieved, `defaultErrorMessage()` is used instead.
|
||||
*/
|
||||
PythonError() : MyException(getPythonErrorMessage()) { }
|
||||
|
||||
/**
|
||||
* @brief Create a new PythonError with the given message.
|
||||
*
|
||||
* @param message Message for the exception.
|
||||
*/
|
||||
PythonError(QString message) : MyException(message) { }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static QString defaultErrorMessage() {
|
||||
return QObject::tr("An unexpected C++ exception was thrown in python code.");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static QString getPythonErrorMessage() {
|
||||
if (PyErr_Occurred()) {
|
||||
ErrWrapper& errWrapper = ErrWrapper::instance();
|
||||
|
||||
errWrapper.startRecordingExceptionMessage();
|
||||
PyErr_Print();
|
||||
errWrapper.stopRecordingExceptionMessage();
|
||||
|
||||
return errWrapper.getLastExceptionMessage();
|
||||
}
|
||||
else {
|
||||
return defaultErrorMessage();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Exception to throw when an unknown error occured. This is typically thrown
|
||||
* from a catch(...) block.
|
||||
*/
|
||||
class UnknownException : public MOBase::MyException {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Create a new UnknownException with the default message.
|
||||
*
|
||||
* @see defaultErrorMessage
|
||||
*/
|
||||
UnknownException() : MyException(defaultErrorMessage()) { }
|
||||
|
||||
/**
|
||||
* @brief Create a new UnknownException with the given message.
|
||||
*
|
||||
* @param message Message for the exception.
|
||||
*/
|
||||
UnknownException(QString message) : MyException(message) { }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static QString defaultErrorMessage() {
|
||||
return QObject::tr("An unknown exception was thrown in python code.");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ERROR_H
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <isavegame.h>
|
||||
#include <isavegameinfowidget.h>
|
||||
|
||||
#include "gilock.h"
|
||||
#include "pythonwrapperutilities.h"
|
||||
|
||||
/////////////////////////////
|
||||
@@ -18,22 +17,22 @@
|
||||
|
||||
bool BSAInvalidationWrapper::isInvalidationBSA(const QString &bsaName)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<BSAInvalidationWrapper, bool>(this, "isInvalidationBSA", bsaName);
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isInvalidationBSA", bsaName);
|
||||
}
|
||||
|
||||
void BSAInvalidationWrapper::deactivate(MOBase::IProfile *profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<BSAInvalidationWrapper, void>(this, "deactivate", boost::python::ptr(profile));
|
||||
return basicWrapperFunctionImplementation<void>(this, "deactivate", boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
void BSAInvalidationWrapper::activate(MOBase::IProfile *profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<BSAInvalidationWrapper, void>(this, "activate", boost::python::ptr(profile));
|
||||
return basicWrapperFunctionImplementation<void>(this, "activate", boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
bool BSAInvalidationWrapper::prepareProfile(MOBase::IProfile *profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<BSAInvalidationWrapper, bool>(this, "prepareProfile", boost::python::ptr(profile));
|
||||
return basicWrapperFunctionImplementation<bool>(this, "prepareProfile", boost::python::ptr(profile));
|
||||
}
|
||||
/// end BSAInvalidation Wrapper
|
||||
/////////////////////////////
|
||||
@@ -42,22 +41,22 @@ bool BSAInvalidationWrapper::prepareProfile(MOBase::IProfile *profile)
|
||||
|
||||
QStringList DataArchivesWrapper::vanillaArchives() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<DataArchivesWrapper, QStringList>(this, "vanillaArchives");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "vanillaArchives");
|
||||
}
|
||||
|
||||
QStringList DataArchivesWrapper::archives(const MOBase::IProfile *profile) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<DataArchivesWrapper, QStringList>(this, "archives", boost::python::ptr(profile));
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "archives", boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
void DataArchivesWrapper::addArchive(MOBase::IProfile *profile, int index, const QString &archiveName)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<DataArchivesWrapper, void>(this, "addArchive", boost::python::ptr(profile), index, archiveName);
|
||||
return basicWrapperFunctionImplementation<void>(this, "addArchive", boost::python::ptr(profile), index, archiveName);
|
||||
}
|
||||
|
||||
void DataArchivesWrapper::removeArchive(MOBase::IProfile *profile, const QString &archiveName)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<DataArchivesWrapper, void>(this, "removeArchive", boost::python::ptr(profile), archiveName);
|
||||
return basicWrapperFunctionImplementation<void>(this, "removeArchive", boost::python::ptr(profile), archiveName);
|
||||
}
|
||||
/// end DataArchives Wrapper
|
||||
/////////////////////////////
|
||||
@@ -66,22 +65,22 @@ void DataArchivesWrapper::removeArchive(MOBase::IProfile *profile, const QString
|
||||
|
||||
void GamePluginsWrapper::writePluginLists(const MOBase::IPluginList * pluginList)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<GamePluginsWrapper, void>(this, "writePluginLists", boost::python::ptr(pluginList));
|
||||
return basicWrapperFunctionImplementation<void>(this, "writePluginLists", boost::python::ptr(pluginList));
|
||||
}
|
||||
|
||||
void GamePluginsWrapper::readPluginLists(MOBase::IPluginList * pluginList)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<GamePluginsWrapper, void>(this, "readPluginLists", boost::python::ptr(pluginList));
|
||||
return basicWrapperFunctionImplementation<void>(this, "readPluginLists", boost::python::ptr(pluginList));
|
||||
}
|
||||
|
||||
void GamePluginsWrapper::getLoadOrder(QStringList &loadOrder)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<GamePluginsWrapper, void>(this, "getLoadOrder", loadOrder);
|
||||
return basicWrapperFunctionImplementation<void>(this, "getLoadOrder", loadOrder);
|
||||
}
|
||||
|
||||
bool GamePluginsWrapper::lightPluginsAreSupported()
|
||||
{
|
||||
return basicWrapperFunctionImplementation<GamePluginsWrapper, bool>(this, "lightPluginsAreSupported");
|
||||
return basicWrapperFunctionImplementation<bool>(this, "lightPluginsAreSupported");
|
||||
}
|
||||
|
||||
/// end GamePlugins Wrapper
|
||||
@@ -91,38 +90,45 @@ bool GamePluginsWrapper::lightPluginsAreSupported()
|
||||
|
||||
MappingType LocalSavegamesWrapper::mappings(const QDir & profileSaveDir) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<LocalSavegamesWrapper, MappingType>(this, "mappings", profileSaveDir);
|
||||
return basicWrapperFunctionImplementation<MappingType>(this, "mappings", profileSaveDir);
|
||||
}
|
||||
|
||||
bool LocalSavegamesWrapper::prepareProfile(MOBase::IProfile * profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<LocalSavegamesWrapper, bool>(this, "prepareProfile", boost::python::ptr(profile));
|
||||
return basicWrapperFunctionImplementation<bool>(this, "prepareProfile", boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
/// end LocalSavegames Wrapper
|
||||
/////////////////////////////
|
||||
/// ModDataChecker Wrapper
|
||||
|
||||
bool ModDataCheckerWrapper::dataLooksValid(std::shared_ptr<const MOBase::IFileTree> fileTree) const {
|
||||
return basicWrapperFunctionImplementation<bool>(this, "dataLooksValid", fileTree);
|
||||
}
|
||||
|
||||
/// end ModDataChecker Wrapper
|
||||
/////////////////////////////
|
||||
/// SaveGameInfo Wrapper
|
||||
|
||||
|
||||
MOBase::ISaveGame const * SaveGameInfoWrapper::getSaveGameInfo(QString const & file) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<SaveGameInfoWrapper, MOBase::ISaveGame const *>(this, "getSaveGameInfo", file);
|
||||
return basicWrapperFunctionImplementation<MOBase::ISaveGame*>(this, m_SaveGames[file], "getSaveGameInfo", file);
|
||||
}
|
||||
|
||||
SaveGameInfoWrapper::MissingAssets SaveGameInfoWrapper::getMissingAssets(QString const & file) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<SaveGameInfoWrapper, SaveGameInfoWrapper::MissingAssets>(this, "getMissingAssets", file);
|
||||
return basicWrapperFunctionImplementation<SaveGameInfoWrapper::MissingAssets>(this, "getMissingAssets", file);
|
||||
}
|
||||
|
||||
MOBase::ISaveGameInfoWidget * SaveGameInfoWrapper::getSaveGameWidget(QWidget * parent) const
|
||||
MOBase::ISaveGameInfoWidget* SaveGameInfoWrapper::getSaveGameWidget(QWidget* parent) const
|
||||
{
|
||||
qCritical("Calling method with unimplemented from_python converter.");
|
||||
return basicWrapperFunctionImplementation<SaveGameInfoWrapper, MOBase::ISaveGameInfoWidget *>(this, "getSaveGameWidget", boost::python::ptr(parent));
|
||||
return basicWrapperFunctionImplementation<MOBase::ISaveGameInfoWidget*>(this, m_SaveGameWidget, "getSaveGameWidget", parent);
|
||||
}
|
||||
|
||||
bool SaveGameInfoWrapper::hasScriptExtenderSave(QString const & file) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<SaveGameInfoWrapper, bool>(this, "hasScriptExtenderSave", file);
|
||||
return basicWrapperFunctionImplementation<bool>(this, "hasScriptExtenderSave", file);
|
||||
}
|
||||
/// end SaveGameInfo Wrapper
|
||||
/////////////////////////////
|
||||
@@ -130,42 +136,42 @@ bool SaveGameInfoWrapper::hasScriptExtenderSave(QString const & file) const
|
||||
|
||||
QString ScriptExtenderWrapper::BinaryName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, QString>(this, "BinaryName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "BinaryName");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::PluginPath() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, QString>(this, "PluginPath");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "PluginPath");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::loaderName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, QString>(this, "loaderName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "loaderName");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::loaderPath() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, QString>(this, "loaderPath");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "loaderPath");
|
||||
}
|
||||
|
||||
QStringList ScriptExtenderWrapper::saveGameAttachmentExtensions() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, QStringList>(this, "saveGameAttachmentExtensions");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "saveGameAttachmentExtensions");
|
||||
}
|
||||
|
||||
bool ScriptExtenderWrapper::isInstalled() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, bool>(this, "isInstalled");
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isInstalled");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::getExtenderVersion() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, QString>(this, "getExtenderVersion");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "getExtenderVersion");
|
||||
}
|
||||
|
||||
WORD ScriptExtenderWrapper::getArch() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<ScriptExtenderWrapper, WORD>(this, "getArch");
|
||||
return basicWrapperFunctionImplementation<WORD>(this, "getArch");
|
||||
}
|
||||
|
||||
/// end ScriptExtender Wrapper
|
||||
@@ -175,31 +181,26 @@ WORD ScriptExtenderWrapper::getArch() const
|
||||
|
||||
QStringList UnmanagedModsWrapper::mods(bool onlyOfficial) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<UnmanagedModsWrapper, QStringList>(this, "mods", onlyOfficial);
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "mods", onlyOfficial);
|
||||
}
|
||||
|
||||
QString UnmanagedModsWrapper::displayName(const QString & modName) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<UnmanagedModsWrapper, QString>(this, "displayName", modName);
|
||||
return basicWrapperFunctionImplementation<QString>(this, "displayName", modName);
|
||||
}
|
||||
|
||||
QFileInfo UnmanagedModsWrapper::referenceFile(const QString & modName) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<UnmanagedModsWrapper, QFileInfo>(this, "referenceFile", modName);
|
||||
return basicWrapperFunctionImplementation<QFileInfo>(this, "referenceFile", modName);
|
||||
}
|
||||
|
||||
QStringList UnmanagedModsWrapper::secondaryFiles(const QString & modName) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<UnmanagedModsWrapper, QStringList>(this, "secondaryFiles", modName);
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "secondaryFiles", modName);
|
||||
}
|
||||
/// end UnmanagedMods Wrapper
|
||||
/////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
void insertGameFeature(std::map<std::type_index, boost::any> &map, const boost::python::object &pyObject)
|
||||
{
|
||||
map[std::type_index(typeid(T))] = boost::python::extract<T*>(pyObject)();
|
||||
}
|
||||
|
||||
game_features_map_from_python::game_features_map_from_python()
|
||||
{
|
||||
@@ -211,6 +212,12 @@ void * game_features_map_from_python::convertible(PyObject * objPtr)
|
||||
return PyDict_Check(objPtr) ? objPtr : nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void insertGameFeature(std::map<std::type_index, boost::any>& map, const boost::python::object& pyObject)
|
||||
{
|
||||
map[std::type_index(typeid(T))] = boost::python::extract<T*>(pyObject)();
|
||||
}
|
||||
|
||||
void game_features_map_from_python::construct(PyObject * objPtr, boost::python::converter::rvalue_from_python_stage1_data * data)
|
||||
{
|
||||
void *storage = ((boost::python::converter::rvalue_from_python_storage<std::map<std::type_index, boost::any>>*)data)->storage.bytes;
|
||||
@@ -221,22 +228,18 @@ void game_features_map_from_python::construct(PyObject * objPtr, boost::python::
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
boost::python::object pyKey = keys[i];
|
||||
// pyKey should be a Boost.Python.class corresponding to a game feature.
|
||||
std::string className = boost::python::extract<std::string>(pyKey.attr("__name__"))();
|
||||
if (className == "BSAInvalidation")
|
||||
insertGameFeature<BSAInvalidation>(*result, source[pyKey]);
|
||||
else if (className == "DataArchives")
|
||||
insertGameFeature<DataArchives>(*result, source[pyKey]);
|
||||
else if (className == "GamePlugins")
|
||||
insertGameFeature<GamePlugins>(*result, source[pyKey]);
|
||||
else if (className == "LocalSavegames")
|
||||
insertGameFeature<LocalSavegames>(*result, source[pyKey]);
|
||||
else if (className == "SaveGameInfo")
|
||||
insertGameFeature<SaveGameInfo>(*result, source[pyKey]);
|
||||
else if (className == "ScriptExtender")
|
||||
insertGameFeature<ScriptExtender>(*result, source[pyKey]);
|
||||
else if (className == "UnmanagedMods")
|
||||
insertGameFeature<UnmanagedMods>(*result, source[pyKey]);
|
||||
boost::python::object pyValue = source[pyKey];
|
||||
|
||||
boost::mp11::mp_for_each<
|
||||
// Must user pointers because mp_for_each construct object:
|
||||
boost::mp11::mp_transform<std::add_pointer_t, MpGameFeaturesList>
|
||||
>([&](auto* pt) {
|
||||
using T = std::remove_pointer_t<decltype(pt)>;
|
||||
boost::python::extract<T*> extract(pyValue);
|
||||
if (extract.check()) {
|
||||
(*result)[std::type_index(typeid(T))] = extract();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
data->convertible = storage;
|
||||
@@ -274,10 +277,14 @@ void registerGameFeaturesPythonConverters()
|
||||
.def("prepareProfile", bpy::pure_virtual(&LocalSavegames::prepareProfile))
|
||||
;
|
||||
|
||||
bpy::class_<ModDataCheckerWrapper, boost::noncopyable>("ModDataChecker")
|
||||
.def("dataLooksValid", bpy::pure_virtual(&ModDataChecker::dataLooksValid))
|
||||
;
|
||||
|
||||
bpy::class_<SaveGameInfoWrapper, boost::noncopyable>("SaveGameInfo")
|
||||
.def("getSaveGameInfo", bpy::pure_virtual(&SaveGameInfo::getSaveGameInfo), bpy::return_value_policy<bpy::manage_new_object>())
|
||||
.def("getMissingAssets", bpy::pure_virtual(&SaveGameInfo::getMissingAssets))
|
||||
.def("getSaveGameWidget", bpy::pure_virtual(&SaveGameInfo::getSaveGameWidget), bpy::return_value_policy<bpy::manage_new_object>())
|
||||
.def("getSaveGameWidget", bpy::pure_virtual(&SaveGameInfo::getSaveGameWidget), bpy::return_value_policy<bpy::manage_new_object>(), "[optional]")
|
||||
.def("hasScriptExtenderSave", bpy::pure_virtual(&SaveGameInfo::hasScriptExtenderSave))
|
||||
;
|
||||
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
#ifndef GAMEFEATURESWRAPPERS_H
|
||||
#define GAMEFEATURESWRAPPERS_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <bsainvalidation.h>
|
||||
#include <dataarchives.h>
|
||||
#include <gameplugins.h>
|
||||
#include <localsavegames.h>
|
||||
#include <moddatachecker.h>
|
||||
#include <savegameinfo.h>
|
||||
#include <scriptextender.h>
|
||||
#include <unmanagedmods.h>
|
||||
|
||||
// this might need turning off if Q_MOC_RUN is defined
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
|
||||
// This is a simple MPL list that contains all the game features in one place:
|
||||
using MpGameFeaturesList = boost::mp11::mp_list<
|
||||
BSAInvalidation,
|
||||
DataArchives,
|
||||
GamePlugins,
|
||||
LocalSavegames,
|
||||
ModDataChecker,
|
||||
SaveGameInfo,
|
||||
ScriptExtender,
|
||||
UnmanagedMods
|
||||
>;
|
||||
|
||||
/////////////////////////////
|
||||
/// Wrapper declarations
|
||||
@@ -61,6 +77,15 @@ public:
|
||||
virtual bool prepareProfile(MOBase::IProfile *profile) override;
|
||||
};
|
||||
|
||||
class ModDataCheckerWrapper : public ModDataChecker, public boost::python::wrapper<ModDataChecker>
|
||||
{
|
||||
public:
|
||||
static constexpr const char* className = "ModDataCheckerWrapper";
|
||||
using boost::python::wrapper<ModDataChecker>::get_override;
|
||||
|
||||
virtual bool dataLooksValid(std::shared_ptr<const MOBase::IFileTree> fileTree) const;
|
||||
};
|
||||
|
||||
class SaveGameInfoWrapper : public SaveGameInfo, public boost::python::wrapper<SaveGameInfo>
|
||||
{
|
||||
public:
|
||||
@@ -71,6 +96,11 @@ public:
|
||||
virtual MissingAssets getMissingAssets(QString const &file) const override;
|
||||
virtual MOBase::ISaveGameInfoWidget *getSaveGameWidget(QWidget *parent = 0) const override;
|
||||
virtual bool hasScriptExtenderSave(QString const &file) const override;
|
||||
|
||||
private:
|
||||
// We need to keep the python objects alive:
|
||||
mutable std::map<QString, boost::python::object> m_SaveGames;
|
||||
mutable boost::python::object m_SaveGameWidget;
|
||||
};
|
||||
|
||||
class ScriptExtenderWrapper : public ScriptExtender, public boost::python::wrapper<ScriptExtender>
|
||||
|
||||
@@ -31,37 +31,37 @@ using namespace MOBase;
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(class_name) \
|
||||
bool class_name::init(MOBase::IOrganizer *moInfo) \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<class_name, bool>(this, "init", boost::python::ptr(moInfo)); \
|
||||
return basicWrapperFunctionImplementation<bool>(this, "init", boost::python::ptr(moInfo)); \
|
||||
} \
|
||||
\
|
||||
QString class_name::name() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<class_name, QString>(this, "name"); \
|
||||
return basicWrapperFunctionImplementation<QString>(this, "name"); \
|
||||
} \
|
||||
\
|
||||
QString class_name::author() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<class_name, QString>(this, "author"); \
|
||||
return basicWrapperFunctionImplementation<QString>(this, "author"); \
|
||||
} \
|
||||
\
|
||||
QString class_name::description() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<class_name, QString>(this, "description"); \
|
||||
return basicWrapperFunctionImplementation<QString>(this, "description"); \
|
||||
} \
|
||||
\
|
||||
MOBase::VersionInfo class_name::version() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<class_name, MOBase::VersionInfo>(this, "version"); \
|
||||
return basicWrapperFunctionImplementation<MOBase::VersionInfo>(this, "version"); \
|
||||
} \
|
||||
\
|
||||
bool class_name::isActive() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<class_name, bool>(this, "isActive"); \
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isActive"); \
|
||||
} \
|
||||
\
|
||||
QList<MOBase::PluginSetting> class_name::settings() const \
|
||||
{ \
|
||||
return basicWrapperFunctionImplementation<class_name, QList<MOBase::PluginSetting>>(this, "settings"); \
|
||||
return basicWrapperFunctionImplementation<QList<MOBase::PluginSetting>>(this, "settings"); \
|
||||
}
|
||||
|
||||
/// end COMMON_I_PLUGIN_WRAPPER_DEFINITIONS
|
||||
@@ -79,33 +79,29 @@ COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginDiagnoseWrapper)
|
||||
|
||||
std::vector<unsigned int> IPluginDiagnoseWrapper::activeProblems() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginDiagnoseWrapper, std::vector<unsigned int>>(this, "activeProblems");
|
||||
return basicWrapperFunctionImplementation<std::vector<unsigned int>>(this, "activeProblems");
|
||||
}
|
||||
|
||||
QString IPluginDiagnoseWrapper::shortDescription(unsigned int key) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginDiagnoseWrapper, QString>(this, "shortDescription", key);
|
||||
return basicWrapperFunctionImplementation<QString>(this, "shortDescription", key);
|
||||
}
|
||||
|
||||
QString IPluginDiagnoseWrapper::fullDescription(unsigned int key) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginDiagnoseWrapper, QString>(this, "fullDescription", key);
|
||||
return basicWrapperFunctionImplementation<QString>(this, "fullDescription", key);
|
||||
}
|
||||
|
||||
bool IPluginDiagnoseWrapper::hasGuidedFix(unsigned int key) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginDiagnoseWrapper, bool>(this, "hasGuidedFix", key);
|
||||
return basicWrapperFunctionImplementation<bool>(this, "hasGuidedFix", key);
|
||||
}
|
||||
|
||||
void IPluginDiagnoseWrapper::startGuidedFix(unsigned int key) const
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginDiagnoseWrapper, void>(this, "startGuidedFix", key);
|
||||
basicWrapperFunctionImplementation<void>(this, "startGuidedFix", key);
|
||||
}
|
||||
|
||||
void IPluginDiagnoseWrapper::invalidate()
|
||||
{
|
||||
IPluginDiagnose::invalidate();
|
||||
}
|
||||
/// end IPluginDiagnose Wrapper
|
||||
/////////////////////////////////////
|
||||
/// IPluginFileMapper Wrapper
|
||||
@@ -115,7 +111,7 @@ COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginFileMapperWrapper)
|
||||
|
||||
MappingType IPluginFileMapperWrapper::mappings() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginFileMapperWrapper, MappingType>(this, "mappings");
|
||||
return basicWrapperFunctionImplementation<MappingType>(this, "mappings");
|
||||
}
|
||||
/// end IPluginFileMapper Wrapper
|
||||
/////////////////////////////////////
|
||||
@@ -124,178 +120,178 @@ MappingType IPluginFileMapperWrapper::mappings() const
|
||||
|
||||
QString IPluginGameWrapper::gameName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "gameName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "gameName");
|
||||
}
|
||||
|
||||
void IPluginGameWrapper::initializeProfile(const QDir & directory, ProfileSettings settings) const
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginGameWrapper, void>(this, "initializeProfile", directory, settings);
|
||||
basicWrapperFunctionImplementation<void>(this, "initializeProfile", directory, settings);
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::savegameExtension() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "savegameExtension");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "savegameExtension");
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::savegameSEExtension() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "savegameSEExtension");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "savegameSEExtension");
|
||||
}
|
||||
|
||||
bool IPluginGameWrapper::isInstalled() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, bool>(this, "isInstalled");
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isInstalled");
|
||||
}
|
||||
|
||||
QIcon IPluginGameWrapper::gameIcon() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QIcon>(this, "gameIcon");
|
||||
return basicWrapperFunctionImplementation<QIcon>(this, "gameIcon");
|
||||
}
|
||||
|
||||
QDir IPluginGameWrapper::gameDirectory() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QDir>(this, "gameDirectory");
|
||||
return basicWrapperFunctionImplementation<QDir>(this, "gameDirectory");
|
||||
}
|
||||
|
||||
QDir IPluginGameWrapper::dataDirectory() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QDir>(this, "dataDirectory");
|
||||
return basicWrapperFunctionImplementation<QDir>(this, "dataDirectory");
|
||||
}
|
||||
|
||||
void IPluginGameWrapper::setGamePath(const QString & path)
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginGameWrapper, void>(this, "setGamePath", path);
|
||||
basicWrapperFunctionImplementation<void>(this, "setGamePath", path);
|
||||
}
|
||||
|
||||
QDir IPluginGameWrapper::documentsDirectory() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QDir>(this, "documentsDirectory");
|
||||
return basicWrapperFunctionImplementation<QDir>(this, "documentsDirectory");
|
||||
}
|
||||
|
||||
QDir IPluginGameWrapper::savesDirectory() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QDir>(this, "savesDirectory");
|
||||
return basicWrapperFunctionImplementation<QDir>(this, "savesDirectory");
|
||||
}
|
||||
|
||||
QList<MOBase::ExecutableInfo> IPluginGameWrapper::executables() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QList<MOBase::ExecutableInfo>>(this, "executables");
|
||||
return basicWrapperFunctionImplementation<QList<MOBase::ExecutableInfo>>(this, "executables");
|
||||
}
|
||||
|
||||
QList<MOBase::ExecutableForcedLoadSetting> IPluginGameWrapper::executableForcedLoads() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QList<MOBase::ExecutableForcedLoadSetting>>(this, "executableForcedLoads");
|
||||
return basicWrapperFunctionImplementation<QList<MOBase::ExecutableForcedLoadSetting>>(this, "executableForcedLoads");
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::steamAPPId() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "steamAPPId");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "steamAPPId");
|
||||
}
|
||||
|
||||
QStringList IPluginGameWrapper::primaryPlugins() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QStringList>(this, "primaryPlugins");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "primaryPlugins");
|
||||
}
|
||||
|
||||
QStringList IPluginGameWrapper::gameVariants() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QStringList>(this, "gameVariants");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "gameVariants");
|
||||
}
|
||||
|
||||
void IPluginGameWrapper::setGameVariant(const QString & variant)
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginGameWrapper, void>(this, "setGameVariant", variant);
|
||||
basicWrapperFunctionImplementation<void>(this, "setGameVariant", variant);
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::binaryName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "binaryName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "binaryName");
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::gameShortName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "gameShortName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "gameShortName");
|
||||
}
|
||||
|
||||
QStringList IPluginGameWrapper::primarySources() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QStringList>(this, "primarySources");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "primarySources");
|
||||
}
|
||||
|
||||
QStringList IPluginGameWrapper::validShortNames() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QStringList>(this, "validShortNames");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "validShortNames");
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::gameNexusName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "gameNexusName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "gameNexusName");
|
||||
}
|
||||
|
||||
QStringList IPluginGameWrapper::iniFiles() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QStringList>(this, "iniFiles");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "iniFiles");
|
||||
}
|
||||
|
||||
QStringList IPluginGameWrapper::DLCPlugins() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QStringList>(this, "DLCPlugins");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "DLCPlugins");
|
||||
}
|
||||
|
||||
QStringList IPluginGameWrapper::CCPlugins() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QStringList>(this, "CCPlugins");
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "CCPlugins");
|
||||
}
|
||||
|
||||
IPluginGame::LoadOrderMechanism IPluginGameWrapper::loadOrderMechanism() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, IPluginGame::LoadOrderMechanism>(this, "loadOrderMechanism");
|
||||
return basicWrapperFunctionImplementation<IPluginGame::LoadOrderMechanism>(this, "loadOrderMechanism");
|
||||
}
|
||||
|
||||
IPluginGame::SortMechanism IPluginGameWrapper::sortMechanism() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, IPluginGame::SortMechanism>(this, "sortMechanism");
|
||||
return basicWrapperFunctionImplementation<IPluginGame::SortMechanism>(this, "sortMechanism");
|
||||
}
|
||||
|
||||
int IPluginGameWrapper::nexusModOrganizerID() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, int>(this, "nexusModOrganizerID");
|
||||
return basicWrapperFunctionImplementation<int>(this, "nexusModOrganizerID");
|
||||
}
|
||||
|
||||
int IPluginGameWrapper::nexusGameID() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, int>(this, "nexusGameID");
|
||||
return basicWrapperFunctionImplementation<int>(this, "nexusGameID");
|
||||
}
|
||||
|
||||
bool IPluginGameWrapper::looksValid(QDir const & dir) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, bool>(this, "looksValid", dir);
|
||||
return basicWrapperFunctionImplementation<bool>(this, "looksValid", dir);
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::gameVersion() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "gameVersion");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "gameVersion");
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::getLauncherName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "getLauncherName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "getLauncherName");
|
||||
}
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginGameWrapper)
|
||||
|
||||
std::map<std::type_index, boost::any> IPluginGameWrapper::featureList() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, std::map<std::type_index, boost::any>>(this, "_featureList");
|
||||
return basicWrapperFunctionImplementation<std::map<std::type_index, boost::any>>(this, "_featureList");
|
||||
}
|
||||
/// end IPluginGame Wrapper
|
||||
/////////////////////////////////////
|
||||
/// IPluginInstaller macro
|
||||
|
||||
#define COMMON_I_PLUGIN_INSTALLER_WRAPPER_DEFINITIONS(class_name) \
|
||||
unsigned int class_name::priority() const { return basicWrapperFunctionImplementation<class_name, unsigned int>(this, "priority"); } \
|
||||
bool class_name::isManualInstaller() const { return basicWrapperFunctionImplementation<class_name, bool>(this, "isManualInstaller"); } \
|
||||
bool class_name::isArchiveSupported(std::shared_ptr<const IFileTree> tree) const { return basicWrapperFunctionImplementation<class_name, bool>(this, "isArchiveSupported", tree); }
|
||||
unsigned int class_name::priority() const { return basicWrapperFunctionImplementation<unsigned int>(this, "priority"); } \
|
||||
bool class_name::isManualInstaller() const { return basicWrapperFunctionImplementation<bool>(this, "isManualInstaller"); } \
|
||||
bool class_name::isArchiveSupported(std::shared_ptr<const IFileTree> tree) const { return basicWrapperFunctionImplementation<bool>(this, "isArchiveSupported", tree); }
|
||||
|
||||
/// end IPluginInstaller macro
|
||||
/////////////////////////////////////
|
||||
@@ -314,7 +310,7 @@ IPluginInstaller::EInstallResult IPluginInstallerSimpleWrapper::install(
|
||||
IPluginInstaller::EInstallResult,
|
||||
std::shared_ptr<IFileTree>,
|
||||
std::tuple<IPluginInstaller::EInstallResult, std::shared_ptr<IFileTree>, QString, int>> ;
|
||||
auto ret = basicWrapperFunctionImplementation<IPluginInstallerSimpleWrapper, return_type>(this, "install", boost::ref(modName), tree, version, nexusID);
|
||||
auto ret = basicWrapperFunctionImplementation<return_type>(this, "install", boost::ref(modName), tree, version, nexusID);
|
||||
|
||||
return std::visit([&](auto const& t) {
|
||||
using type = std::decay_t<decltype(t)>;
|
||||
@@ -342,12 +338,12 @@ COMMON_I_PLUGIN_INSTALLER_WRAPPER_DEFINITIONS(IPluginInstallerCustomWrapper)
|
||||
|
||||
bool IPluginInstallerCustomWrapper::isArchiveSupported(const QString &archiveName) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, bool>(this, "isArchiveSupported", archiveName);
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isArchiveSupported", archiveName);
|
||||
}
|
||||
|
||||
std::set<QString> IPluginInstallerCustomWrapper::supportedExtensions() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, std::set<QString>>(this, "supportedExtensions");
|
||||
return basicWrapperFunctionImplementation<std::set<QString>>(this, "supportedExtensions");
|
||||
}
|
||||
|
||||
IPluginInstaller::EInstallResult IPluginInstallerCustomWrapper::install(
|
||||
@@ -355,7 +351,7 @@ IPluginInstaller::EInstallResult IPluginInstallerCustomWrapper::install(
|
||||
{
|
||||
// Note: This requires far more less trouble than the "Simple" installer version since 1) there is no tree
|
||||
// and 2) there version and modId cannot be modified:
|
||||
return basicWrapperFunctionImplementation<IPluginInstallerCustomWrapper, IPluginInstaller::EInstallResult>(
|
||||
return basicWrapperFunctionImplementation<IPluginInstaller::EInstallResult>(
|
||||
this, "install", boost::ref(modName), gameName, archiveName, version, modID);
|
||||
}
|
||||
|
||||
@@ -368,32 +364,32 @@ COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginModPageWrapper)
|
||||
|
||||
QString IPluginModPageWrapper::displayName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginModPageWrapper, QString>(this, "displayName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "displayName");
|
||||
}
|
||||
|
||||
QIcon IPluginModPageWrapper::icon() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginModPageWrapper, QIcon>(this, "icon");
|
||||
return basicWrapperFunctionImplementation<QIcon>(this, "icon");
|
||||
}
|
||||
|
||||
QUrl IPluginModPageWrapper::pageURL() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginModPageWrapper, QUrl>(this, "pageURL");
|
||||
return basicWrapperFunctionImplementation<QUrl>(this, "pageURL");
|
||||
}
|
||||
|
||||
bool IPluginModPageWrapper::useIntegratedBrowser() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginModPageWrapper, bool>(this, "useIntegratedBrowser");
|
||||
return basicWrapperFunctionImplementation<bool>(this, "useIntegratedBrowser");
|
||||
}
|
||||
|
||||
bool IPluginModPageWrapper::handlesDownload(const QUrl & pageURL, const QUrl & downloadURL, MOBase::ModRepositoryFileInfo & fileInfo) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginModPageWrapper, bool>(this, "handlesDownload", pageURL, downloadURL, fileInfo);
|
||||
return basicWrapperFunctionImplementation<bool>(this, "handlesDownload", pageURL, downloadURL, fileInfo);
|
||||
}
|
||||
|
||||
void IPluginModPageWrapper::setParentWidget(QWidget * widget)
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginModPageWrapper, void>(this, "setParentWidget", widget);
|
||||
basicWrapperFunctionImplementationWithDefault<void>(this, &IPluginModPageWrapper::setParentWidget_Default, "setParentWidget", widget);
|
||||
}
|
||||
/// end IPluginModPage Wrapper
|
||||
/////////////////////////////
|
||||
@@ -404,7 +400,7 @@ COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginPreviewWrapper)
|
||||
|
||||
std::set<QString> IPluginPreviewWrapper::supportedExtensions() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginPreviewWrapper, std::set<QString>>(this, "supportedExtensions");
|
||||
return basicWrapperFunctionImplementation<std::set<QString>>(this, "supportedExtensions");
|
||||
}
|
||||
|
||||
QWidget *IPluginPreviewWrapper::genFilePreview(const QString &fileName, const QSize &maxSize) const
|
||||
@@ -414,12 +410,21 @@ QWidget *IPluginPreviewWrapper::genFilePreview(const QString &fileName, const QS
|
||||
GILock lock;
|
||||
boost::python::override implementation = this->get_override("genFilePreview");
|
||||
if (!implementation)
|
||||
throw MissingImplementation(this->className, "genFilePreview");
|
||||
throw pyexcept::MissingImplementation(this->className, "genFilePreview");
|
||||
boost::python::object pyVersion = implementation(fileName, maxSize);
|
||||
// We need responsibility for deleting the QWidget to be transferred to C++
|
||||
sipAPIAccess::sipAPI()->api_transfer_to(pyVersion.ptr(), Py_None);
|
||||
return boost::python::extract<QWidget *>(pyVersion)();
|
||||
} PYCATCH;
|
||||
}
|
||||
catch (const boost::python::error_already_set&) {
|
||||
throw pyexcept::PythonError();
|
||||
}
|
||||
catch (pyexcept::MissingImplementation const& missingImplementation) {
|
||||
throw missingImplementation;
|
||||
}
|
||||
catch (...) {
|
||||
throw pyexcept::UnknownException();
|
||||
}
|
||||
}
|
||||
/// end IPluginPreview Wrapper
|
||||
/////////////////////////////
|
||||
@@ -430,27 +435,27 @@ COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginToolWrapper)
|
||||
|
||||
QString IPluginToolWrapper::displayName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginToolWrapper, QString>(this, "displayName");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "displayName");
|
||||
}
|
||||
|
||||
QString IPluginToolWrapper::tooltip() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginToolWrapper, QString>(this, "tooltip");
|
||||
return basicWrapperFunctionImplementation<QString>(this, "tooltip");
|
||||
}
|
||||
|
||||
QIcon IPluginToolWrapper::icon() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginToolWrapper, QIcon>(this, "icon");
|
||||
return basicWrapperFunctionImplementation<QIcon>(this, "icon");
|
||||
}
|
||||
|
||||
void IPluginToolWrapper::setParentWidget(QWidget *parent)
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginToolWrapper, void>(this, "setParentWidget", parent);
|
||||
basicWrapperFunctionImplementationWithDefault<void>(this, &IPluginToolWrapper::setParentWidget_Default, "setParentWidget", parent);
|
||||
}
|
||||
|
||||
void IPluginToolWrapper::display() const
|
||||
{
|
||||
basicWrapperFunctionImplementation<IPluginToolWrapper, void>(this, "display");
|
||||
basicWrapperFunctionImplementation<void>(this, "display");
|
||||
}
|
||||
|
||||
/// end IPluginTool Wrapper
|
||||
|
||||
@@ -51,14 +51,14 @@ public:
|
||||
static constexpr const char* className = "IPluginDiagnoseWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginDiagnose>::get_override;
|
||||
|
||||
// Bring in public scope:
|
||||
using IPluginDiagnose::invalidate;
|
||||
|
||||
virtual std::vector<unsigned int> activeProblems() const override;
|
||||
virtual QString shortDescription(unsigned int key) const override;
|
||||
virtual QString fullDescription(unsigned int key) const override;
|
||||
virtual bool hasGuidedFix(unsigned int key) const override;
|
||||
virtual void startGuidedFix(unsigned int key) const override;
|
||||
// Other functions exist, but shouldn't need wrapping as a default implementation exists
|
||||
// This was protected, but Python doesn't have that, so it needs making public
|
||||
virtual void invalidate();
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
};
|
||||
@@ -186,12 +186,19 @@ public:
|
||||
static constexpr const char* className = "IPluginModPageWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginModPage>::get_override;
|
||||
|
||||
// Bring in public scope:
|
||||
using IPluginModPage::parentWidget;
|
||||
|
||||
virtual QString displayName() const override;
|
||||
virtual QIcon icon() const override;
|
||||
virtual QUrl pageURL() const override;
|
||||
virtual bool useIntegratedBrowser() const override;
|
||||
virtual bool handlesDownload(const QUrl &pageURL, const QUrl &downloadURL, MOBase::ModRepositoryFileInfo &fileInfo) const override;
|
||||
virtual void setParentWidget(QWidget *widget) override;
|
||||
|
||||
void setParentWidget_Default(QWidget* parent) {
|
||||
IPluginModPage::setParentWidget(parent);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -220,13 +227,20 @@ public:
|
||||
static constexpr const char* className = "IPluginToolWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginTool>::get_override;
|
||||
|
||||
virtual QString displayName() const;
|
||||
virtual QString tooltip() const;
|
||||
virtual QIcon icon() const;
|
||||
virtual void setParentWidget(QWidget *parent);
|
||||
// Bring in public scope:
|
||||
using IPluginTool::parentWidget;
|
||||
|
||||
virtual QString displayName() const override;
|
||||
virtual QString tooltip() const override;
|
||||
virtual QIcon icon() const override;
|
||||
virtual void setParentWidget(QWidget *parent) override;
|
||||
|
||||
void setParentWidget_Default(QWidget* parent) {
|
||||
IPluginTool::setParentWidget(parent);
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void display() const;
|
||||
virtual void display() const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+528
-828
File diff suppressed because it is too large
Load Diff
@@ -70,11 +70,12 @@ namespace utils {
|
||||
bpy::list pyList;
|
||||
|
||||
try {
|
||||
for (auto& item : container)
|
||||
for (auto& item : container) {
|
||||
pyList.append(item);
|
||||
}
|
||||
}
|
||||
catch (const bpy::error_already_set&) {
|
||||
reportPythonError();
|
||||
throw pyexcept::PythonError();
|
||||
}
|
||||
|
||||
return bpy::incref(pyList.ptr());
|
||||
@@ -115,7 +116,7 @@ namespace utils {
|
||||
pyList.append(item);
|
||||
}
|
||||
catch (const bpy::error_already_set&) {
|
||||
reportPythonError();
|
||||
throw pyexcept::PythonError();
|
||||
}
|
||||
|
||||
return bpy::incref(pyList.ptr());
|
||||
|
||||
@@ -1,32 +1,116 @@
|
||||
#ifndef PYTHONWRAPPERUTILITIES_H
|
||||
#define PYTHONWRAPPERUTILITIES_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
#include <log.h>
|
||||
#include <utility.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "gilock.h"
|
||||
|
||||
class MissingImplementation : public MOBase::MyException {
|
||||
public:
|
||||
MissingImplementation(QString className, QString methodName) : MyException("Python class implementing \"" +
|
||||
className +
|
||||
"\" has no implementation of method \"" +
|
||||
methodName + "\"") {}
|
||||
};
|
||||
namespace details {
|
||||
|
||||
#define PYCATCH catch (const boost::python::error_already_set &) { reportPythonError(); throw MOBase::MyException("unhandled exception"); }\
|
||||
catch (const MissingImplementation &missingImplementationException) { throw missingImplementationException; }\
|
||||
catch (...) { throw MOBase::MyException("An unknown exception was thrown in python code"); }
|
||||
|
||||
template <typename WrapperType, typename ReturnType, typename... Args>
|
||||
ReturnType basicWrapperFunctionImplementation(const WrapperType *wrapper, const char *methodName, Args... args)
|
||||
{
|
||||
try {
|
||||
/**
|
||||
* @brief Common stuffs for all basicWrapperFunction methods.
|
||||
*/
|
||||
template <class ReturnType, class WrapperTypePtr, class Fn, class... Args>
|
||||
ReturnType wrapperFunctionImplementation(WrapperTypePtr wrapper, Fn fn, boost::python::object* objPtr, const char *methodName, Args... args) {
|
||||
GILock lock;
|
||||
boost::python::override implementation = wrapper->get_override(methodName);
|
||||
if (!implementation)
|
||||
throw MissingImplementation(wrapper->className, methodName);
|
||||
return implementation(args...).as<ReturnType>();
|
||||
} PYCATCH;
|
||||
if (!implementation) {
|
||||
if constexpr (std::is_same_v<Fn, std::nullptr_t>) {
|
||||
throw pyexcept::MissingImplementation(wrapper->className, methodName);
|
||||
}
|
||||
else {
|
||||
return std::invoke(fn, wrapper, args...);
|
||||
}
|
||||
}
|
||||
try {
|
||||
boost::python::object result = implementation(args...);
|
||||
if (objPtr) {
|
||||
*objPtr = result;
|
||||
}
|
||||
if constexpr (!std::is_same_v<ReturnType, void>) {
|
||||
return boost::python::extract<ReturnType>(result)();
|
||||
}
|
||||
}
|
||||
catch (const boost::python::error_already_set&) {
|
||||
throw pyexcept::PythonError();
|
||||
}
|
||||
catch (...) {
|
||||
throw pyexcept::UnknownException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with proper
|
||||
* exception handling.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
||||
* available `className` attribute.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::MissingImplementation if the method does not exist.
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperType, class... Args>
|
||||
ReturnType basicWrapperFunctionImplementation(const WrapperType *wrapper, const char *methodName, Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(wrapper, nullptr, nullptr, methodName, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with proper
|
||||
* exception handling, and store the intermediate result in the given python object.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
||||
* available `className` attribute.
|
||||
* @param ref Python object to which the result of `get_override()` should be stored.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::MissingImplementation if the method does not exist.
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperType, class... Args>
|
||||
ReturnType basicWrapperFunctionImplementation(const WrapperType* wrapper, boost::python::object &ref, const char* methodName, Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(wrapper, nullptr, &ref, methodName, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with proper
|
||||
* exception handling, falling back to the given function if the method does not exist.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must have a publicly
|
||||
* available `className` attribute.
|
||||
* @param fn The function to call if the method does not exists.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* Note: `fn` does not have to be a member-function of `wrapper` but `std::invoke(fn, wrapper, args...)` must be valid.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperTypePtr, class Fn, class... Args>
|
||||
ReturnType basicWrapperFunctionImplementationWithDefault(WrapperTypePtr wrapper, Fn fn, const char* methodName, Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(wrapper, fn, nullptr, methodName, args...);
|
||||
}
|
||||
|
||||
#endif // PYTHONWRAPPERUTILITIES_H
|
||||
|
||||
+18
-468
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user