diff --git a/src/proxy/error.cpp b/src/proxy/error.cpp new file mode 100644 index 0000000..59d869d --- /dev/null +++ b/src/proxy/error.cpp @@ -0,0 +1,25 @@ +#include "utility.h" +#include +#include +#include + +using namespace MOBase; +namespace bpy = boost::python; + +void reportPythonError() +{ + if (PyErr_Occurred()) { + // prints to s_ErrIO buffer + PyErr_Print(); + // extract data from python buffer + bpy::object mainModule = bpy::import("__main__"); + bpy::object mainNamespace = mainModule.attr("__dict__"); + bpy::object errMsgObj = bpy::eval("s_ErrIO.getvalue()", mainNamespace); + QString errMsg = bpy::extract(errMsgObj.ptr()); + bpy::eval("s_ErrIO.truncate(0)", mainNamespace); + + throw MyException(errMsg); + } else { + throw MyException("An unexpected C++ exception was thrown in python code"); + } +} diff --git a/src/proxy/error.h b/src/proxy/error.h new file mode 100644 index 0000000..5d3d6ff --- /dev/null +++ b/src/proxy/error.h @@ -0,0 +1,7 @@ +#ifndef ERROR_H +#define ERROR_H + +// turn an error from the python interpreter into an exception +void reportPythonError(); + +#endif // ERROR_H diff --git a/src/proxy/gilock.cpp b/src/proxy/gilock.cpp new file mode 100644 index 0000000..ed5985c --- /dev/null +++ b/src/proxy/gilock.cpp @@ -0,0 +1,11 @@ +#include "gilock.h" + +GILock::GILock() +{ + m_State = PyGILState_Ensure(); +} + +GILock::~GILock() +{ + PyGILState_Release(m_State); +} diff --git a/src/proxy/gilock.h b/src/proxy/gilock.h new file mode 100644 index 0000000..560e29a --- /dev/null +++ b/src/proxy/gilock.h @@ -0,0 +1,18 @@ +#ifndef GILOCK_H +#define GILOCK_H + + +#ifndef Q_MOC_RUN +#include +#endif // Q_MOC_RUN + +class GILock { +public: + GILock(); + ~GILock(); +private: + PyGILState_STATE m_State; +}; + + +#endif // GILOCK_H diff --git a/src/proxy/proxyPython.pro b/src/proxy/proxyPython.pro index 32c6343..ec0a6da 100644 --- a/src/proxy/proxyPython.pro +++ b/src/proxy/proxyPython.pro @@ -17,11 +17,15 @@ INCLUDEPATH += "$(BOOSTPATH)" "$$(PYTHONPATH)/include" INCLUDEPATH += "$$(SIPPATH)/siplib" SOURCES += proxypython.cpp \ - proxypluginwrappers.cpp + proxypluginwrappers.cpp \ + error.cpp \ + gilock.cpp HEADERS += proxypython.h \ proxypluginwrappers.h \ - uibasewrappers.h + uibasewrappers.h \ + error.h \ + gilock.h LIBS += -L"$$(PYTHONPATH)/libs" -L"$(BOOSTPATH)/stage/lib" -lpython27 diff --git a/src/proxy/proxypluginwrappers.cpp b/src/proxy/proxypluginwrappers.cpp new file mode 100644 index 0000000..5848f13 --- /dev/null +++ b/src/proxy/proxypluginwrappers.cpp @@ -0,0 +1,223 @@ +#include "proxypluginwrappers.h" +#include +#include + +namespace bpy = boost::python; + +using namespace MOBase; + +static void reportPythonError() +{ + if (PyErr_Occurred()) { + // prints to s_ErrIO buffer + PyErr_Print(); + // extract data from python buffer + bpy::object mainModule = bpy::import("__main__"); + bpy::object mainNamespace = mainModule.attr("__dict__"); + bpy::object errMsgObj = bpy::eval("s_ErrIO.getvalue()", mainNamespace); + QString errMsg = bpy::extract(errMsgObj.ptr()); + bpy::eval("s_ErrIO.truncate(0)", mainNamespace); + throw MyException(errMsg); + } else { + throw MyException("An unexpected C++ exception was thrown in python code"); + } +} + +#define PYCATCH catch (const bpy::error_already_set &) { reportPythonError(); throw MyException("unhandled exception"); }\ + catch (...) { throw MyException("An unknown exception was thrown in python code"); } + + +///////////////////////////// +/// IPluginTool Wrapper + + +bool IPluginToolWrapper::init(MOBase::IOrganizer *moInfo) +{ + try { + return this->get_override("init")(bpy::ptr(moInfo)); + } PYCATCH; +} + +QString IPluginToolWrapper::name() const +{ + try { + return this->get_override("name")(); + } PYCATCH; +} + +QString IPluginToolWrapper::author() const +{ + try { + return this->get_override("author")(); + } PYCATCH; +} + +QString IPluginToolWrapper::description() const +{ + try { + return this->get_override("description")(); + } PYCATCH; +} + +MOBase::VersionInfo IPluginToolWrapper::version() const +{ + try { + return this->get_override("version")(); + } PYCATCH; +} + +bool IPluginToolWrapper::isActive() const +{ + try { + return this->get_override("isActive")(); + } PYCATCH; +} + +QList IPluginToolWrapper::settings() const +{ + try { + return this->get_override("settings")(); + } PYCATCH; +} + +QString IPluginToolWrapper::displayName() const +{ + try { + return this->get_override("displayName")(); + } PYCATCH; +} + +QString IPluginToolWrapper::tooltip() const +{ + try { + return this->get_override("tooltip")(); + } PYCATCH; +} + +QIcon IPluginToolWrapper::icon() const +{ + try { + return this->get_override("icon")(); + } PYCATCH; +} + +void IPluginToolWrapper::setParentWidget(QWidget *parent) +{ + try { + this->get_override("setParentWidget")(parent); + } PYCATCH; +} + +void IPluginToolWrapper::display() const +{ + try { + this->get_override("display")(); + } PYCATCH; +} + +/// end IPluginTool Wrapper +///////////////////////////////////// +/// IPluginInstallerCustom Wrapper + + +bool IPluginInstallerCustomWrapper::init(MOBase::IOrganizer *moInfo) +{ + try { + return this->get_override("init")(bpy::ptr(moInfo)); + } PYCATCH; +} + +QString IPluginInstallerCustomWrapper::name() const +{ + try { + return this->get_override("name")(); + } PYCATCH; +} + +QString IPluginInstallerCustomWrapper::author() const +{ + try { + return this->get_override("author")(); + } PYCATCH; +} + +QString IPluginInstallerCustomWrapper::description() const +{ + try { + return this->get_override("description")(); + } PYCATCH; +} + +MOBase::VersionInfo IPluginInstallerCustomWrapper::version() const +{ + try { + return this->get_override("version")(); + } PYCATCH; +} + +bool IPluginInstallerCustomWrapper::isActive() const +{ + try { + return this->get_override("isActive")(); + } PYCATCH; +} + +QList IPluginInstallerCustomWrapper::settings() const +{ + try { + return this->get_override("settings")(); + } PYCATCH; +} + +unsigned int IPluginInstallerCustomWrapper::priority() const +{ + try { + return this->get_override("priority")(); + } PYCATCH; +} + +bool IPluginInstallerCustomWrapper::isManualInstaller() const +{ + try { + return this->get_override("isManualInstaller")(); + } PYCATCH; +} + +bool IPluginInstallerCustomWrapper::isArchiveSupported(const DirectoryTree &tree) const +{ + try { + return this->get_override("isArchiveSupported")(tree); + } PYCATCH; +} + +bool IPluginInstallerCustomWrapper::isArchiveSupported(const QString &archiveName) const +{ + try { + return this->get_override("isArchiveSupported")(archiveName); + } PYCATCH; +} + +std::set IPluginInstallerCustomWrapper::supportedExtensions() const +{ + try { + return this->get_override("supportedExtensions")(); + } PYCATCH; +} + + +IPluginInstaller::EInstallResult IPluginInstallerCustomWrapper::install(GuessedValue &modName, const QString &archiveName) +{ + try { + return this->get_override("install")(modName, archiveName); + } PYCATCH; +} + + +void IPluginInstallerCustomWrapper::setParentWidget(QWidget *parent) +{ + try { + this->get_override("setParentWidget")(parent); + } PYCATCH; +} + + diff --git a/src/proxy/proxypluginwrappers.h b/src/proxy/proxypluginwrappers.h new file mode 100644 index 0000000..741feb4 --- /dev/null +++ b/src/proxy/proxypluginwrappers.h @@ -0,0 +1,79 @@ +#ifndef PROXYPLUGINWRAPPERS_H +#define PROXYPLUGINWRAPPERS_H + + +#include +#include +#include +#include + +#ifndef Q_MOC_RUN +#include +#endif + + +class IPluginWrapper : public boost::python::wrapper +{ +public: + virtual bool init(MOBase::IOrganizer *moInfo); + virtual QString name() const; + virtual QString author() const; + virtual QString description() const; + virtual MOBase::VersionInfo version() const; + virtual bool isActive() const; + virtual QList settings() const; +}; + + +class IPluginToolWrapper: public MOBase::IPluginTool, public boost::python::wrapper +{ + Q_OBJECT + Q_INTERFACES(MOBase::IPlugin MOBase::IPluginTool) + +public: + virtual bool init(MOBase::IOrganizer *moInfo); + virtual QString name() const; + virtual QString author() const; + virtual QString description() const; + virtual MOBase::VersionInfo version() const; + virtual bool isActive() const; + virtual QList settings() const; + + virtual QString displayName() const; + virtual QString tooltip() const; + virtual QIcon icon() const; + virtual void setParentWidget(QWidget *parent); + +public slots: + virtual void display() const; +}; + + +class IPluginInstallerCustomWrapper: public MOBase::IPluginInstallerCustom, public boost::python::wrapper +{ + Q_OBJECT + Q_INTERFACES(MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerCustom) + +public: + virtual bool init(MOBase::IOrganizer *moInfo); + virtual QString name() const; + virtual QString author() const; + virtual QString description() const; + virtual MOBase::VersionInfo version() const; + virtual bool isActive() const; + virtual QList settings() const; + + virtual unsigned int priority() const; + virtual bool isManualInstaller() const; + virtual bool isArchiveSupported(const MOBase::DirectoryTree &tree) const; + virtual bool isArchiveSupported(const QString &archiveName) const; + virtual std::set supportedExtensions() const; + virtual EInstallResult install(MOBase::GuessedValue &modName, const QString &archiveName); + virtual void setParentWidget(QWidget *parent); + +}; + + + + +#endif // PROXYPLUGINWRAPPERS_H diff --git a/src/proxy/proxypython.cpp b/src/proxy/proxypython.cpp index d7bf555..c909d84 100644 --- a/src/proxy/proxypython.cpp +++ b/src/proxy/proxypython.cpp @@ -14,6 +14,7 @@ #include #include "proxypluginwrappers.h" #include "uibasewrappers.h" +#include "error.h" // sip and qt slots seems to conflict #include @@ -23,27 +24,28 @@ using namespace MOBase; namespace bpy = boost::python; -static void reportPythonError() +MOBase::IOrganizer *s_Organizer = NULL; + + +struct ModRepositoryFileInfo_to_python_dict { - if (PyErr_Occurred()) { - // prints to s_ErrIO buffer - PyErr_Print(); - // extract data from python buffer - bpy::object mainModule = bpy::import("__main__"); - bpy::object mainNamespace = mainModule.attr("__dict__"); - bpy::object errMsgObj = bpy::eval("s_ErrIO.getvalue()", mainNamespace); - QString errMsg = bpy::extract(errMsgObj.ptr()); - bpy::eval("s_ErrIO.truncate(0)", mainNamespace); - throw MyException(errMsg); - } else { - throw MyException("An unexpected C++ exception was thrown in python code"); + static PyObject *convert(const ModRepositoryFileInfo &info) { + PyObject *res = PyDict_New(); + PyDict_SetItemString(res, "uri", bpy::incref(bpy::object(info.uri).ptr())); + PyDict_SetItemString(res, "name", bpy::incref(bpy::object(info.name).ptr())); + PyDict_SetItemString(res, "description", bpy::incref(bpy::object(info.description.toUtf8().constData()).ptr())); + PyDict_SetItemString(res, "categoryID", PyLong_FromLong(info.categoryID)); + PyDict_SetItemString(res, "fileID", PyLong_FromLong(info.fileID)); + PyDict_SetItemString(res, "fileSize", PyLong_FromLong(info.fileSize)); + PyDict_SetItemString(res, "version", bpy::incref(bpy::object(info.version).ptr())); + return bpy::incref(res); } -} +}; struct QString_to_python_str { - static PyObject *convert(QString const& str) { + static PyObject *convert(const QString &str) { return bpy::incref(bpy::object(str.toUtf8().constData()).ptr()); } }; @@ -226,13 +228,17 @@ struct QList_to_python_list { static PyObject *convert(const QList &list) { - qDebug("convert list"); + bpy::list pyList; - boost::python::list pyList; - foreach (const T &item, list) { - pyList.append(item); + try { + foreach (const T &item, list) { + pyList.append(item); + } + } catch (const bpy::error_already_set&) { + reportPythonError(); } - return bpy::incref(pyList.ptr()); + PyObject *res = bpy::incref(pyList.ptr()); + return res; } }; @@ -287,12 +293,8 @@ struct stdset_from_python_list bpy::list source(bpy::handle<>(bpy::borrowed(objPtr))); int length = bpy::len(source); - try { - for (int i = 0; i < length; ++i) { - result->insert(bpy::extract(source[i])); - } - } catch (const bpy::error_already_set&) { - qDebug("bla"); + for (int i = 0; i < length; ++i) { + result->insert(bpy::extract(source[i])); } data->convertible = storage; @@ -314,6 +316,7 @@ static const sipAPIDef *sipAPI() template struct MetaData; template <> struct MetaData { static const char *className() { return "MOBase::INexusBridge"; } }; +template <> struct MetaData { static const char *className() { return "QObject"; } }; template <> struct MetaData { static const char *className() { return "QObject"; } }; template <> struct MetaData { static const char *className() { return "QWidget"; } }; template <> struct MetaData { static const char *className() { return "QIcon"; } }; @@ -332,7 +335,7 @@ PyObject *toPyQt(T *objPtr) const sipTypeDef *type = sipAPI()->api_find_type(MetaData::className()); if (type == NULL) { - qDebug("failed to determine type"); + qDebug("failed to determine type: %s", MetaData::className()); return bpy::incref(Py_None); } @@ -478,6 +481,7 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(updateWithQuality, MOBase::GuessedValue(); QVariant_from_python_obj(); @@ -489,8 +493,10 @@ BOOST_PYTHON_MODULE(mobase) //QClass_converters(); QClass_converters(); QInterface_converters(); + QInterface_converters(); bpy::def("toPyQt", &toPyQt); + bpy::def("toPyQt", &toPyQt); bpy::enum_("ReleaseType") .value("final", MOBase::VersionInfo::RELEASE_FINAL) @@ -526,7 +532,7 @@ BOOST_PYTHON_MODULE(mobase) bpy::class_("IOrganizer") .def("gameInfo", bpy::pure_virtual(&MOBase::IOrganizer::gameInfo), bpy::return_value_policy()) - .def("createNexusBridge", bpy::pure_virtual(&MOBase::IOrganizer::createNexusBridge), bpy::return_value_policy()) + //.def("createNexusBridge", bpy::pure_virtual(&MOBase::IOrganizer::createNexusBridge), bpy::return_value_policy()) .def("profileName", bpy::pure_virtual(&MOBase::IOrganizer::profileName)) .def("profilePath", bpy::pure_virtual(&MOBase::IOrganizer::profilePath)) .def("downloadsPath", bpy::pure_virtual(&MOBase::IOrganizer::downloadsPath)) @@ -536,15 +542,23 @@ BOOST_PYTHON_MODULE(mobase) .def("removeMod", bpy::pure_virtual(&MOBase::IOrganizer::removeMod)) .def("modDataChanged", bpy::pure_virtual(&MOBase::IOrganizer::modDataChanged)) .def("pluginSetting", bpy::pure_virtual(&IOrganizer::pluginSetting)) - .def("pluginDataPath", bpy::pure_virtual(&IOrganizer::pluginDataPath)); + .def("pluginDataPath", bpy::pure_virtual(&IOrganizer::pluginDataPath)) + .def("installMod", bpy::pure_virtual(&IOrganizer::installMod)) + .def("downloadManager", bpy::pure_virtual(&IOrganizer::downloadManager), bpy::return_value_policy()); - bpy::class_("INexusBridge") - .def("requestDescription", bpy::pure_virtual(&MOBase::IModRepositoryBridge::requestDescription)) - .def("requestFiles", bpy::pure_virtual(&MOBase::IModRepositoryBridge::requestFiles)) - .def("requestFileInfo", bpy::pure_virtual(&MOBase::IModRepositoryBridge::requestFileInfo)) - .def("requestDownloadURL", bpy::pure_virtual(&MOBase::IModRepositoryBridge::requestDownloadURL)) - .def("requestToggleEndorsement", bpy::pure_virtual(&MOBase::IModRepositoryBridge::requestToggleEndorsement)) - ; + bpy::class_("ModRepositoryBridge") + .def("requestDescription", &ModRepositoryBridgeWrapper::requestDescription) + .def("requestFiles", &ModRepositoryBridgeWrapper::requestFiles) + .def("requestFileInfo", &ModRepositoryBridgeWrapper::requestFileInfo) + .def("requestDownloadURL", &ModRepositoryBridgeWrapper::requestDownloadURL) + .def("requestToggleEndorsement", &ModRepositoryBridgeWrapper::requestToggleEndorsement) + .def("onFilesAvailable", &ModRepositoryBridgeWrapper::onFilesAvailable) + .def("onRequestFailed", &ModRepositoryBridgeWrapper::onRequestFailed); + + bpy::class_("IDownloadManager") + .def("startDownloadURLs", bpy::pure_virtual(&IDownloadManager::startDownloadURLs)) + .def("startDownloadNexusFile", bpy::pure_virtual(&IDownloadManager::startDownloadNexusFile)) + .def("downloadPath", bpy::pure_virtual(&IDownloadManager::downloadPath)); bpy::enum_("GuessQuality") .value("invalid", MOBase::GUESS_INVALID) @@ -565,20 +579,20 @@ BOOST_PYTHON_MODULE(mobase) bpy::class_("IPluginInstallerCustom") .def("setParentWidget", bpy::pure_virtual(&MOBase::IPluginInstallerCustom::setParentWidget)); - bpy::class_("NexusFileInfo") +/* bpy::class_("ModRepositoryFileInfo") .def_readonly("name", &ModRepositoryFileInfo::name) - .def_readonly("uri", &ModRepositoryFileInfo::uri); -/* QString name; - QString uri; - VersionInfo version; - int categoryID; + .def_readonly("uri", &ModRepositoryFileInfo::uri) + .def_readonly("version", &ModRepositoryFileInfo::version) + .def_readonly("categoryID", &ModRepositoryFileInfo::categoryID); int fileID;*/ GuessedValue_converters(); + bpy::to_python_converter(); + QList_from_python_obj(); - bpy::to_python_converter, - QList_to_python_list >(); + bpy::to_python_converter, + QList_to_python_list >(); stdset_from_python_list(); } @@ -616,6 +630,7 @@ ProxyPython::ProxyPython() bool ProxyPython::init(IOrganizer *moInfo) { m_MOInfo = moInfo; + s_Organizer = moInfo; return true; } @@ -680,6 +695,7 @@ bool handled_exec_file(bpy::str filename, bpy::object globals = bpy::object(), b QObject *ProxyPython::instantiate(const QString &pluginName) { try { + GILock lock; bpy::object main_module = bpy::import("__main__"); bpy::object main_namespace = main_module.attr("__dict__"); diff --git a/src/proxy/uibasewrappers.h b/src/proxy/uibasewrappers.h index fa65530..636fd45 100644 --- a/src/proxy/uibasewrappers.h +++ b/src/proxy/uibasewrappers.h @@ -11,6 +11,103 @@ #include #include #include +#include "error.h" +#include "gilock.h" + + + +extern MOBase::IOrganizer *s_Organizer; + +using MOBase::ModRepositoryFileInfo; + +/** + * @brief Wrapper class for the bridge to a mod repository. Awkward: This may be + * unnecessary but I didn't manage to figure out how to correctly connect python + * code to C++ signals + */ +class ModRepositoryBridgeWrapper : public QObject +{ + Q_OBJECT +public: + + ModRepositoryBridgeWrapper() + : m_Wrapped(s_Organizer->createNexusBridge()) + { + } + + ModRepositoryBridgeWrapper(MOBase::IModRepositoryBridge *wrapped) + : m_Wrapped(wrapped) + { + } + + ~ModRepositoryBridgeWrapper() + { + delete m_Wrapped; + } + + void requestDescription(int modID, QVariant userData) + { m_Wrapped->requestDescription(modID, userData); } + void requestFiles(int modID, QVariant userData) + { m_Wrapped->requestFiles(modID, userData); } + void requestFileInfo(int modID, int fileID, QVariant userData) + { m_Wrapped->requestFileInfo(modID, fileID, userData); } + void requestDownloadURL(int modID, int fileID, QVariant userData) + { m_Wrapped->requestDownloadURL(modID, fileID, userData); } + void requestToggleEndorsement(int modID, bool endorse, QVariant userData) + { m_Wrapped->requestToggleEndorsement(modID, endorse, userData); } + + void onFilesAvailable(boost::python::object callback) { + m_FilesAvailableHandler = callback; + connect(m_Wrapped, SIGNAL(filesAvailable(int,QVariant,const QList&)), + this, SLOT(filesAvailable(int,QVariant,const QList&)), + Qt::UniqueConnection); + } + + void onRequestFailed(boost::python::object callback) { + m_FailedHandler = callback; + connect(m_Wrapped, SIGNAL(requestFailed(int,QVariant,QString)), + this, SLOT(requestFailed(int,QVariant,QString)), + Qt::UniqueConnection); + } + +private: + + Q_DISABLE_COPY(ModRepositoryBridgeWrapper) + +private slots: + + void filesAvailable(int modID, QVariant userData, const QList &resultData) + { + if (m_FilesAvailableHandler.is_none()) { + qCritical("no handler connected"); + return; + } +// try { + GILock lock; + m_FilesAvailableHandler(modID, userData, resultData); +// } catch (const boost::python::error_already_set&) { +// qDebug("error"); + //reportPythonError(); +// } + } + + void requestFailed(int modID, QVariant userData, const QString &errorMessage) + { + try { + GILock lock; + m_FailedHandler(modID, userData, errorMessage); + } catch (const boost::python::error_already_set&) { + reportPythonError(); + } + } + +private: + + MOBase::IModRepositoryBridge *m_Wrapped; + boost::python::object m_FilesAvailableHandler; + boost::python::object m_FailedHandler; + +}; struct IOrganizerWrapper: MOBase::IOrganizer, boost::python::wrapper @@ -20,8 +117,15 @@ struct IOrganizerWrapper: MOBase::IOrganizer, boost::python::wrapperget_override("createNexusBridge")(); +// return new INexusBridgeWrapper(temp); return this->get_override("createNexusBridge")(); } +/* + static ModRepositoryBridgeWrapper newNexusBridge(IOrganizerWrapper *self) { + return ModRepositoryBridgeWrapper(self->createNexusBridge()); + }*/ + virtual QString profileName() const { return this->get_override("profileName")(); } virtual QString profilePath() const { return this->get_override("profilePath")(); } virtual QString downloadsPath() const { return this->get_override("downloadsPath")(); } @@ -32,8 +136,18 @@ struct IOrganizerWrapper: MOBase::IOrganizer, boost::python::wrapperget_override("modDataChanged")(mod); } virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const { return this->get_override("pluginSetting")(pluginName, key); } virtual QString pluginDataPath() const { return this->get_override("pluginDataPath")(); } + virtual void installMod(const QString &fileName) { this->get_override("installMod")(fileName); } + virtual MOBase::IDownloadManager *downloadManager() { return this->get_override("downloadManager")(); } }; +struct IDownloadManagerWrapper: MOBase::IDownloadManager, boost::python::wrapper +{ + virtual int startDownloadURLs(const QStringList &urls) { return this->get_override("downloadURLs")(urls); } + virtual int startDownloadNexusFile(int modID, int fileID) { return this->get_override("downloadNexusFile")(modID, fileID); } + virtual QString downloadPath(int id) { return this->get_override("downloadPath")(id); } +private: + boost::python::object m_DownloadCompleteHandler; +}; struct IGameInfoWrapper: MOBase::IGameInfo, boost::python::wrapper { @@ -43,20 +157,4 @@ struct IGameInfoWrapper: MOBase::IGameInfo, boost::python::wrapper -{ - virtual void requestDescription(int modID, QVariant userData) - { this->get_override("requestDescription")(modID, userData); } - virtual void requestFiles(int modID, QVariant userData) - { this->get_override("requestFiles")(modID, userData); } - virtual void requestFileInfo(int modID, int fileID, QVariant userData) - { this->get_override("requestFileInfo")(modID, fileID, userData); } - virtual void requestDownloadURL(int modID, int fileID, QVariant userData) - { this->get_override("requestDownloadURL")(modID, fileID, userData); } - virtual void requestToggleEndorsement(int modID, bool endorse, QVariant userData) - { this->get_override("requestToggleEndorsement")(modID, endorse, userData); } - -}; - - #endif // UIBASEWRAPPERS_H