Compare commits

...
Author SHA1 Message Date
Tannin f56c605479 - bugfix: endless loop in detection of mod order problems 2014-05-04 16:13:35 +02:00
Tannin 617c76e9f8 - main window now has a small view displaying log messages
- mod list will now be highlighted when grouping is active is active
- download tooltip now supports bbcode markup in the description
- bbcode translator will now translate some named colors
- algorithm for detection of mod order problems is now more sophisticated
- exposed more functionality to python plugins
- updated to qt 4.8.6 dlls
- bugfix: plugin list wasn't
- bugfix: state changes in mod list wasn't always reported
- bugfix: loot client will now create necessary directory
- bugfix: NCC sometimes used wrong source path for extracting
- bugfix: removed noisy debug message
2014-05-04 14:50:01 +02:00
Tannin 96081888f1 Merge with branch1.1 2014-04-05 15:36:42 +02:00
Tannin af5958b0af some fixes towards qt5 compatibility 2014-03-16 20:04:57 +01:00
Tannin b33293e49a - bugfix: elevation dialog didn't offer a "yes" option
- bugfix: python plugins crashed the application when trying to create a nexus bridge
- bugfix: python plugins couldn't register for failed requests correctly
2014-01-29 21:06:55 +01:00
Tannin dc3b60e578 - bugfix: accessing profile without loading one when starting an app through the commandline
- bugfix: locked-dialog was disabled
2014-01-27 21:31:10 +01:00
Tannin d591bc017a Merge with default 2013-12-07 16:55:19 +01:00
Tannin aad5864192 minor text changes 2013-12-07 14:23:51 +01:00
Tannin fee774db45 - added support for mod page plugins
- re-introduced the integrated browser
- added a plugin to download from the tes alliance page
- the download list now contains the file description
- nexus interface now stores cookies persistently to reduce number of required log-ins
2013-09-15 15:20:00 +02:00
8 changed files with 232 additions and 29 deletions
+2 -2
View File
@@ -178,7 +178,7 @@ QString ProxyPython::description() const
VersionInfo ProxyPython::version() const
{
return VersionInfo(1, 2, 0, VersionInfo::RELEASE_FINAL);
return VersionInfo(1, 3, 0, VersionInfo::RELEASE_FINAL);
}
bool ProxyPython::isActive() const
@@ -305,7 +305,7 @@ QString ProxyPython::fullDescription(unsigned int key) const
"The only solution I can offer is to remove the semicolon / move MO to a path without a semicolon.").arg(QCoreApplication::applicationDirPath());
} break;
default:
throw MyException(tr("invalid problem key %1").arg(key));
throw MyException(QString("invalid problem key %1").arg(key));
}
}
-1
View File
@@ -1,5 +1,4 @@
#include "proxypluginwrappers.h"
#include <boost/python.hpp>
#include <utility.h>
#include "error.h"
#include "gilock.h"
+9
View File
@@ -31,17 +31,26 @@ HEADERS += pythonrunner.h \
CONFIG(debug, debug|release) {
SRCDIR = $$OUT_PWD/debug
DSTDIR = $$PWD/../../outputd
LIBS += -L$$OUT_PWD/../uibase/debug
} else {
SRCDIR = $$OUT_PWD/release
DSTDIR = $$PWD/../../output
LIBS += -L$$OUT_PWD/../uibase/release
QMAKE_CXXFLAGS += /Zi
QMAKE_LFLAGS += /DEBUG
}
SRCDIR ~= s,/,$$QMAKE_DIR_SEP,g
DSTDIR ~= s,/,$$QMAKE_DIR_SEP,g
INCLUDEPATH += "$(BOOSTPATH)" "$$(PYTHONPATH)/include" "$$(PYTHONPATH)/Lib/site-packages/PyQt4/include"
LIBS += -L"$$(PYTHONPATH)/libs" -L"$(BOOSTPATH)/stage/lib"
LIBS += -lpython27
INCLUDEPATH += ../uibase
LIBS += -luibase
QMAKE_POST_LINK += xcopy /y /I $$quote($$SRCDIR\\$${TARGET}*.pdb) $$quote($$DSTDIR)\\plugins $$escape_expand(\\n)
-1
View File
@@ -99,7 +99,6 @@ QList<MOBase::PluginSetting> PythonPluginWrapper::settings() const
try {
boost::python::object l = m_SettingsFunction();
if (!l.is_none()) {
// boost::python::list l = extract<boost::python::list>(temp);
for (int i = 0; i < boost::python::len(l); ++i) {
result.append(extract<MOBase::PluginSetting>(l[i]));
}
+1
View File
@@ -27,6 +27,7 @@ public:
virtual QList<MOBase::PluginSetting> settings() const;
protected:
void reportPythonError() const;
private:
+169 -15
View File
@@ -46,8 +46,9 @@ private:
};
IPythonRunner *CreatePythonRunner(const MOBase::IOrganizer *moInfo, const QString &pythonDir)
IPythonRunner *CreatePythonRunner(MOBase::IOrganizer *moInfo, const QString &pythonDir)
{
s_Organizer = moInfo;
PythonRunner *result = new PythonRunner(moInfo);
if (result->initPython(pythonDir)) {
return result;
@@ -85,6 +86,15 @@ struct QString_to_python_str
}
};
template <typename T>
struct QFlags_to_int
{
static PyObject *convert(const QFlags<T> &flags) {
return bpy::incref(bpy::object(static_cast<int>(flags)).ptr());
}
};
struct QString_from_python_str
{
QString_from_python_str() {
@@ -110,7 +120,6 @@ struct QString_from_python_str
};
template <typename T>
struct GuessedValue_converters
{
@@ -140,7 +149,6 @@ struct GuessedValue_converters
}
}
static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data* data) {
void *storage = ((bpy::converter::rvalue_from_python_storage<GuessedValue<T> >*)data)->storage.bytes;
GuessedValue<T> *result = new (storage) GuessedValue<T>();
@@ -257,6 +265,7 @@ struct QVariant_from_python_obj
}
};
template <typename T>
struct QList_to_python_list
{
@@ -380,6 +389,7 @@ PyObject *toPyQt(T *objPtr)
return bpy::incref(sipObj);
}
template <typename T>
struct QClass_converters
{
@@ -507,6 +517,101 @@ struct QInterface_converters
};
int getArgCount(PyObject *object) {
int result = 0;
PyObject *funcCode = PyObject_GetAttrString(object, "func_code");
if (funcCode) {
PyObject *argCount = PyObject_GetAttrString(funcCode, "co_argcount");
if(argCount) {
result = PyInt_AsLong(argCount);
Py_DECREF(argCount);
}
Py_DECREF(funcCode);
}
return result;
}
struct Functor0_converter
{
struct FunctorWrapper
{
FunctorWrapper(boost::python::object callable) : m_Callable(callable) {
}
void operator()() {
GILock lock;
m_Callable();
}
boost::python::object m_Callable;
};
Functor0_converter()
{
bpy::converter::registry::push_back(&convertible, &construct, bpy::type_id<std::function<void()>>());
}
static void *convertible(PyObject *object)
{
if (!PyCallable_Check(object)
|| (getArgCount(object) != 0)) {
return NULL;
}
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<void()>>*)data)->storage.bytes;
new (storage) std::function<void()>(FunctorWrapper(callable));
data->convertible = storage;
}
};
template <typename PAR1, typename PAR2>
struct Functor2_converter
{
struct FunctorWrapper
{
FunctorWrapper(boost::python::object callable) : m_Callable(callable) {
}
void operator()(const PAR1 &param1, const PAR2 &param2) {
GILock lock;
m_Callable(param1, param2);
}
boost::python::object m_Callable;
};
Functor2_converter()
{
bpy::converter::registry::push_back(&convertible, &construct, bpy::type_id<std::function<void(PAR1, PAR2)>>());
}
static void *convertible(PyObject *object)
{
if (!PyCallable_Check(object)
|| (getArgCount(object) != 2)) {
return NULL;
}
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<void(PAR1, PAR2)>>*)data)->storage.bytes;
new (storage) std::function<void(PAR1, PAR2)>(FunctorWrapper(callable));
data->convertible = storage;
}
};
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(updateWithQuality, MOBase::GuessedValue<QString>::update, 2, 2)
@@ -534,32 +639,37 @@ BOOST_PYTHON_MODULE(mobase)
.value("candidate", MOBase::VersionInfo::RELEASE_CANDIDATE)
.value("beta", MOBase::VersionInfo::RELEASE_BETA)
.value("alpha", MOBase::VersionInfo::RELEASE_ALPHA)
.value("prealpha", MOBase::VersionInfo::RELEASE_PREALPHA);
.value("prealpha", MOBase::VersionInfo::RELEASE_PREALPHA)
;
bpy::enum_<MOBase::IPluginInstaller::EInstallResult>("InstallResult")
.value("success", MOBase::IPluginInstaller::RESULT_SUCCESS)
.value("failed", MOBase::IPluginInstaller::RESULT_FAILED)
.value("canceled", MOBase::IPluginInstaller::RESULT_CANCELED)
.value("manualRequested", MOBase::IPluginInstaller::RESULT_MANUALREQUESTED)
.value("notAttempted", MOBase::IPluginInstaller::RESULT_NOTATTEMPTED);
.value("notAttempted", MOBase::IPluginInstaller::RESULT_NOTATTEMPTED)
;
bpy::enum_<MOBase::IGameInfo::Type>("GameType")
.value("oblivion", MOBase::IGameInfo::TYPE_OBLIVION)
.value("fallout3", MOBase::IGameInfo::TYPE_FALLOUT3)
.value("falloutnv", MOBase::IGameInfo::TYPE_FALLOUTNV)
.value("skyrim", MOBase::IGameInfo::TYPE_SKYRIM);
.value("skyrim", MOBase::IGameInfo::TYPE_SKYRIM)
;
bpy::class_<MOBase::VersionInfo>("VersionInfo")
.def(bpy::init<int, int, int, MOBase::VersionInfo::ReleaseType>())
.def("parse", &MOBase::VersionInfo::parse)
.def("canonicalString", &MOBase::VersionInfo::canonicalString);
.def("canonicalString", &MOBase::VersionInfo::canonicalString)
;
bpy::class_<MOBase::PluginSetting>("PluginSetting", bpy::init<const QString&, const QString&, const QVariant&>());
bpy::class_<IGameInfoWrapper, boost::noncopyable>("GameInfo")
.def("type", bpy::pure_virtual(&MOBase::IGameInfo::type))
.def("path", bpy::pure_virtual(&MOBase::IGameInfo::path))
.def("binaryName", bpy::pure_virtual(&MOBase::IGameInfo::binaryName));
.def("binaryName", bpy::pure_virtual(&MOBase::IGameInfo::binaryName))
;
bpy::class_<IOrganizerWrapper, boost::noncopyable>("IOrganizer")
.def("gameInfo", bpy::pure_virtual(&MOBase::IOrganizer::gameInfo), bpy::return_value_policy<bpy::reference_existing_object>())
@@ -577,9 +687,10 @@ BOOST_PYTHON_MODULE(mobase)
.def("persistent", bpy::pure_virtual(&IOrganizer::persistent))
.def("setPersistent", bpy::pure_virtual(&IOrganizer::setPersistent))
.def("pluginDataPath", bpy::pure_virtual(&IOrganizer::pluginDataPath))
.def("installMod", bpy::pure_virtual(&IOrganizer::installMod))
.def("installMod", bpy::pure_virtual(&IOrganizer::installMod), bpy::return_value_policy<bpy::reference_existing_object>())
.def("downloadManager", bpy::pure_virtual(&IOrganizer::downloadManager), bpy::return_value_policy<bpy::reference_existing_object>())
.def("pluginList", bpy::pure_virtual(&IOrganizer::pluginList), bpy::return_value_policy<bpy::reference_existing_object>())
.def("modList", bpy::pure_virtual(&IOrganizer::modList), bpy::return_value_policy<bpy::reference_existing_object>())
.def("startApplication", bpy::pure_virtual(&IOrganizer::startApplication), bpy::return_value_policy<bpy::return_by_value>())
.def("onAboutToRun", bpy::pure_virtual(&IOrganizer::onAboutToRun))
.def("refreshModList", bpy::pure_virtual(&IOrganizer::refreshModList))
@@ -592,12 +703,32 @@ BOOST_PYTHON_MODULE(mobase)
.def("requestDownloadURL", &ModRepositoryBridgeWrapper::requestDownloadURL)
.def("requestToggleEndorsement", &ModRepositoryBridgeWrapper::requestToggleEndorsement)
.def("onFilesAvailable", &ModRepositoryBridgeWrapper::onFilesAvailable)
.def("onRequestFailed", &ModRepositoryBridgeWrapper::onRequestFailed);
.def("onRequestFailed", &ModRepositoryBridgeWrapper::onRequestFailed)
;
bpy::class_<IDownloadManagerWrapper, boost::noncopyable>("IDownloadManager")
.def("startDownloadURLs", bpy::pure_virtual(&IDownloadManager::startDownloadURLs))
.def("startDownloadNexusFile", bpy::pure_virtual(&IDownloadManager::startDownloadNexusFile))
.def("downloadPath", bpy::pure_virtual(&IDownloadManager::downloadPath));
.def("downloadPath", bpy::pure_virtual(&IDownloadManager::downloadPath))
;
bpy::class_<IInstallationManagerWrapper, boost::noncopyable>("IInstallationManager")
.def("extractFile", bpy::pure_virtual(&IInstallationManager::extractFile))
.def("extractFiles", bpy::pure_virtual(&IInstallationManager::extractFiles))
.def("installArchive", bpy::pure_virtual(&IInstallationManager::installArchive))
;
bpy::class_<IModInterfaceWrapper, boost::noncopyable>("IModInterface")
.def("name", bpy::pure_virtual(&IModInterface::name))
.def("absolutePath", bpy::pure_virtual(&IModInterface::absolutePath))
.def("setVersion", bpy::pure_virtual(&IModInterface::setVersion))
.def("setNewestVersion", bpy::pure_virtual(&IModInterface::setNewestVersion))
.def("setIsEndorsed", bpy::pure_virtual(&IModInterface::setIsEndorsed))
.def("setNexusID", bpy::pure_virtual(&IModInterface::setNexusID))
.def("addNexusCategory", bpy::pure_virtual(&IModInterface::addNexusCategory))
.def("setName", bpy::pure_virtual(&IModInterface::setName))
.def("remove", bpy::pure_virtual(&IModInterface::remove))
;
bpy::enum_<MOBase::EGuessQuality>("GuessQuality")
.value("invalid", MOBase::GUESS_INVALID)
@@ -605,18 +736,41 @@ BOOST_PYTHON_MODULE(mobase)
.value("good", MOBase::GUESS_GOOD)
.value("meta", MOBase::GUESS_META)
.value("preset", MOBase::GUESS_PRESET)
.value("user", MOBase::GUESS_USER);
.value("user", MOBase::GUESS_USER)
;
bpy::class_<MOBase::GuessedValue<QString>, boost::noncopyable>("GuessedString")
.def("update",
static_cast<GuessedValue<QString> &(GuessedValue<QString>::*)(const QString&, EGuessQuality)>(&GuessedValue<QString>::update),
bpy::return_value_policy<bpy::reference_existing_object>(), updateWithQuality())
.def("variants", &MOBase::GuessedValue<QString>::variants, bpy::return_value_policy<bpy::copy_const_reference>());
.def("variants", &MOBase::GuessedValue<QString>::variants, bpy::return_value_policy<bpy::copy_const_reference>())
;
bpy::class_<IPluginToolWrapper, boost::noncopyable>("IPluginTool")
.def("setParentWidget", bpy::pure_virtual(&MOBase::IPluginTool::setParentWidget));
.def("setParentWidget", bpy::pure_virtual(&MOBase::IPluginTool::setParentWidget))
;
bpy::class_<IPluginInstallerCustomWrapper, boost::noncopyable>("IPluginInstallerCustom")
.def("setParentWidget", bpy::pure_virtual(&MOBase::IPluginInstallerCustom::setParentWidget));
.def("setParentWidget", bpy::pure_virtual(&MOBase::IPluginInstallerCustom::setParentWidget))
;
Functor0_converter(); // converter for the onRefreshed-callback
bpy::class_<IPluginListWrapper, boost::noncopyable>("IPluginList")
.def("state", bpy::pure_virtual(&MOBase::IPluginList::state))
.def("priority", bpy::pure_virtual(&MOBase::IPluginList::priority))
.def("loadOrder", bpy::pure_virtual(&MOBase::IPluginList::loadOrder))
.def("isMaster", bpy::pure_virtual(&MOBase::IPluginList::isMaster))
.def("origin", bpy::pure_virtual(&MOBase::IPluginList::origin))
.def("onRefreshed", bpy::pure_virtual(&MOBase::IPluginList::onRefreshed))
;
bpy::to_python_converter<IModList::ModStates, QFlags_to_int<IModList::ModState>>();
Functor2_converter<const QString&, IModList::ModStates>(); // converter for the onModStateChanged-callback
bpy::class_<IModListWrapper, boost::noncopyable>("IModList")
.def("state", bpy::pure_virtual(&MOBase::IModList::state))
.def("priority", bpy::pure_virtual(&MOBase::IModList::priority))
.def("setPriority", bpy::pure_virtual(&MOBase::IModList::setPriority))
.def("onModStateChanged", bpy::pure_virtual(&MOBase::IModList::onModStateChanged))
;
GuessedValue_converters<QString>();
+1 -1
View File
@@ -22,7 +22,7 @@ public:
#define PYDLLEXPORT Q_DECL_IMPORT
#endif // PYTHONRUNNER_LIBRARY
extern "C" PYDLLEXPORT IPythonRunner *CreatePythonRunner(const MOBase::IOrganizer *moInfo, const QString &pythonDir);
extern "C" PYDLLEXPORT IPythonRunner *CreatePythonRunner(MOBase::IOrganizer *moInfo, const QString &pythonDir);
+50 -9
View File
@@ -3,7 +3,9 @@
#ifndef Q_MOC_RUN
#pragma warning (push, 0)
#include <boost/python.hpp>
#pragma warning (pop)
#endif
#include <QString>
@@ -11,6 +13,8 @@
#include <imoinfo.h>
#include <igameinfo.h>
#include <imodrepositorybridge.h>
#include <imodinterface.h>
#include <iinstallationmanager.h>
#include "error.h"
#include "gilock.h"
@@ -65,8 +69,8 @@ public:
void onRequestFailed(boost::python::object callback) {
m_FailedHandler = callback;
connect(m_Wrapped, SIGNAL(requestFailed(int,QVariant,QString)),
this, SLOT(requestFailed(int,QVariant,QString)),
connect(m_Wrapped, SIGNAL(requestFailed(int,int,QVariant,QString)),
this, SLOT(requestFailed(int,int,QVariant,QString)),
Qt::UniqueConnection);
}
@@ -82,20 +86,20 @@ private slots:
qCritical("no handler connected");
return;
}
// try {
try {
GILock lock;
m_FilesAvailableHandler(modID, userData, resultData);
// } catch (const boost::python::error_already_set&) {
} catch (const boost::python::error_already_set&) {
// qDebug("error");
//reportPythonError();
// }
reportPythonError();
}
}
void requestFailed(int modID, QVariant userData, const QString &errorMessage)
void requestFailed(int modID, int fileID, QVariant userData, const QString &errorMessage)
{
try {
GILock lock;
m_FailedHandler(modID, userData, errorMessage);
m_FailedHandler(modID, fileID, userData, errorMessage);
} catch (const boost::python::error_already_set&) {
reportPythonError();
}
@@ -133,7 +137,7 @@ struct IOrganizerWrapper: MOBase::IOrganizer, boost::python::wrapper<MOBase::IOr
virtual QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def = QVariant()) const { return this->get_override("persistent")(pluginName, key, def); }
virtual void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync = true) { this->get_override("setPersistent")(pluginName, key, value, sync); }
virtual QString pluginDataPath() const { return this->get_override("pluginDataPath")(); }
virtual void installMod(const QString &fileName) { this->get_override("installMod")(fileName); }
virtual MOBase::IModInterface *installMod(const QString &fileName) { return this->get_override("installMod")(fileName); }
virtual MOBase::IDownloadManager *downloadManager() { return this->get_override("downloadManager")(); }
virtual MOBase::IPluginList *pluginList() { return this->get_override("pluginList")(); }
virtual MOBase::IModList *modList() { return this->get_override("modList")(); }
@@ -155,6 +159,13 @@ private:
boost::python::object m_DownloadCompleteHandler;
};
struct IInstallationManagerWrapper: MOBase::IInstallationManager, boost::python::wrapper<MOBase::IInstallationManager>
{
virtual QString extractFile(const QString &fileName) { return this->get_override("extractFile")(fileName); }
virtual QStringList extractFiles(const QStringList &files, bool flatten) { return this->get_override("extractFiles")(files, flatten); }
virtual MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveFile) { return this->get_override("installArchive")(modName, archiveFile); }
};
struct IGameInfoWrapper: MOBase::IGameInfo, boost::python::wrapper<MOBase::IGameInfo>
{
virtual Type type() const { return this->get_override("type")(); }
@@ -162,5 +173,35 @@ struct IGameInfoWrapper: MOBase::IGameInfo, boost::python::wrapper<MOBase::IGame
virtual QString binaryName() const { return this->get_override("binaryName")(); }
};
struct IModInterfaceWrapper: MOBase::IModInterface, boost::python::wrapper<MOBase::IModInterface>
{
virtual QString name() const { return this->get_override("name")(); }
virtual QString absolutePath() const { return this->get_override("absolutePath")(); }
virtual void setVersion(const MOBase::VersionInfo &version) { this->get_override("setVersion")(version); }
virtual void setNewestVersion(const MOBase::VersionInfo &version) { this->get_override("setNewestVersion")(version); }
virtual void setIsEndorsed(bool endorsed) { this->get_override("setIsEndorsed")(endorsed); }
virtual void setNexusID(int nexusID) { this->get_override("setNexusID")(nexusID); }
virtual void addNexusCategory(int categoryID) { this->get_override("addNexusCategory")(categoryID); }
virtual bool setName(const QString &name) { return this->get_override("setName")(name); }
virtual bool remove() { return this->get_override("remove")(); }
};
struct IPluginListWrapper: MOBase::IPluginList, boost::python::wrapper<MOBase::IPluginList> {
virtual PluginState state(const QString &name) const { return this->get_override("state")(name); }
virtual int priority(const QString &name) const { return this->get_override("priority")(name); }
virtual int loadOrder(const QString &name) const { return this->get_override("loadOrder")(name); }
virtual bool isMaster(const QString &name) const { return this->get_override("isMaster")(name); }
virtual QString origin(const QString &name) const { return this->get_override("origin")(name); }
virtual bool onRefreshed(const std::function<void ()> &callback) { return this->get_override("onRefreshed")(callback); }
};
struct IModListWrapper: MOBase::IModList, boost::python::wrapper<MOBase::IModList> {
virtual ModStates state(const QString &name) const{ return this->get_override("state")(name); }
virtual int priority(const QString &name) const{ return this->get_override("priority")(name); }
virtual bool setPriority(const QString &name, int newPriority){ return this->get_override("setPriority")(name, newPriority); }
virtual bool onModStateChanged(const std::function<void (const QString &, ModStates)> &func) { return this->get_override("onModStateChanged")(func); }
};
#endif // UIBASEWRAPPERS_H