diff --git a/3rdparty/pythonqt/CMakeLists.txt b/3rdparty/pythonqt/CMakeLists.txt index 476b6b6ba..9760732ed 100644 --- a/3rdparty/pythonqt/CMakeLists.txt +++ b/3rdparty/pythonqt/CMakeLists.txt @@ -25,8 +25,6 @@ set(SOURCES generated_cpp/com_trolltech_qt_network/com_trolltech_qt_network0.cpp generated_cpp/com_trolltech_qt_network/com_trolltech_qt_network1.cpp generated_cpp/com_trolltech_qt_network/com_trolltech_qt_network_init.cpp - generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.cpp - generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools_init.cpp src/gui/PythonQtScriptingConsole.cpp src/PythonQtClassInfo.cpp src/PythonQtClassWrapper.cpp @@ -63,7 +61,6 @@ set(HEADERS generated_cpp/com_trolltech_qt_gui/com_trolltech_qt_gui9.h generated_cpp/com_trolltech_qt_network/com_trolltech_qt_network0.h generated_cpp/com_trolltech_qt_network/com_trolltech_qt_network1.h - generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.h src/gui/PythonQtScriptingConsole.h src/PythonQt.h src/PythonQtSignalReceiver.h diff --git a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.cpp b/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.cpp deleted file mode 100644 index 67f0f7b8b..000000000 --- a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.cpp +++ /dev/null @@ -1,332 +0,0 @@ -#include "com_trolltech_qt_uitools0.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void PythonQtShell_QUiLoader::childEvent(QChildEvent* arg__1) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "childEvent"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"" , "QChildEvent*"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(2, argumentList); - void* args[2] = {NULL, (void*)&arg__1}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return; - } -} - QUiLoader::childEvent(arg__1); -} -QAction* PythonQtShell_QUiLoader::createAction(QObject* parent, const QString& name) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "createAction"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"QAction*" , "QObject*" , "const QString&"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(3, argumentList); - QAction* returnValue; - void* args[3] = {NULL, (void*)&parent, (void*)&name}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { - args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue); - if (args[0]!=&returnValue) { - if (args[0]==NULL) { - PythonQt::priv()->handleVirtualOverloadReturnError("createAction", methodInfo, result); - } else { - returnValue = *((QAction**)args[0]); - } - } - } - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return returnValue; - } -} - return QUiLoader::createAction(parent, name); -} -QActionGroup* PythonQtShell_QUiLoader::createActionGroup(QObject* parent, const QString& name) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "createActionGroup"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"QActionGroup*" , "QObject*" , "const QString&"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(3, argumentList); - QActionGroup* returnValue; - void* args[3] = {NULL, (void*)&parent, (void*)&name}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { - args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue); - if (args[0]!=&returnValue) { - if (args[0]==NULL) { - PythonQt::priv()->handleVirtualOverloadReturnError("createActionGroup", methodInfo, result); - } else { - returnValue = *((QActionGroup**)args[0]); - } - } - } - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return returnValue; - } -} - return QUiLoader::createActionGroup(parent, name); -} -QLayout* PythonQtShell_QUiLoader::createLayout(const QString& className, QObject* parent, const QString& name) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "createLayout"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"QLayout*" , "const QString&" , "QObject*" , "const QString&"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(4, argumentList); - QLayout* returnValue; - void* args[4] = {NULL, (void*)&className, (void*)&parent, (void*)&name}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { - args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue); - if (args[0]!=&returnValue) { - if (args[0]==NULL) { - PythonQt::priv()->handleVirtualOverloadReturnError("createLayout", methodInfo, result); - } else { - returnValue = *((QLayout**)args[0]); - } - } - } - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return returnValue; - } -} - return QUiLoader::createLayout(className, parent, name); -} -QWidget* PythonQtShell_QUiLoader::createWidget(const QString& className, QWidget* parent, const QString& name) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "createWidget"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"QWidget*" , "const QString&" , "QWidget*" , "const QString&"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(4, argumentList); - QWidget* returnValue; - void* args[4] = {NULL, (void*)&className, (void*)&parent, (void*)&name}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { - args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue); - if (args[0]!=&returnValue) { - if (args[0]==NULL) { - PythonQt::priv()->handleVirtualOverloadReturnError("createWidget", methodInfo, result); - } else { - returnValue = *((QWidget**)args[0]); - } - } - } - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return returnValue; - } -} - return QUiLoader::createWidget(className, parent, name); -} -void PythonQtShell_QUiLoader::customEvent(QEvent* arg__1) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "customEvent"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"" , "QEvent*"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(2, argumentList); - void* args[2] = {NULL, (void*)&arg__1}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return; - } -} - QUiLoader::customEvent(arg__1); -} -bool PythonQtShell_QUiLoader::event(QEvent* arg__1) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "event"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"bool" , "QEvent*"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(2, argumentList); - bool returnValue; - void* args[2] = {NULL, (void*)&arg__1}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { - args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue); - if (args[0]!=&returnValue) { - if (args[0]==NULL) { - PythonQt::priv()->handleVirtualOverloadReturnError("event", methodInfo, result); - } else { - returnValue = *((bool*)args[0]); - } - } - } - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return returnValue; - } -} - return QUiLoader::event(arg__1); -} -bool PythonQtShell_QUiLoader::eventFilter(QObject* arg__1, QEvent* arg__2) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "eventFilter"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"bool" , "QObject*" , "QEvent*"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(3, argumentList); - bool returnValue; - void* args[3] = {NULL, (void*)&arg__1, (void*)&arg__2}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { - args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue); - if (args[0]!=&returnValue) { - if (args[0]==NULL) { - PythonQt::priv()->handleVirtualOverloadReturnError("eventFilter", methodInfo, result); - } else { - returnValue = *((bool*)args[0]); - } - } - } - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return returnValue; - } -} - return QUiLoader::eventFilter(arg__1, arg__2); -} -void PythonQtShell_QUiLoader::timerEvent(QTimerEvent* arg__1) -{ -if (_wrapper) { - PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "timerEvent"); - PyErr_Clear(); - if (obj && !PythonQtSlotFunction_Check(obj)) { - static const char* argumentList[] ={"" , "QTimerEvent*"}; - static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(2, argumentList); - void* args[2] = {NULL, (void*)&arg__1}; - PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true); - if (result) { Py_DECREF(result); } - Py_DECREF(obj); - return; - } -} - QUiLoader::timerEvent(arg__1); -} -QUiLoader* PythonQtWrapper_QUiLoader::new_QUiLoader(QObject* parent) -{ -return new PythonQtShell_QUiLoader(parent); } - -void PythonQtWrapper_QUiLoader::addPluginPath(QUiLoader* theWrappedObject, const QString& path) -{ - ( theWrappedObject->addPluginPath(path)); -} - -QStringList PythonQtWrapper_QUiLoader::availableLayouts(QUiLoader* theWrappedObject) const -{ - return ( theWrappedObject->availableLayouts()); -} - -QStringList PythonQtWrapper_QUiLoader::availableWidgets(QUiLoader* theWrappedObject) const -{ - return ( theWrappedObject->availableWidgets()); -} - -void PythonQtWrapper_QUiLoader::clearPluginPaths(QUiLoader* theWrappedObject) -{ - ( theWrappedObject->clearPluginPaths()); -} - -QAction* PythonQtWrapper_QUiLoader::createAction(QUiLoader* theWrappedObject, QObject* parent, const QString& name) -{ - return ( ((PythonQtPublicPromoter_QUiLoader*)theWrappedObject)->promoted_createAction(parent, name)); -} - -QActionGroup* PythonQtWrapper_QUiLoader::createActionGroup(QUiLoader* theWrappedObject, QObject* parent, const QString& name) -{ - return ( ((PythonQtPublicPromoter_QUiLoader*)theWrappedObject)->promoted_createActionGroup(parent, name)); -} - -QLayout* PythonQtWrapper_QUiLoader::createLayout(QUiLoader* theWrappedObject, const QString& className, QObject* parent, const QString& name) -{ - return ( ((PythonQtPublicPromoter_QUiLoader*)theWrappedObject)->promoted_createLayout(className, parent, name)); -} - -QWidget* PythonQtWrapper_QUiLoader::createWidget(QUiLoader* theWrappedObject, const QString& className, QWidget* parent, const QString& name) -{ - return ( ((PythonQtPublicPromoter_QUiLoader*)theWrappedObject)->promoted_createWidget(className, parent, name)); -} - -bool PythonQtWrapper_QUiLoader::isLanguageChangeEnabled(QUiLoader* theWrappedObject) const -{ - return ( theWrappedObject->isLanguageChangeEnabled()); -} - -bool PythonQtWrapper_QUiLoader::isScriptingEnabled(QUiLoader* theWrappedObject) const -{ - return ( theWrappedObject->isScriptingEnabled()); -} - -bool PythonQtWrapper_QUiLoader::isTranslationEnabled(QUiLoader* theWrappedObject) const -{ - return ( theWrappedObject->isTranslationEnabled()); -} - -QWidget* PythonQtWrapper_QUiLoader::load(QUiLoader* theWrappedObject, QIODevice* device, QWidget* parentWidget) -{ - return ( theWrappedObject->load(device, parentWidget)); -} - -QStringList PythonQtWrapper_QUiLoader::pluginPaths(QUiLoader* theWrappedObject) const -{ - return ( theWrappedObject->pluginPaths()); -} - -void PythonQtWrapper_QUiLoader::setLanguageChangeEnabled(QUiLoader* theWrappedObject, bool enabled) -{ - ( theWrappedObject->setLanguageChangeEnabled(enabled)); -} - -void PythonQtWrapper_QUiLoader::setScriptingEnabled(QUiLoader* theWrappedObject, bool enabled) -{ - ( theWrappedObject->setScriptingEnabled(enabled)); -} - -void PythonQtWrapper_QUiLoader::setTranslationEnabled(QUiLoader* theWrappedObject, bool enabled) -{ - ( theWrappedObject->setTranslationEnabled(enabled)); -} - -void PythonQtWrapper_QUiLoader::setWorkingDirectory(QUiLoader* theWrappedObject, const QDir& dir) -{ - ( theWrappedObject->setWorkingDirectory(dir)); -} - -QDir PythonQtWrapper_QUiLoader::workingDirectory(QUiLoader* theWrappedObject) const -{ - return ( theWrappedObject->workingDirectory()); -} - - diff --git a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.h b/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.h deleted file mode 100644 index 7afee7152..000000000 --- a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools0.h +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -class PythonQtShell_QUiLoader : public QUiLoader -{ -public: - PythonQtShell_QUiLoader(QObject* parent = 0):QUiLoader(parent),_wrapper(NULL) {}; - -virtual void childEvent(QChildEvent* arg__1); -virtual QAction* createAction(QObject* parent = 0, const QString& name = QString()); -virtual QActionGroup* createActionGroup(QObject* parent = 0, const QString& name = QString()); -virtual QLayout* createLayout(const QString& className, QObject* parent = 0, const QString& name = QString()); -virtual QWidget* createWidget(const QString& className, QWidget* parent = 0, const QString& name = QString()); -virtual void customEvent(QEvent* arg__1); -virtual bool event(QEvent* arg__1); -virtual bool eventFilter(QObject* arg__1, QEvent* arg__2); -virtual void timerEvent(QTimerEvent* arg__1); - - PythonQtInstanceWrapper* _wrapper; -}; - -class PythonQtPublicPromoter_QUiLoader : public QUiLoader -{ public: -inline QAction* promoted_createAction(QObject* parent = 0, const QString& name = QString()) { return QUiLoader::createAction(parent, name); } -inline QActionGroup* promoted_createActionGroup(QObject* parent = 0, const QString& name = QString()) { return QUiLoader::createActionGroup(parent, name); } -inline QLayout* promoted_createLayout(const QString& className, QObject* parent = 0, const QString& name = QString()) { return QUiLoader::createLayout(className, parent, name); } -inline QWidget* promoted_createWidget(const QString& className, QWidget* parent = 0, const QString& name = QString()) { return QUiLoader::createWidget(className, parent, name); } -}; - -class PythonQtWrapper_QUiLoader : public QObject -{ Q_OBJECT -public: -public slots: -QUiLoader* new_QUiLoader(QObject* parent = 0); -void delete_QUiLoader(QUiLoader* obj) { delete obj; } - void addPluginPath(QUiLoader* theWrappedObject, const QString& path); - QStringList availableLayouts(QUiLoader* theWrappedObject) const; - QStringList availableWidgets(QUiLoader* theWrappedObject) const; - void clearPluginPaths(QUiLoader* theWrappedObject); - QAction* createAction(QUiLoader* theWrappedObject, QObject* parent = 0, const QString& name = QString()); - QActionGroup* createActionGroup(QUiLoader* theWrappedObject, QObject* parent = 0, const QString& name = QString()); - QLayout* createLayout(QUiLoader* theWrappedObject, const QString& className, QObject* parent = 0, const QString& name = QString()); - QWidget* createWidget(QUiLoader* theWrappedObject, const QString& className, QWidget* parent = 0, const QString& name = QString()); - bool isLanguageChangeEnabled(QUiLoader* theWrappedObject) const; - bool isScriptingEnabled(QUiLoader* theWrappedObject) const; - bool isTranslationEnabled(QUiLoader* theWrappedObject) const; - QWidget* load(QUiLoader* theWrappedObject, QIODevice* device, QWidget* parentWidget = 0); - QStringList pluginPaths(QUiLoader* theWrappedObject) const; - void setLanguageChangeEnabled(QUiLoader* theWrappedObject, bool enabled); - void setScriptingEnabled(QUiLoader* theWrappedObject, bool enabled); - void setTranslationEnabled(QUiLoader* theWrappedObject, bool enabled); - void setWorkingDirectory(QUiLoader* theWrappedObject, const QDir& dir); - QDir workingDirectory(QUiLoader* theWrappedObject) const; -}; - - diff --git a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools_init.cpp b/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools_init.cpp deleted file mode 100644 index 8578f3cef..000000000 --- a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools_init.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include "com_trolltech_qt_uitools0.h" -#include "com_trolltech_qt_uitools_init.h" - - -void PythonQt_init_QtUiTools(PyObject* module) { -PythonQt::priv()->registerClass(&QUiLoader::staticMetaObject, "QtUiTools", PythonQtCreateObject, PythonQtSetInstanceWrapperOnShell, module, 0); - -} diff --git a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools_init.h b/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools_init.h deleted file mode 100644 index 65b74a0b5..000000000 --- a/3rdparty/pythonqt/generated_cpp/com_trolltech_qt_uitools/com_trolltech_qt_uitools_init.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef COM_TROLLTECH_QT_UITOOLS_INIT_H -#define COM_TROLLTECH_QT_UITOOLS_INIT_H - -#include "PythonQtSystem.h" - -PYTHONQT_EXPORT void PythonQt_init_QtUiTools(PyObject* module); - -#endif // COM_TROLLTECH_QT_UITOOLS_INIT_H diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b9f3f7d8..3e91a5d61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ if (UNIX AND NOT APPLE) set(LINUX 1) endif (UNIX AND NOT APPLE) -find_package(Qt4 4.5.0 REQUIRED QtCore QtGui QtOpenGL QtSql QtNetwork QtXml QtUiTools) +find_package(Qt4 4.5.0 REQUIRED QtCore QtGui QtOpenGL QtSql QtNetwork QtXml) if (LINUX) option(ENABLE_DBUS "Enable D-Bus, MPRIS and native notifications. Required for DeviceKit and Wii remote support" ON) if(ENABLE_DBUS) diff --git a/data/data.qrc b/data/data.qrc index c80ab6e90..27bca3b96 100644 --- a/data/data.qrc +++ b/data/data.qrc @@ -297,7 +297,6 @@ schema/schema-24.sql schema/schema-25.sql schema/schema-26.sql - pythonstartup.py schema/schema-27.sql schema/schema-28.sql icons/22x22/network-server.png @@ -325,5 +324,21 @@ schema/schema-34.sql icons/22x22/audio-x-generic.png icons/22x22/audio-x-disabled.png + pythonlibs/uic/driver.py + pythonlibs/uic/exceptions.py + pythonlibs/uic/icon_cache.py + pythonlibs/uic/__init__.py + pythonlibs/uic/Loader/__init__.py + pythonlibs/uic/Loader/loader.py + pythonlibs/uic/Loader/qobjectcreator.py + pythonlibs/uic/objcreator.py + pythonlibs/uic/port_v2/ascii_upper.py + pythonlibs/uic/port_v2/encode_utf8.py + pythonlibs/uic/port_v2/__init__.py + pythonlibs/uic/port_v2/invoke.py + pythonlibs/uic/port_v2/load_plugin.py + pythonlibs/uic/port_v2/string_io.py + pythonlibs/uic/properties.py + pythonlibs/uic/uiparser.py diff --git a/data/pythonlibs/uic/Loader/__init__.py b/data/pythonlibs/uic/Loader/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/data/pythonlibs/uic/Loader/loader.py b/data/pythonlibs/uic/Loader/loader.py new file mode 100644 index 000000000..d888f6c2e --- /dev/null +++ b/data/pythonlibs/uic/Loader/loader.py @@ -0,0 +1,21 @@ +from PythonQt import QtGui, QtCore +from uic.uiparser import UIParser +from uic.Loader.qobjectcreator import LoaderCreatorPolicy + + +class DynamicUILoader(UIParser): + def __init__(self): + UIParser.__init__(self, QtCore, QtGui, LoaderCreatorPolicy()) + + def createToplevelWidget(self, classname, widgetname): + if self.toplevelInst is not None: + if not isinstance(self.toplevelInst, self.factory.findQObjectType(classname)): + raise TypeError(("Wrong base class of toplevel widget", + (type(self.toplevelInst), classname))) + return self.toplevelInst + else: + return self.factory.createQObject(classname, widgetname, ()) + + def loadUi(self, filename, toplevelInst = None): + self.toplevelInst = toplevelInst + return self.parse(filename) diff --git a/data/pythonlibs/uic/Loader/qobjectcreator.py b/data/pythonlibs/uic/Loader/qobjectcreator.py new file mode 100644 index 000000000..68b9fd14b --- /dev/null +++ b/data/pythonlibs/uic/Loader/qobjectcreator.py @@ -0,0 +1,83 @@ +import sys + +try: + set() +except NameError: + from sets import Set as set + +from PythonQt import QtGui + + +class _QtGuiWrapper(object): + def search(cls): + return getattr(QtGui, cls, None) + search = staticmethod(search) + + +class _ModuleWrapper(object): + def __init__(self, moduleName, classes): + self._moduleName = moduleName + self._module = None + self._classes = set(classes) + + def search(self, cls): + if cls in self._classes: + if self._module is None: + self._module = __import__(self._moduleName, {}, {}, self._classes) + # Allow for namespaces. + obj = self._module + for attr in cls.split('.'): + obj = getattr(obj, attr) + + return obj + else: + return None + + +class _CustomWidgetLoader(object): + def __init__(self): + # should it stay this way? + sys.path.append(".") + self._widgets = {} + self._modules = {} + + def addCustomWidget(self, widgetClass, baseClass, module): + assert widgetClass not in self._widgets + self._widgets[widgetClass] = module + + def search(self, cls): + try: + module = self._widgets[cls] + if module not in self._modules: + self._modules[module] = __import__(module, {}, {}, (cls,)) + + return getattr(self._modules[module], cls) + except KeyError: + pass + return None + + +class LoaderCreatorPolicy(object): + def createQtGuiWrapper(self): + return _QtGuiWrapper + + def createModuleWrapper(self, moduleName, classes): + return _ModuleWrapper(moduleName, classes) + + def createCustomWidgetLoader(self): + return _CustomWidgetLoader() + + def instantiate(self, clsObject, objectName, ctor_args, is_attribute=True): + # Create a new type so setattr() can work + new_type = type("__WidgetWrapper_" + clsObject.__name__, (clsObject,), {}) + return new_type(*ctor_args) + + def invoke(self, rname, method, args): + return method(*args) + + def getSlot(self, object, slotname): + # Rename slots that correspond to Python keyword arguments. + if slotname == 'raise': + slotname += '_' + + return getattr(object, slotname) diff --git a/data/pythonlibs/uic/__init__.py b/data/pythonlibs/uic/__init__.py new file mode 100644 index 000000000..b33283fa6 --- /dev/null +++ b/data/pythonlibs/uic/__init__.py @@ -0,0 +1,21 @@ +__all__ = ("loadUi") + + +def loadUi(uifile, baseinstance=None): + """loadUi(uifile, baseinstance=None) -> widget + + Load a Qt Designer .ui file and return an instance of the user interface. + + uifile is a file name or file-like object containing the .ui file. + baseinstance is an optional instance of the Qt base class. If specified + then the user interface is created in it. Otherwise a new instance of the + base class is automatically created. + """ + + from uic.Loader.loader import DynamicUILoader + + return DynamicUILoader().loadUi(uifile, baseinstance) + + +# The list of directories that are searched for widget plugins. +from uic.objcreator import widgetPluginPath diff --git a/data/pythonlibs/uic/driver.py b/data/pythonlibs/uic/driver.py new file mode 100644 index 000000000..6606f375b --- /dev/null +++ b/data/pythonlibs/uic/driver.py @@ -0,0 +1,91 @@ +import sys +import logging + +from uic import compileUi, loadUi + + +class Driver(object): + """ This encapsulates access to the pyuic functionality so that it can be + called by code that is Python v2/v3 specific. + """ + + LOGGER_NAME = 'uic' + + def __init__(self, opts, ui_file): + """ Initialise the object. opts is the parsed options. ui_file is the + name of the .ui file. + """ + + if opts.debug: + logger = logging.getLogger(self.LOGGER_NAME) + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter("%(name)s: %(message)s")) + logger.addHandler(handler) + logger.setLevel(logging.DEBUG) + + self._opts = opts + self._ui_file = ui_file + + def invoke(self): + """ Invoke the action as specified by the parsed options. Returns 0 if + there was no error. + """ + + if self._opts.preview: + return self._preview() + + self._generate() + + return 0 + + def _preview(self): + """ Preview the .ui file. Return the exit status to be passed back to + the parent process. + """ + + from PythonQt import QtGui + + app = QtGui.QApplication([self._ui_file]) + widget = loadUi(self._ui_file) + widget.show() + + return app.exec_() + + def _generate(self): + """ Generate the Python code. """ + + if self._opts.output == "-": + pyfile = sys.stdout + else: + pyfile = open(self._opts.output, 'wt') + + compileUi(self._ui_file, pyfile, self._opts.execute, self._opts.indent, + self._opts.pyqt3_wrapper) + + def on_IOError(self, e): + """ Handle an IOError exception. """ + + sys.stderr.write("Error: %s: \"%s\"\n" % (e.strerror, e.filename)) + + def on_SyntaxError(self, e): + """ Handle a SyntaxError exception. """ + + sys.stderr.write("Error in input file: %s\n" % e) + + def on_NoSuchWidgetError(self, e): + """ Handle a NoSuchWidgetError exception. """ + + if e.args[0].startswith("Q3"): + sys.stderr.write("Error: Q3Support widgets are not supported by PythonQt.\n") + else: + sys.stderr.write(str(e) + "\n") + + def on_Exception(self, e): + """ Handle a generic exception. """ + + if logging.getLogger(self.LOGGER_NAME).level == logging.DEBUG: + import traceback + + traceback.print_exception(*sys.exc_info()) + else: + sys.stderr.write("An unexpected error occurred") diff --git a/data/pythonlibs/uic/exceptions.py b/data/pythonlibs/uic/exceptions.py new file mode 100644 index 000000000..ba7fac932 --- /dev/null +++ b/data/pythonlibs/uic/exceptions.py @@ -0,0 +1,9 @@ +class NoSuchWidgetError(Exception): + def __str__(self): + return "Unknown Qt widget: %s" % (self.args[0],) + +class UnsupportedPropertyError(Exception): + pass + +class WidgetPluginError(Exception): + pass diff --git a/data/pythonlibs/uic/icon_cache.py b/data/pythonlibs/uic/icon_cache.py new file mode 100644 index 000000000..fa94eb52d --- /dev/null +++ b/data/pythonlibs/uic/icon_cache.py @@ -0,0 +1,111 @@ +"""Maintain a cache of icons. + +If an icon is used more than once by a GUI then ensure that only one copy is +created. +""" + + +class IconCache(object): + """A cache of icons.""" + + def __init__(self, object_factory, qtgui_module): + """Initialise the cache.""" + + self._object_factory = object_factory + self._qtgui_module = qtgui_module + self._cache = [] + + def get_icon(self, iconset): + """Return an icon described by the given iconset tag.""" + + iset = _IconSet(iconset) + + try: + idx = self._cache.index(iset) + except ValueError: + idx = -1 + + if idx >= 0: + # Return the icon from the cache. + iset = self._cache[idx] + else: + # Follow uic's naming convention. + name = 'icon' + idx = len(self._cache) + + if idx > 0: + name += str(idx) + + icon = self._object_factory.createQObject("QIcon", name, (), + is_attribute=False) + iset.set_icon(icon, self._qtgui_module) + self._cache.append(iset) + + return iset.icon + + +class _IconSet(object): + """An icon set, ie. the mode and state and the pixmap used for each.""" + + def __init__(self, iconset): + """Initialise the icon set from an XML tag.""" + + # Set the pre-Qt v4.4 fallback (ie. with no roles). + self._fallback = iconset.text.replace("\\", "\\\\") + self._use_fallback = True + + # Parse the icon set. + self._roles = {} + + for i in iconset: + file_name = i.text + if file_name is not None: + file_name = file_name.replace("\\", "\\\\") + + self._roles[i.tag] = file_name + self._use_fallback = False + + # There is no real icon yet. + self.icon = None + + def set_icon(self, icon, qtgui_module): + """Save the icon and set its attributes.""" + + if self._use_fallback: + icon.addFile(self._fallback) + else: + for role, pixmap in self._roles.items(): + if role.endswith("off"): + mode = role[:-3] + state = qtgui_module.QIcon.Off + elif role.endswith("on"): + mode = role[:-2] + state = qtgui_module.QIcon.On + else: + continue + + mode = getattr(qtgui_module.QIcon, mode.title()) + + if pixmap: + icon.addPixmap(qtgui_module.QPixmap(pixmap), mode, state) + else: + icon.addPixmap(qtgui_module.QPixmap(), mode, state) + + self.icon = icon + + def __eq__(self, other): + """Compare two icon sets for equality.""" + + if not isinstance(other, type(self)): + return NotImplemented + + if self._use_fallback: + if other._use_fallback: + return self._fallback == other._fallback + + return False + + if other._use_fallback: + return False + + return self._roles == other._roles diff --git a/data/pythonlibs/uic/objcreator.py b/data/pythonlibs/uic/objcreator.py new file mode 100644 index 000000000..1e4a0684b --- /dev/null +++ b/data/pythonlibs/uic/objcreator.py @@ -0,0 +1,90 @@ +import sys +import os.path + +from uic.exceptions import NoSuchWidgetError, WidgetPluginError + +if sys.hexversion >= 0x03000000: + from uic.port_v3.load_plugin import load_plugin +else: + from uic.port_v2.load_plugin import load_plugin + + +# The list of directories that are searched for widget plugins. This is +# exposed as part of the API. +widgetPluginPath = [os.path.join(os.path.dirname(__file__), 'widget-plugins')] + + +MATCH = True +NO_MATCH = False +MODULE = 0 +CW_FILTER = 1 + + +class QObjectCreator(object): + def __init__(self, creatorPolicy): + self._cpolicy = creatorPolicy + + self._cwFilters = [] + self._modules = [self._cpolicy.createQtGuiWrapper()] + + # Get the optional plugins. + for plugindir in widgetPluginPath: + try: + plugins = os.listdir(plugindir) + except: + plugins = [] + + for filename in plugins: + if not filename.endswith('.py'): + continue + + filename = os.path.join(plugindir, filename) + + plugin_globals = { + "MODULE": MODULE, + "CW_FILTER": CW_FILTER, + "MATCH": MATCH, + "NO_MATCH": NO_MATCH} + + plugin_locals = {} + + if load_plugin(open(filename), plugin_globals, plugin_locals): + pluginType = plugin_locals["pluginType"] + if pluginType == MODULE: + modinfo = plugin_locals["moduleInformation"]() + self._modules.append(self._cpolicy.createModuleWrapper(*modinfo)) + elif pluginType == CW_FILTER: + self._cwFilters.append(plugin_locals["getFilter"]()) + else: + raise WidgetPluginError("Unknown plugin type of %s" % filename) + + self._customWidgets = self._cpolicy.createCustomWidgetLoader() + self._modules.append(self._customWidgets) + + def createQObject(self, classname, *args, **kwargs): + classType = self.findQObjectType(classname) + if classType: + return self._cpolicy.instantiate(classType, *args, **kwargs) + raise NoSuchWidgetError(classname) + + def invoke(self, rname, method, args=()): + return self._cpolicy.invoke(rname, method, args) + + def findQObjectType(self, classname): + for module in self._modules: + w = module.search(classname) + if w is not None: + return w + return None + + def getSlot(self, obj, slotname): + return self._cpolicy.getSlot(obj, slotname) + + def addCustomWidget(self, widgetClass, baseClass, module): + for cwFilter in self._cwFilters: + match, result = cwFilter(widgetClass, baseClass, module) + if match: + widgetClass, baseClass, module = result + break + + self._customWidgets.addCustomWidget(widgetClass, baseClass, module) diff --git a/data/pythonlibs/uic/port_v2/__init__.py b/data/pythonlibs/uic/port_v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/data/pythonlibs/uic/port_v2/ascii_upper.py b/data/pythonlibs/uic/port_v2/ascii_upper.py new file mode 100644 index 000000000..4f4dfee54 --- /dev/null +++ b/data/pythonlibs/uic/port_v2/ascii_upper.py @@ -0,0 +1,11 @@ +import string + + +# A translation table for converting ASCII lower case to upper case. +_ascii_trans_table = string.maketrans(string.ascii_lowercase, + string.ascii_uppercase) + + +# Convert a string to ASCII upper case irrespective of the current locale. +def ascii_upper(s): + return s.translate(_ascii_trans_table) diff --git a/data/pythonlibs/uic/port_v2/encode_utf8.py b/data/pythonlibs/uic/port_v2/encode_utf8.py new file mode 100644 index 000000000..fcba3973a --- /dev/null +++ b/data/pythonlibs/uic/port_v2/encode_utf8.py @@ -0,0 +1,2 @@ +def encode_utf8(s): + return s.encode('UTF-8') diff --git a/data/pythonlibs/uic/port_v2/invoke.py b/data/pythonlibs/uic/port_v2/invoke.py new file mode 100644 index 000000000..be07cbdf5 --- /dev/null +++ b/data/pythonlibs/uic/port_v2/invoke.py @@ -0,0 +1,26 @@ +from uic.exceptions import NoSuchWidgetError + + +def invoke(driver): + """ Invoke the given command line driver. Return the exit status to be + passed back to the parent process. + """ + + exit_status = 1 + + try: + exit_status = driver.invoke() + + except IOError, e: + driver.on_IOError(e) + + except SyntaxError, e: + driver.on_SyntaxError(e) + + except NoSuchWidgetError, e: + driver.on_NoSuchWidgetError(e) + + except Exception, e: + driver.on_Exception(e) + + return exit_status diff --git a/data/pythonlibs/uic/port_v2/load_plugin.py b/data/pythonlibs/uic/port_v2/load_plugin.py new file mode 100644 index 000000000..723352d21 --- /dev/null +++ b/data/pythonlibs/uic/port_v2/load_plugin.py @@ -0,0 +1,17 @@ +from uic.exceptions import WidgetPluginError + + +def load_plugin(plugin, plugin_globals, plugin_locals): + """ Load the given plugin (which is an open file). Return True if the + plugin was loaded, or False if it wanted to be ignored. Raise an exception + if there was an error. + """ + + try: + exec(plugin.read(), plugin_globals, plugin_locals) + except ImportError: + return False + except Exception, e: + raise WidgetPluginError("%s: %s" % (e.__class__, str(e))) + + return True diff --git a/data/pythonlibs/uic/port_v2/string_io.py b/data/pythonlibs/uic/port_v2/string_io.py new file mode 100644 index 000000000..0a50ed9b9 --- /dev/null +++ b/data/pythonlibs/uic/port_v2/string_io.py @@ -0,0 +1,5 @@ +# Import the StringIO object. +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO diff --git a/data/pythonlibs/uic/properties.py b/data/pythonlibs/uic/properties.py new file mode 100644 index 000000000..da8c472b3 --- /dev/null +++ b/data/pythonlibs/uic/properties.py @@ -0,0 +1,442 @@ +import logging +import sys + +from uic.exceptions import UnsupportedPropertyError +from uic.icon_cache import IconCache + +if sys.hexversion >= 0x03000000: + from uic.port_v3.ascii_upper import ascii_upper +else: + from uic.port_v2.ascii_upper import ascii_upper + + +logger = logging.getLogger(__name__) +DEBUG = logger.debug + +QtCore = None +QtGui = None + + +def int_list(prop): + return [int(child.text) for child in prop] + +def float_list(prop): + return [float(child.text) for child in prop] + +bool_ = lambda v: v == "true" + +def needsWidget(func): + func.needsWidget = True + return func + + +class Properties(object): + def __init__(self, factory, QtCore_mod, QtGui_mod): + global QtGui, QtCore + QtGui = QtGui_mod + QtCore = QtCore_mod + self.factory = factory + self.reset() + + def reset(self): + self.buddies = [] + self.delayed_props = [] + self.icon_cache = IconCache(self.factory, QtGui) + + def _pyEnumMember(self, cpp_name): + try: + prefix, membername = cpp_name.split("::") + DEBUG(membername) + if prefix == "Qt": + return getattr(QtCore.Qt, membername) + else: + return getattr(getattr(QtGui, prefix), membername) + except ValueError: + pass + + try: + return getattr(QtCore.Qt, cpp_name) + except AttributeError: + # There seems to be a bug where this can succeed when it shouldn't. + # If so it will be picked up when the generated code is run. + return getattr(getattr(QtGui, self.wclass), cpp_name) + + def _set(self, prop): + expr = [self._pyEnumMember(v) for v in prop.text.split('|')] + + value = expr[0] + for v in expr[1:]: + value |= v + + return value + + def _enum(self, prop): + return self._pyEnumMember(prop.text) + + def _number(self, prop): + return int(prop.text) + + _uInt = _longLong = _uLongLong = _number + + def _double(self, prop): + return float(prop.text) + + def _bool(self, prop): + return prop.text == 'true' + + def _stringlist(self, prop): + return [self._string(p, notr='true') for p in prop] + + def _string(self, prop, notr=None): + if prop.get('notr', notr) == 'true': + return self._cstring(prop) + + if prop.text is None: + return "" + + return QtGui.QApplication.translate(self.uiname, prop.text, None, + QtGui.QApplication.UnicodeUTF8) + + _char = _string + + def _cstring(self, prop): + return str(prop.text) + + def _color(self, prop): + args = int_list(prop) + + # Handle the optional alpha component. + alpha = int(prop.get("alpha", "255")) + + if alpha != 255: + args.append(alpha) + + return QtGui.QColor(*args) + + def _point(self, prop): + return QtCore.QPoint(*int_list(prop)) + + def _pointf(self, prop): + return QtCore.QPointF(*float_list(prop)) + + def _rect(self, prop): + return QtCore.QRect(*int_list(prop)) + + def _rectf(self, prop): + return QtCore.QRectF(*float_list(prop)) + + def _size(self, prop): + return QtCore.QSize(*int_list(prop)) + + def _sizef(self, prop): + return QtCore.QSizeF(*float_list(prop)) + + def _pixmap(self, prop): + if prop.text: + return QtGui.QPixmap(prop.text.replace("\\", "\\\\")) + + # Don't bother to set the property if the pixmap is empty. + return None + + def _iconset(self, prop): + return self.icon_cache.get_icon(prop) + + def _url(self, prop): + return QtCore.QUrl(prop[0].text) + + def _locale(self, prop): + lang = getattr(QtCore.QLocale, prop.attrib['language']) + country = getattr(QtCore.QLocale, prop.attrib['country']) + return QtCore.QLocale(lang, country) + + def _cursor(self, prop): + return QtGui.QCursor(QtCore.Qt.CursorShape(int(prop.text))) + + def _date(self, prop): + return QtCore.QDate(*int_list(prop)) + + def _datetime(self, prop): + args = int_list(prop) + return QtCore.QDateTime(QtCore.QDate(*args[-3:]), QtCore.QTime(*args[:-3])) + + def _time(self, prop): + return QtCore.QTime(*int_list(prop)) + + def _gradient(self, prop): + name = 'gradient' + + # Create the specific gradient. + gtype = prop.get('type', '') + + if gtype == 'LinearGradient': + startx = float(prop.get('startx')) + starty = float(prop.get('starty')) + endx = float(prop.get('endx')) + endy = float(prop.get('endy')) + gradient = self.factory.createQObject('QLinearGradient', name, + (startx, starty, endx, endy), is_attribute=False) + + elif gtype == 'ConicalGradient': + centralx = float(prop.get('centralx')) + centraly = float(prop.get('centraly')) + angle = float(prop.get('angle')) + gradient = self.factory.createQObject('QConicalGradient', name, + (centralx, centraly, angle), is_attribute=False) + + elif gtype == 'RadialGradient': + centralx = float(prop.get('centralx')) + centraly = float(prop.get('centraly')) + radius = float(prop.get('radius')) + focalx = float(prop.get('focalx')) + focaly = float(prop.get('focaly')) + gradient = self.factory.createQObject('QRadialGradient', name, + (centralx, centraly, radius, focalx, focaly), + is_attribute=False) + + else: + raise UnsupportedPropertyError(prop.tag) + + # Set the common values. + spread = prop.get('spread') + if spread: + gradient.setSpread(getattr(QtGui.QGradient, spread)) + + cmode = prop.get('coordinatemode') + if cmode: + gradient.setCoordinateMode(getattr(QtGui.QGradient, cmode)) + + # Get the gradient stops. + for gstop in prop: + if gstop.tag != 'gradientstop': + raise UnsupportedPropertyError(gstop.tag) + + position = float(gstop.get('position')) + color = self._color(gstop[0]) + + gradient.setColorAt(position, color) + + return name + + def _palette(self, prop): + palette = self.factory.createQObject("QPalette", "palette", (), + is_attribute=False) + + for palette_elem in prop: + sub_palette = getattr(QtGui.QPalette, palette_elem.tag.title()) + for role, color in enumerate(palette_elem): + if color.tag == 'color': + # Handle simple colour descriptions where the role is + # implied by the colour's position. + palette.setColor(sub_palette, + QtGui.QPalette.ColorRole(role), self._color(color)) + elif color.tag == 'colorrole': + role = getattr(QtGui.QPalette, color.get('role')) + + brushstyle = color[0].get('brushstyle') + if brushstyle in ('LinearGradientPattern', 'ConicalGradientPattern', 'RadialGradientPattern'): + gradient = self._gradient(color[0][0]) + brush = self.factory.createQObject("QBrush", "brush", + (gradient, ), is_attribute=False) + else: + color = self._color(color[0][0]) + brush = self.factory.createQObject("QBrush", "brush", + (color, ), is_attribute=False) + + brushstyle = getattr(QtCore.Qt, brushstyle) + brush.setStyle(brushstyle) + + palette.setBrush(sub_palette, role, brush) + else: + raise UnsupportedPropertyError(color.tag) + + return palette + + #@needsWidget + def _sizepolicy(self, prop, widget): + values = [int(child.text) for child in prop] + + if len(values) == 2: + # Qt v4.3.0 and later. + horstretch, verstretch = values + hsizetype = getattr(QtGui.QSizePolicy, prop.get('hsizetype')) + vsizetype = getattr(QtGui.QSizePolicy, prop.get('vsizetype')) + else: + hsizetype, vsizetype, horstretch, verstretch = values + hsizetype = QtGui.QSizePolicy.Policy(hsizetype) + vsizetype = QtGui.QSizePolicy.Policy(vsizetype) + + sizePolicy = self.factory.createQObject("QSizePolicy", "sizePolicy", + (hsizetype, vsizetype), is_attribute=False) + sizePolicy.setHorizontalStretch(horstretch) + sizePolicy.setVerticalStretch(verstretch) + sizePolicy.setHeightForWidth(widget.sizePolicy.hasHeightForWidth()) + return sizePolicy + _sizepolicy = needsWidget(_sizepolicy) + + # font needs special handling/conversion of all child elements. + _font_attributes = (("Family", str), + ("PointSize", int), + ("Weight", int), + ("Italic", bool_), + ("Underline", bool_), + ("StrikeOut", bool_), + ("Bold", bool_)) + + def _font(self, prop): + newfont = self.factory.createQObject("QFont", "font", (), + is_attribute = False) + for attr, converter in self._font_attributes: + v = prop.findtext("./%s" % (attr.lower(),)) + if v is None: + continue + + getattr(newfont, "set%s" % (attr,))(converter(v)) + return newfont + + def _cursorShape(self, prop): + return getattr(QtCore.Qt, prop.text) + + def convert(self, prop, widget=None): + try: + func = getattr(self, "_" + prop[0].tag) + except AttributeError: + raise UnsupportedPropertyError(prop[0].tag) + else: + args = {} + if getattr(func, "needsWidget", False): + assert widget is not None + args["widget"] = widget + + return func(prop[0], **args) + + + def _getChild(self, elem_tag, elem, name, default=None): + for prop in elem.findall(elem_tag): + if prop.attrib["name"] == name: + return self.convert(prop) + else: + return default + + def getProperty(self, elem, name, default=None): + return self._getChild("property", elem, name, default) + + def getAttribute(self, elem, name, default=None): + return self._getChild("attribute", elem, name, default) + + def setProperties(self, widget, elem): + try: + self.wclass = elem.attrib["class"] + except KeyError: + pass + for prop in elem.findall("property"): + prop_name = prop.attrib["name"] + DEBUG("setting property %s" % (prop_name,)) + + try: + stdset = bool(int(prop.attrib["stdset"])) + except KeyError: + stdset = True + + if not stdset: + self._setViaSetProperty(widget, prop) + elif hasattr(self, prop_name): + getattr(self, prop_name)(widget, prop) + else: + prop_value = self.convert(prop, widget) + if prop_value is not None: + getattr(widget, "set%s%s" % (ascii_upper(prop_name[0]), prop_name[1:]))(prop_value) + + # SPECIAL PROPERTIES + # If a property has a well-known value type but needs special, + # context-dependent handling, the default behaviour can be overridden here. + + # Delayed properties will be set after the whole widget tree has been + # populated. + def _delay(self, widget, prop): + prop_value = self.convert(prop) + if prop_value is not None: + prop_name = prop.attrib["name"] + self.delayed_props.append(( + getattr(widget, "set%s%s" % (ascii_upper(prop_name[0]), prop_name[1:])), + prop_value)) + + # These properties will be set with a widget.setProperty call rather than + # calling the set function. + def _setViaSetProperty(self, widget, prop): + prop_value = self.convert(prop) + if prop_value is not None: + widget.setProperty(prop.attrib["name"], prop_value) + + # Ignore the property. + def _ignore(self, widget, prop): + pass + + # Define properties that use the canned handlers. + currentIndex = _delay + currentRow = _delay + + showDropIndicator = _setViaSetProperty + intValue = _setViaSetProperty + value = _setViaSetProperty + + objectName = _ignore + leftMargin = _ignore + topMargin = _ignore + rightMargin = _ignore + bottomMargin = _ignore + horizontalSpacing = _ignore + verticalSpacing = _ignore + + # buddy setting has to be done after the whole widget tree has been + # populated. We can't use delay here because we cannot get the actual + # buddy yet. + def buddy(self, widget, prop): + buddy_name = prop[0].text + if buddy_name: + self.buddies.append((widget, buddy_name)) + + # geometry is handled specially if set on the toplevel widget. + def geometry(self, widget, prop): + if widget.objectName == self.uiname: + geom = int_list(prop[0]) + widget.resize(geom[2], geom[3]) + else: + widget.setGeometry(self._rect(prop[0])) + + def orientation(self, widget, prop): + # If the class is a QFrame, it's a line. + if widget.className() == "QFrame": + widget.setFrameShape( + {"Qt::Horizontal": QtGui.QFrame.HLine, + "Qt::Vertical" : QtGui.QFrame.VLine}[prop[0].text]) + + # In Qt Designer, lines appear to be sunken, QFormBuilder loads + # them as such, uic generates plain lines. We stick to the look in + # Qt Designer. + widget.setFrameShadow(QtGui.QFrame.Sunken) + else: + widget.setOrientation(self._enum(prop[0])) + + # The isWrapping attribute of QListView is named inconsistently, it should + # be wrapping. + def isWrapping(self, widget, prop): + widget.setWrapping(self.convert(prop)) + + # This is a pseudo-property injected to deal with setContentsMargin() + # introduced in Qt v4.3. + def pyuicContentsMargins(self, widget, prop): + widget.setContentsMargins(*int_list(prop)) + + # This is a pseudo-property injected to deal with setHorizontalSpacing() + # and setVerticalSpacing() introduced in Qt v4.3. + def pyuicSpacing(self, widget, prop): + horiz, vert = int_list(prop) + + if horiz == vert: + widget.setSpacing(horiz) + else: + if horiz >= 0: + widget.setHorizontalSpacing(horiz) + + if vert >= 0: + widget.setVerticalSpacing(vert) diff --git a/data/pythonlibs/uic/uiparser.py b/data/pythonlibs/uic/uiparser.py new file mode 100644 index 000000000..f991a4fc4 --- /dev/null +++ b/data/pythonlibs/uic/uiparser.py @@ -0,0 +1,819 @@ +import sys +import logging +import os.path +import re + +try: + from xml.etree.ElementTree import parse, SubElement +except ImportError: + try: + from ElementTree import parse, SubElement + except ImportError: + from elementtree.ElementTree import parse, SubElement + +from uic.exceptions import NoSuchWidgetError +from uic.objcreator import QObjectCreator +from uic.properties import Properties + + +logger = logging.getLogger(__name__) +DEBUG = logger.debug + +if sys.version_info < (2,4,0): + def reversed(seq): + for i in xrange(len(seq)-1, -1, -1): + yield seq[i] + +QtCore = None +QtGui = None + + +def gridPosition(elem): + """gridPosition(elem) -> tuple + + Return the 4-tuple of (row, column, rowspan, colspan) + for a widget element, or an empty tuple. + """ + try: + return (int(elem.attrib["row"]), + int(elem.attrib["column"]), + int(elem.attrib.get("rowspan", 1)), + int(elem.attrib.get("colspan", 1))) + except KeyError: + return () + + +class WidgetStack(list): + topwidget = None + def push(self, item): + DEBUG("push %s %s" % (item.className(), + item.objectName)) + self.append(item) + if item.inherits("QWidget"): + self.topwidget = item + + def popLayout(self): + layout = list.pop(self) + DEBUG("pop layout %s %s" % (layout.className(), + layout.objectName)) + return layout + + def popWidget(self): + widget = list.pop(self) + DEBUG("pop widget %s %s" % (widget.className(), + widget.objectName)) + for item in reversed(self): + if item.inherits("QWidget"): + self.topwidget = item + break + else: + self.topwidget = None + DEBUG("new topwidget %s" % (self.topwidget,)) + return widget + + def peek(self): + return self[-1] + + def topIsLayout(self): + return self[-1].inherits("QLayout") + + +class UIParser(object): + def __init__(self, QtCoreModule, QtGuiModule, creatorPolicy): + self.factory = QObjectCreator(creatorPolicy) + self.wprops = Properties(self.factory, QtCoreModule, QtGuiModule) + + global QtCore, QtGui + QtCore = QtCoreModule + QtGui = QtGuiModule + + self.reset() + + def uniqueName(self, name): + """UIParser.uniqueName(string) -> string + + Create a unique name from a string. + >>> p = UIParser(QtCore, QtGui) + >>> p.uniqueName("foo") + 'foo' + >>> p.uniqueName("foo") + 'foo1' + """ + try: + suffix = self.name_suffixes[name] + except KeyError: + self.name_suffixes[name] = 0 + return name + + suffix += 1 + self.name_suffixes[name] = suffix + + return "%s%i" % (name, suffix) + + def reset(self): + try: self.wprops.reset() + except AttributeError: pass + self.toplevelWidget = None + self.stack = WidgetStack() + self.name_suffixes = {} + self.defaults = {"spacing": 6, "margin": 0} + self.actions = [] + self.currentActionGroup = None + self.resources = [] + self.button_groups = [] + self.item_nr = 0 + + def setupObject(self, clsname, parent, branch, is_attribute = True): + name = self.uniqueName(branch.attrib.get("name") or clsname[1:].lower()) + if parent is None: + args = () + else: + args = (parent, ) + obj = self.factory.createQObject(clsname, name, args, is_attribute) + self.wprops.setProperties(obj, branch) + obj.setObjectName(name) + if is_attribute: + setattr(self.toplevelWidget, name, obj) + return obj + + def createWidget(self, elem): + def widgetClass(elem): + cls = elem.attrib["class"].replace('::', '.') + if cls == "Line": + return "QFrame" + else: + return cls + + self.column_counter = 0 + self.row_counter = 0 + self.item_nr = 0 + self.itemstack = [] + self.sorting_enabled = None + + parent = self.stack.topwidget + for class_name in ["QToolBox", "QTabWidget", "QStackedWidget", + "QDockWidget", "QWizard"]: + if parent.inherits(class_name): + parent = None + break + + self.stack.push(self.setupObject(widgetClass(elem), parent, elem)) + + if self.stack.topwidget.inherits("QTableWidget"): + self.stack.topwidget.setColumnCount(len(elem.findall("column"))) + self.stack.topwidget.setRowCount(len(elem.findall("row"))) + + self.traverseWidgetTree(elem) + widget = self.stack.popWidget() + + if widget.inherits("QTreeView"): + self.handleHeaderView(elem, "header", widget.header()) + + elif widget.inherits("QTableView"): + self.handleHeaderView(elem, "horizontalHeader", + widget.horizontalHeader()) + self.handleHeaderView(elem, "verticalHeader", + widget.verticalHeader()) + + elif widget.inherits("QAbstractButton"): + bg_i18n = self.wprops.getAttribute(elem, "buttonGroup") + if bg_i18n is not None: + bg_name = str(bg_i18n) + + for bg in self.button_groups: + if bg.objectName == bg_name: + break + else: + bg = self.factory.createQObject("QButtonGroup", bg_name, + (self.toplevelWidget, )) + bg.setObjectName(bg_name) + self.button_groups.append(bg) + + bg.addButton(widget) + + if self.sorting_enabled is not None: + widget.setSortingEnabled(self.sorting_enabled) + self.sorting_enabled = None + + if self.stack.topIsLayout(): + lay = self.stack.peek() + gp = elem.attrib["grid-position"] + + if lay.inherits("QFormLayout"): + if gp[1]: + role = QtGui.QFormLayout.FieldRole + else: + role = QtGui.QFormLayout.LabelRole + + lay.setWidget(gp[0], role, widget) + else: + lay.addWidget(widget, *gp) + + topwidget = self.stack.topwidget + + if topwidget.inherits("QToolBox"): + icon = self.wprops.getAttribute(elem, "icon") + if icon is not None: + topwidget.addItem(widget, icon, self.wprops.getAttribute(elem, "label")) + else: + topwidget.addItem(widget, self.wprops.getAttribute(elem, "label")) + + tooltip = self.wprops.getAttribute(elem, "toolTip") + if tooltip is not None: + topwidget.setItemToolTip(topwidget.indexOf(widget), tooltip) + + elif topwidget.inherits("QTabWidget"): + icon = self.wprops.getAttribute(elem, "icon") + if icon is not None: + topwidget.addTab(widget, icon, self.wprops.getAttribute(elem, "title")) + else: + topwidget.addTab(widget, self.wprops.getAttribute(elem, "title")) + + tooltip = self.wprops.getAttribute(elem, "toolTip") + if tooltip is not None: + topwidget.setTabToolTip(topwidget.indexOf(widget), tooltip) + + elif topwidget.inherits("QWizard"): + topwidget.addPage(widget) + + elif topwidget.inherits("QStackedWidget"): + topwidget.addWidget(widget) + + elif topwidget.inherits("QDockWidget") or topwidget.inherits("QScrollArea"): + topwidget.setWidget(widget) + + elif topwidget.inherits("QMainWindow"): + if type(widget) == QtGui.QWidget: + topwidget.setCentralWidget(widget) + elif widget.inherits("QToolBar"): + tbArea = self.wprops.getAttribute(elem, "toolBarArea") + + if tbArea is None: + topwidget.addToolBar(widget) + else: + if isinstance(tbArea, str) or isinstance(tbArea, unicode): + tbArea = getattr(QtCore.Qt, tbArea) + else: + tbArea = QtCore.Qt.ToolBarArea(tbArea) + + topwidget.addToolBar(tbArea, widget) + + tbBreak = self.wprops.getAttribute(elem, "toolBarBreak") + + if tbBreak: + topwidget.insertToolBarBreak(widget) + + elif widget.inherits("QMenuBar"): + topwidget.setMenuBar(widget) + elif widget.inherits("QStatusBar"): + topwidget.setStatusBar(widget) + elif widget.inherits("QDockWidget"): + dwArea = self.wprops.getAttribute(elem, "dockWidgetArea") + topwidget.addDockWidget(QtCore.Qt.DockWidgetArea(dwArea), + widget) + + def handleHeaderView(self, elem, name, header): + value = self.wprops.getAttribute(elem, name + "Visible") + if value is not None: + header.setVisible(value) + + value = self.wprops.getAttribute(elem, name + "CascadingSectionResizes") + if value is not None: + header.setCascadingSectionResizes(value) + + value = self.wprops.getAttribute(elem, name + "DefaultSectionSize") + if value is not None: + header.setDefaultSectionSize(value) + + value = self.wprops.getAttribute(elem, name + "HighlightSections") + if value is not None: + header.setHighlightSections(value) + + value = self.wprops.getAttribute(elem, name + "MinimumSectionSize") + if value is not None: + header.setMinimumSectionSize(value) + + value = self.wprops.getAttribute(elem, name + "ShowSortIndicator") + if value is not None: + header.setSortIndicatorShown(value) + + value = self.wprops.getAttribute(elem, name + "StretchLastSection") + if value is not None: + header.setStretchLastSection(value) + + def createSpacer(self, elem): + width = int(elem.findtext("property/size/width")) + height = int(elem.findtext("property/size/height")) + + sizeType = self.wprops.getProperty(elem, "sizeType", + QtGui.QSizePolicy.Expanding) + + policy = (QtGui.QSizePolicy.Minimum, sizeType) + + if self.wprops.getProperty(elem, "orientation") == QtCore.Qt.Horizontal: + policy = policy[1], policy[0] + + name = self.uniqueName("spacerItem") + spacer = self.factory.createQObject("QSpacerItem", + name, (width, height) + policy, + is_attribute=False) + + if self.stack.topIsLayout(): + lay = self.stack.peek() + gp = elem.attrib["grid-position"] + + if lay.inherits("QFormLayout"): + if gp[1]: + role = QtGui.QFormLayout.FieldRole + else: + role = QtGui.QFormLayout.LabelRole + + lay.setItem(gp[0], role, spacer) + else: + lay.addItem(spacer, *gp) + + # Must keep a reference to the spacer otherwise it'll go out of scope + # and cause a crash. + setattr(self.toplevelWidget, name, spacer) + + def createLayout(self, elem): + # Qt v4.3 introduced setContentsMargins() and separate values for each + # of the four margins which are specified as separate properties. This + # doesn't really fit the way we parse the tree (why aren't the values + # passed as attributes of a single property?) so we create a new + # property and inject it. However, if we find that they have all been + # specified and have the same value then we inject a different property + # that is compatible with older versions of Qt. + left = self.wprops.getProperty(elem, 'leftMargin', -1) + top = self.wprops.getProperty(elem, 'topMargin', -1) + right = self.wprops.getProperty(elem, 'rightMargin', -1) + bottom = self.wprops.getProperty(elem, 'bottomMargin', -1) + + # Count the number of properties and if they had the same value. + def comp_property(m, so_far=-2, nr=0): + if m >= 0: + nr += 1 + + if so_far == -2: + so_far = m + elif so_far != m: + so_far = -1 + + return so_far, nr + + margin, nr_margins = comp_property(left) + margin, nr_margins = comp_property(top, margin, nr_margins) + margin, nr_margins = comp_property(right, margin, nr_margins) + margin, nr_margins = comp_property(bottom, margin, nr_margins) + + if nr_margins > 0: + if nr_margins == 4 and margin >= 0: + # We can inject the old margin property. + me = SubElement(elem, 'property', name='margin') + SubElement(me, 'number').text = str(margin) + else: + # We have to inject the new internal property. + cme = SubElement(elem, 'property', name='pyuicContentsMargins') + SubElement(cme, 'number').text = str(left) + SubElement(cme, 'number').text = str(top) + SubElement(cme, 'number').text = str(right) + SubElement(cme, 'number').text = str(bottom) + + # We do the same for setHorizontalSpacing() and setVerticalSpacing(). + horiz = self.wprops.getProperty(elem, 'horizontalSpacing', -1) + vert = self.wprops.getProperty(elem, 'verticalSpacing', -1) + + if horiz >= 0 or vert >= 0: + # We inject the new internal property. + cme = SubElement(elem, 'property', name='pyuicSpacing') + SubElement(cme, 'number').text = str(horiz) + SubElement(cme, 'number').text = str(vert) + + classname = elem.attrib["class"] + if self.stack.topIsLayout(): + parent = None + else: + parent = self.stack.topwidget + if "name" not in elem.attrib: + elem.attrib["name"] = classname[1:].lower() + self.stack.push(self.setupObject(classname, parent, elem)) + self.traverseWidgetTree(elem) + + layout = self.stack.popLayout() + if self.stack.topIsLayout(): + top_layout = self.stack.peek() + gp = elem.attrib["grid-position"] + + if top_layout.inherits("QFormLayout"): + if gp[1]: + role = QtGui.QFormLayout.FieldRole + else: + role = QtGui.QFormLayout.LabelRole + + top_layout.setLayout(gp[0], role, layout) + else: + self.configureLayout(elem, layout) + top_layout.addLayout(layout, *gp) + else: + self.configureLayout(elem, layout) + + def configureLayout(self, elem, layout): + if layout.inherits("QGridLayout"): + self.setArray(elem, 'columnminimumwidth', + layout.setColumnMinimumWidth) + self.setArray(elem, 'rowminimumheight', + layout.setRowMinimumHeight) + self.setArray(elem, 'columnstretch', layout.setColumnStretch) + self.setArray(elem, 'rowstretch', layout.setRowStretch) + + elif layout.inherits("QBoxLayout"): + self.setArray(elem, 'stretch', layout.setStretch) + + def setArray(self, elem, name, setter): + array = elem.attrib.get(name) + if array: + for idx, value in enumerate(array.split(',')): + value = int(value) + if value > 0: + setter(idx, value) + + def handleItem(self, elem): + if self.stack.topIsLayout(): + elem[0].attrib["grid-position"] = gridPosition(elem) + self.traverseWidgetTree(elem) + else: + + w = self.stack.topwidget + + if w.inherits("QComboBox"): + text = self.wprops.getProperty(elem, "text") + icon = self.wprops.getProperty(elem, "icon") + + if icon: + w.addItem(icon, '') + else: + w.addItem('') + + w.setItemText(self.item_nr, text) + + elif w.inherits("QListWidget"): + text = self.wprops.getProperty(elem, "text") + icon = self.wprops.getProperty(elem, "icon") + flags = self.wprops.getProperty(elem, "flags") + check_state = self.wprops.getProperty(elem, "checkState") + + if icon or flags or check_state: + item_name = "item" + else: + item_name = None + + item = self.factory.createQObject("QListWidgetItem", item_name, + (w, ), False) + + if self.item_nr == 0: + self.sorting_enabled = self.factory.invoke("__sortingEnabled", w.isSortingEnabled) + w.setSortingEnabled(False) + + if text: + w.item(self.item_nr).setText(text) + + if icon: + item.setIcon(icon) + + if flags: + item.setFlags(flags) + + if check_state: + item.setCheckState(check_state) + + elif w.inherits("QTreeWidget"): + if self.itemstack: + parent, _ = self.itemstack[-1] + _, nr_in_root = self.itemstack[0] + else: + parent = w + nr_in_root = self.item_nr + + item = self.factory.createQObject("QTreeWidgetItem", + "item_%d" % len(self.itemstack), (parent, ), False) + + if self.item_nr == 0 and not self.itemstack: + self.sorting_enabled = self.factory.invoke("__sortingEnabled", w.isSortingEnabled) + w.setSortingEnabled(False) + + self.itemstack.append((item, self.item_nr)) + self.item_nr = 0 + + # We have to access the item via the tree when setting the + # text. + titm = w.topLevelItem(nr_in_root) + for child, nr_in_parent in self.itemstack[1:]: + titm = titm.child(nr_in_parent) + + column = -1 + for prop in elem.findall("property"): + c_prop = self.wprops.convert(prop) + c_prop_name = prop.attrib["name"] + + if c_prop_name == "text": + column += 1 + if c_prop: + titm.setText(column, c_prop) + elif c_prop_name == "icon": + item.setIcon(column, c_prop) + elif c_prop_name == "flags": + item.setFlags(c_prop) + elif c_prop_name == "checkState": + item.setCheckState(column, c_prop) + + self.traverseWidgetTree(elem) + _, self.item_nr = self.itemstack.pop() + + elif w.inherits("QTableWidget"): + text = self.wprops.getProperty(elem, "text") + icon = self.wprops.getProperty(elem, "icon") + flags = self.wprops.getProperty(elem, "flags") + check_state = self.wprops.getProperty(elem, "checkState") + + item = self.factory.createQObject("QTableWidgetItem", "item", + (), False) + + if self.item_nr == 0: + self.sorting_enabled = self.factory.invoke("__sortingEnabled", w.isSortingEnabled) + w.setSortingEnabled(False) + + row = int(elem.attrib["row"]) + col = int(elem.attrib["column"]) + + if text: + w.item(row, col).setText(text) + + if icon: + item.setIcon(icon) + + if flags: + item.setFlags(flags) + + if check_state: + item.setCheckState(check_state) + + w.setItem(row, col, item) + + self.item_nr += 1 + + def addAction(self, elem): + self.actions.append((self.stack.topwidget, elem.attrib["name"])) + + def addHeader(self, elem): + w = self.stack.topwidget + + if w.inherits("QTreeWidget"): + text = self.wprops.getProperty(elem, "text") + icon = self.wprops.getProperty(elem, "icon") + + if text: + w.headerItem().setText(self.column_counter, text) + + if icon: + w.headerItem().setIcon(self.column_counter, icon) + + self.column_counter += 1 + + elif w.inherits("QTableWidget"): + if len(elem) == 0: + return + + text = self.wprops.getProperty(elem, "text") + icon = self.wprops.getProperty(elem, "icon") + + item = self.factory.createQObject("QTableWidgetItem", "item", + (), False) + + if elem.tag == "column": + w.setHorizontalHeaderItem(self.column_counter, item) + + if text: + w.horizontalHeaderItem(self.column_counter).setText(text) + + if icon: + item.setIcon(icon) + + self.column_counter += 1 + elif elem.tag == "row": + w.setVerticalHeaderItem(self.row_counter, item) + + if text: + w.verticalHeaderItem(self.row_counter).setText(text) + + if icon: + item.setIcon(icon) + + self.row_counter += 1 + + def createAction(self, elem): + self.setupObject("QAction", self.currentActionGroup or self.toplevelWidget, + elem) + + def createActionGroup(self, elem): + action_group = self.setupObject("QActionGroup", self.toplevelWidget, elem) + self.currentActionGroup = action_group + self.traverseWidgetTree(elem) + self.currentActionGroup = None + + widgetTreeItemHandlers = { + "widget" : createWidget, + "addaction" : addAction, + "layout" : createLayout, + "spacer" : createSpacer, + "item" : handleItem, + "action" : createAction, + "actiongroup": createActionGroup, + "column" : addHeader, + "row" : addHeader, + } + + def traverseWidgetTree(self, elem): + for child in iter(elem): + try: + handler = self.widgetTreeItemHandlers[child.tag] + except KeyError: + continue + + handler(self, child) + + def createUserInterface(self, elem): + # Get the names of the class and widget. + cname = elem.attrib["class"] + wname = elem.attrib["name"] + + # If there was no widget name then derive it from the class name. + if not wname: + wname = cname + + if wname.startswith("Q"): + wname = wname[1:] + + wname = wname[0].lower() + wname[1:] + + self.toplevelWidget = self.createToplevelWidget(cname, wname) + self.toplevelWidget.setObjectName(wname) + DEBUG("toplevel widget is %s", + self.toplevelWidget.className()) + self.wprops.setProperties(self.toplevelWidget, elem) + self.stack.push(self.toplevelWidget) + self.traverseWidgetTree(elem) + self.stack.popWidget() + self.addActions() + self.setBuddies() + self.setDelayedProps() + + def addActions(self): + for widget, action_name in self.actions: + if action_name == "separator": + widget.addSeparator() + else: + DEBUG("add action %s to %s", action_name, widget.objectName) + action_obj = getattr(self.toplevelWidget, action_name) + if action_obj.inherits("QMenu"): + widget.addAction(action_obj.menuAction()) + elif not action_obj.inherits("QActionGroup"): + widget.addAction(action_obj) + + def setDelayedProps(self): + for func, args in self.wprops.delayed_props: + func(args) + + def setBuddies(self): + for widget, buddy in self.wprops.buddies: + DEBUG("%s is buddy of %s", buddy, widget.objectName) + try: + widget.setBuddy(getattr(self.toplevelWidget, buddy)) + except AttributeError: + DEBUG("ERROR in ui spec: %s (buddy of %s) does not exist", + buddy, widget.objectName) + + def classname(self, elem): + DEBUG("uiname is %s", elem.text) + name = elem.text + + if name is None: + name = "" + + self.uiname = name + self.wprops.uiname = name + self.setContext(name) + + def setContext(self, context): + """ + Reimplemented by a sub-class if it needs to know the translation + context. + """ + pass + + def readDefaults(self, elem): + self.defaults["margin"] = int(elem.attrib["margin"]) + self.defaults["spacing"] = int(elem.attrib["spacing"]) + + def setTaborder(self, elem): + lastwidget = None + for widget_elem in elem: + widget = getattr(self.toplevelWidget, widget_elem.text) + + if lastwidget is not None: + self.toplevelWidget.setTabOrder(lastwidget, widget) + + lastwidget = widget + + def readResources(self, elem): + """ + Read a "resources" tag and add the module to import to the parser's + list of them. + """ + for include in elem.getiterator("include"): + loc = include.attrib.get("location") + + # Assume our convention for naming the Python files generated by + # pyrcc4. + if loc and loc.endswith('.qrc'): + self.resources.append(os.path.basename(loc[:-4] + '_rc')) + + def createConnections(self, elem): + def name2object(obj): + if obj == self.uiname: + return self.toplevelWidget + else: + return getattr(self.toplevelWidget, obj) + for conn in iter(elem): + name2object(conn.findtext("sender")).connect( + conn.findtext("signal"), + name2object(conn.findtext("receiver")), + conn.findtext("slot")) + + def customWidgets(self, elem): + def header2module(header): + """header2module(header) -> string + + Convert paths to C++ header files to according Python modules + >>> header2module("foo/bar/baz.h") + 'foo.bar.baz' + """ + if header.endswith(".h"): + header = header[:-2] + + mpath = [] + for part in header.split('/'): + # Ignore any empty parts or those that refer to the current + # directory. + if part not in ('', '.'): + if part == '..': + # We should allow this for Python3. + raise SyntaxError("custom widget header file name may not contain '..'.") + + mpath.append(part) + + return '.'.join(mpath) + + for custom_widget in iter(elem): + classname = custom_widget.findtext("class") + if classname.startswith("Q3"): + raise NoSuchWidgetError(classname) + self.factory.addCustomWidget(classname, + custom_widget.findtext("extends") or "QWidget", + header2module(custom_widget.findtext("header"))) + + def createToplevelWidget(self, classname, widgetname): + raise NotImplementedError + + # finalize will be called after the whole tree has been parsed and can be + # overridden. + def finalize(self): + pass + + def parse(self, filename): + # the order in which the different branches are handled is important + # the widget tree handler relies on all custom widgets being known, + # and in order to create the connections, all widgets have to be populated + branchHandlers = ( + ("layoutdefault", self.readDefaults), + ("class", self.classname), + ("customwidgets", self.customWidgets), + ("widget", self.createUserInterface), + ("connections", self.createConnections), + ("tabstops", self.setTaborder), + ("resources", self.readResources), + ) + + document = parse(filename) + version = document.getroot().attrib["version"] + DEBUG("UI version is %s" % (version,)) + # Right now, only version 4.0 is supported, which is used up to at + # least Qt 4.4. + assert version in ("4.0",) + for tagname, actor in branchHandlers: + elem = document.find(tagname) + if elem is not None: + actor(elem) + self.finalize() + w = self.toplevelWidget + self.reset() + return w diff --git a/data/pythonstartup.py b/data/pythonstartup.py deleted file mode 100644 index 2345b0d26..000000000 --- a/data/pythonstartup.py +++ /dev/null @@ -1,29 +0,0 @@ -import clementine -import sys - - -class __ClementineLogger__: - def __init__(self, error): - self._error = error - self._buffer = '' - - def write(self, data): - self._buffer = self._buffer + data - i = self._buffer.find('\n') - while i != -1: - line = self._buffer[0:i] - self._buffer = self._buffer[i+1:] - i = self._buffer.find('\n') - - clementine.pythonengine.AddLogLine(line, self._error) - -sys.stdout = __ClementineLogger__(False) -sys.stderr = __ClementineLogger__(True) - - -# Hack StackedWidget -> QStackedWidget to work around bug in PyQt 4.8.2 -try: - import PyQt4.QtGui - PyQt4.QtGui.StackedWidget = PyQt4.QtGui.QStackedWidget -except: - pass diff --git a/scripts/digitallyimported-radio/settingsdialog.py b/scripts/digitallyimported-radio/settingsdialog.py index 4584f55b2..e17af8e36 100644 --- a/scripts/digitallyimported-radio/settingsdialog.py +++ b/scripts/digitallyimported-radio/settingsdialog.py @@ -1,59 +1,39 @@ from servicebase import DigitallyImportedServiceBase -from PythonQt.QtCore import QEvent, QFile, QObject, QSettings +from PythonQt.QtCore import QEvent, QFile, QSettings from PythonQt.QtGui import QComboBox, QDialog, QIcon, QLineEdit -from PythonQt.QtUiTools import QUiLoader +import uic import os.path -class SettingsDialog(QObject): +class SettingsDialog(QDialog): def __init__(self, parent=None): - QObject.__init__(self, parent) + QDialog.__init__(self, parent) self.path = os.path.dirname(__file__) # Set up the user interface - ui_filename = os.path.join(self.path, "settingsdialog.ui") - ui_file = QFile(ui_filename) - if not ui_file.open(QFile.ReadOnly): - raise IOError(ui_file) - - loader = QUiLoader() - self.dialog = loader.load(ui_file) - - # Get the widgets from the dialog so we can use them later - self.type = self.dialog.findChild(QComboBox, "type") - self.username = self.dialog.findChild(QLineEdit, "username") - self.password = self.dialog.findChild(QLineEdit, "password") - - # Install ourselves as an event filter on the dialog so we can see when - # it gets shown - self.dialog.installEventFilter(self) - - # Connect to the accepted signal so we can save settings when the user - # clicks OK - self.dialog.connect("accepted()", self.SaveSettings) + uic.loadUi(os.path.join(self.path, "settingsdialog.ui"), self) # Set the window icon - self.dialog.setWindowIcon(QIcon(os.path.join(self.path, "icon-small.png"))) + self.setWindowIcon(QIcon(os.path.join(self.path, "icon-small.png"))) - def eventFilter(self, obj, event): - if obj == self.dialog: - if event.type() == QEvent.Show: - self.LoadSettings() - - QObject.eventFilter(self, obj, event) - - def LoadSettings(self): + def showEvent(self, event): + # Load the settings settings = QSettings() settings.beginGroup(DigitallyImportedServiceBase.SETTINGS_GROUP) self.type.setCurrentIndex(int(settings.value("audio_type", 0))) self.username.setText(settings.value("username", "")) self.password.setText(settings.value("password", "")) - def SaveSettings(self): + QDialog.showEvent(self, event) + + def accept(self): + # Save the settings settings = QSettings() settings.beginGroup(DigitallyImportedServiceBase.SETTINGS_GROUP) settings.setValue("audio_type", self.type.currentIndex) settings.setValue("username", self.username.text) settings.setValue("password", self.password.text) + + QDialog.done(self, QDialog.Accepted) diff --git a/src/scripting/python/objectdecorators.cpp b/src/scripting/python/objectdecorators.cpp index cf7a74a0d..5deecfbed 100644 --- a/src/scripting/python/objectdecorators.cpp +++ b/src/scripting/python/objectdecorators.cpp @@ -20,3 +20,7 @@ void ObjectDecorators::deleteLater(QObject* self) { self->deleteLater(); } + +bool ObjectDecorators::inherits(QObject* self, const char* class_name) { + return self->inherits(class_name); +} diff --git a/src/scripting/python/objectdecorators.h b/src/scripting/python/objectdecorators.h index 62421129a..adfce90b6 100644 --- a/src/scripting/python/objectdecorators.h +++ b/src/scripting/python/objectdecorators.h @@ -25,6 +25,7 @@ class ObjectDecorators : public QObject { public slots: void deleteLater(QObject* self); + bool inherits(QObject* self, const char* class_name); }; #endif // OBJECTDECORATORS_H diff --git a/src/scripting/python/pythonengine.cpp b/src/scripting/python/pythonengine.cpp index 2cdde8948..536e071af 100644 --- a/src/scripting/python/pythonengine.cpp +++ b/src/scripting/python/pythonengine.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include "objectdecorators.h" #include "pythonengine.h" @@ -83,11 +82,11 @@ bool PythonEngine::EnsureInitialised() { PythonQt_init_QtCore(0); PythonQt_init_QtGui(0); PythonQt_init_QtNetwork(0); - PythonQt_init_QtUiTools(0); PythonQt* python_qt = PythonQt::self(); python_qt->installDefaultImporter(); python_qt->addDecorators(new ObjectDecorators); + python_qt->addSysPath(":/pythonlibs/"); PythonQtConv::registerMetaTypeToPythonConverter(qMetaTypeId(), PythonQtConvertListOfValueTypeToPythonList);