diff options
author | Renato Filho <renato.filho@openbossa.org> | 2010-07-06 18:44:00 -0300 |
---|---|---|
committer | Renato Filho <renato.filho@openbossa.org> | 2010-07-08 11:27:38 -0300 |
commit | 1c4ee915c07daae9919e890072593b51e54c9aec (patch) | |
tree | 19424c508a942a202711fe65530894c10aaa7282 /libpyside | |
parent | 693ae6d6c4073a483524af48e7a1a0ad1fba1131 (diff) |
Implemented support to properties on QMetaObject.
Reviewer: Hugo Parente Lima <hugo.lima@openbossa.org>,
Luciano Wolf <luciano.wolf@openbossa.org>
Diffstat (limited to 'libpyside')
-rw-r--r-- | libpyside/CMakeLists.txt | 2 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 242 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.h | 21 | ||||
-rw-r--r-- | libpyside/pyside.cpp | 3 | ||||
-rw-r--r-- | libpyside/qproperty.cpp | 318 | ||||
-rw-r--r-- | libpyside/qproperty.h | 187 | ||||
-rw-r--r-- | libpyside/qsignal.cpp | 5 | ||||
-rw-r--r-- | libpyside/signalmanager.cpp | 83 | ||||
-rw-r--r-- | libpyside/signalmanager.h | 2 |
9 files changed, 830 insertions, 33 deletions
diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt index efbe1f2b5..57ecb8013 100644 --- a/libpyside/CMakeLists.txt +++ b/libpyside/CMakeLists.txt @@ -6,6 +6,7 @@ signalmanager.cpp globalreceiver.cpp qsignal.cpp qslot.cpp +qproperty.cpp pyside.cpp ) @@ -36,6 +37,7 @@ set(libpyside_HEADERS signalmanager.h pyside.h qsignal.h + qproperty.h ) # create pkg-config file diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index 562f2d476..8f97b567e 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -43,11 +43,36 @@ #include <QMetaMethod> #include "qsignal.h" +#include "qproperty.h" #define MAX_SIGNALS_COUNT 50 +#define MAX_SLOTS_COUNT 50 using namespace PySide; +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Constant = 0x00000400, + Final = 0x00000800, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000 +}; + static int registerString(const QByteArray& s, QList<QByteArray>* strings) { int idx = 0; @@ -61,6 +86,89 @@ static int registerString(const QByteArray& s, QList<QByteArray>* strings) return idx; } +static int qvariant_nameToType(const char* name) +{ + if (!name) + return 0; + + if (strcmp(name, "QVariant") == 0) + return 0xffffffff; + if (strcmp(name, "QCString") == 0) + return QMetaType::QByteArray; + if (strcmp(name, "Q_LLONG") == 0) + return QMetaType::LongLong; + if (strcmp(name, "Q_ULLONG") == 0) + return QMetaType::ULongLong; + if (strcmp(name, "QIconSet") == 0) + return QMetaType::QIcon; + + uint tp = QMetaType::type(name); + return tp < QMetaType::User ? tp : 0; +} + +/* + Returns true if the type is a QVariant types. +*/ +static bool isVariantType(const char* type) +{ + return qvariant_nameToType(type) != 0; +} + +/*! + Returns true if the type is qreal. +*/ +static bool isQRealType(const char *type) +{ + return strcmp(type, "qreal") == 0; +} + +uint PropertyData::flags() const +{ + const char* typeName = type().data(); + uint flags = Invalid; + if (!isVariantType(typeName)) + flags |= EnumOrFlag; + else if (!isQRealType(typeName)) + flags |= qvariant_nameToType(typeName) << 24; + + if (qproperty_is_readble(m_data)) + flags |= Readable; + + if (qproperty_is_writable(m_data)) + flags |= Writable; + + if (qproperty_has_reset(m_data)) + flags |= Resettable; + + if (!qproperty_is_designable(m_data)) + flags |= ResolveDesignable; + else + flags |= Designable; + + if (!qproperty_is_scriptable(m_data)) + flags |= ResolveScriptable; + else + flags |= Scriptable; + + if (!qproperty_is_stored(m_data)) + flags |= ResolveStored; + else + flags |= Stored; + + if (!qproperty_is_user(m_data)) + flags |= ResolveUser; + else + flags |= User; + + if (qproperty_is_constant(m_data)) + flags |= Constant; + + if (qproperty_is_final(m_data)) + flags |= Final; + + return flags; +} + MethodData::MethodData(const char* signature, const char* type) { m_signature = QSharedPointer<QByteArray>(new QByteArray(signature)); @@ -107,6 +215,39 @@ bool MethodData::isValid() const return m_signature->size(); } + +PropertyData::PropertyData(const char* name, PyObject* data) + : m_name(name), m_data(data) +{ +} + +QByteArray PropertyData::type() const +{ + return QByteArray(qproperty_get_type(m_data)); +} + + +bool PropertyData::isValid() const +{ + return !m_name.isEmpty(); +} + +QByteArray PropertyData::name() const +{ + return m_name; +} + +bool PropertyData::operator==(const PropertyData& other) const +{ + return m_data == other.m_data; +} + +bool PropertyData::operator==(const char* name) const +{ + return m_name == QString(name); +} + + DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* metaObject) { d.superdata = metaObject; @@ -153,6 +294,10 @@ void DynamicQMetaObject::addSlot(const char* slot, const char* type) if (i != m_slots.end()) return; + if (m_slots.size() >= MAX_SLOTS_COUNT) { + qWarning() << "Fail to add dynamic slot to QObject. PySide support at most" << MAX_SLOTS_COUNT << "dynamic slots."; + return; + } //search for a empty space MethodData blank; @@ -177,6 +322,24 @@ void DynamicQMetaObject::removeSlot(uint index) } } +void DynamicQMetaObject::addProperty(const char* property, PyObject* data) +{ + QLinkedList<PropertyData>::iterator i = qFind(m_properties.begin(), m_properties.end(), property); + if (i != m_properties.end()) + return; + + //search for a empty space + PropertyData blank; + i = qFind(m_properties.begin(), m_properties.end(), blank); + if (i != m_properties.end()) { + *i = PropertyData(property, data); + } else { + m_properties << PropertyData(property, data); + } + updateMetaObject(); +} + + DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyObject* pyObj, PyTypeObject* type, const QMetaObject* base) { PyObject* key; @@ -189,6 +352,11 @@ DynamicQMetaObject* DynamicQMetaObject::createBasedOn(PyObject* pyObj, PyTypeObj while (PyDict_Next(type->tp_dict, &pos, &key, &value)) { + //Register properties + if (value->ob_type == &QProperty_Type) { + mo->addProperty(PyString_AsString(key), value); + } + //Register signals if (value->ob_type == &Signal_Type) { PyObject *attr = PyObject_GetAttr(pyObj, key); @@ -234,6 +402,35 @@ void DynamicQMetaObject::removeSignal(uint index) } } +void DynamicQMetaObject::writeMethodsData(QLinkedList<MethodData>& methods, + unsigned int **data, + QList<QByteArray> *strings, + int *prtIndex, + int max_count, + int null_index, + int flags) +{ + int index = *prtIndex; + + QLinkedList<MethodData>::iterator iMethod = methods.begin(); + for(int i=0; i < max_count; i++) { + QByteArray mType; + if (iMethod != methods.end() && ((*iMethod).signature().size() > 0) ) { + (*data)[index++] = registerString((*iMethod).signature(), strings); // func name + mType = (*iMethod).type(); + iMethod++; + } else { + (*data)[index++] = null_index; // func name + } + (*data)[index++] = null_index; // arguments + (*data)[index++] = (mType.size() > 0 ? registerString(mType, strings) : null_index); // normalized type + (*data)[index++] = null_index; // tags + (*data)[index++] = flags; + } + + *prtIndex = index; +} + void DynamicQMetaObject::updateMetaObject() { // these values are from moc source code, generator.cpp:66 @@ -251,22 +448,23 @@ void DynamicQMetaObject::updateMetaObject() }; uint n_signals = MAX_SIGNALS_COUNT; - uint n_methods = n_signals + m_slots.count(); + uint n_methods = n_signals + MAX_SLOTS_COUNT; + uint n_properties = m_properties.size(); int header[] = {5, // revision 0, // class name index in m_metadata 0, 0, // classinfo and classinfo index, not used by us n_methods, 0, // method count and method list index - 0, 0, // prop count and prop indexes + n_properties, 0, // prop count and prop indexes 0, 0, // enum count and enum index 0, 0, // constructors - MAX_SIGNALS_COUNT}; + n_signals}; const int HEADER_LENGHT = sizeof(header)/sizeof(int); header[5] = HEADER_LENGHT; // header size + 5 indexes per method + an ending zero delete[] d.data; unsigned int* data; - data = new unsigned int[HEADER_LENGHT + n_methods*5 + 1]; + data = new unsigned int[HEADER_LENGHT + n_methods*5 + n_properties*3 + 1]; std::memcpy(data, header, sizeof(header)); QList<QByteArray> strings; @@ -275,35 +473,25 @@ void DynamicQMetaObject::updateMetaObject() int index = HEADER_LENGHT; //write signals - QLinkedList<MethodData>::iterator iSignal = m_signals.begin(); - for(int i=0; i < MAX_SIGNALS_COUNT; i++) { - QByteArray sigType; - if (iSignal != m_signals.end() && ((*iSignal).signature().size() > 0) ) { - data[index++] = registerString((*iSignal).signature(), &strings); // func name - sigType = (*iSignal).type(); - iSignal++; - } else { - data[index++] = NULL_INDEX; // func name - } - data[index++] = NULL_INDEX; // arguments - data[index++] = (sigType.size() > 0 ? registerString(sigType, &strings) : NULL_INDEX); // normalized type - data[index++] = NULL_INDEX; // tags - data[index++] = AccessPublic | MethodSignal; // flags - } - + writeMethodsData(m_signals, &data, &strings, &index, MAX_SIGNALS_COUNT, NULL_INDEX, AccessPublic | MethodSignal); //write slots - foreach(MethodData slot, m_slots) { - if (slot.isValid()) - data[index++] = registerString(slot.signature(), &strings); // func name + writeMethodsData(m_slots, &data, &strings, &index, MAX_SLOTS_COUNT, NULL_INDEX, AccessPublic | MethodSlot); + + if (m_properties.size()) + data[7] = index; + + //write properties + foreach(PropertyData pp, m_properties) { + if (pp.isValid()) + data[index++] = registerString(pp.name(), &strings); // name else data[index++] = NULL_INDEX; - data[index++] = NULL_INDEX; // arguments - data[index++] = (slot.isValid() ? registerString(slot.type(), &strings) : NULL_INDEX); // normalized type - data[index++] = NULL_INDEX; // tags - data[index++] = AccessPublic | MethodSlot; // flags + data[index++] = (pp.isValid() ? registerString(pp.type(), &strings) : NULL_INDEX); // normalized type + data[index++] = pp.flags(); //pp.flags(); //TODO: flags } + data[index++] = 0; // the end // create the m_metadata string diff --git a/libpyside/dynamicqmetaobject.h b/libpyside/dynamicqmetaobject.h index 69027f218..23a69c9a9 100644 --- a/libpyside/dynamicqmetaobject.h +++ b/libpyside/dynamicqmetaobject.h @@ -66,6 +66,23 @@ private: QSharedPointer<QByteArray> m_type; }; +class PropertyData +{ +public: + PropertyData(){} + PropertyData(const char*name, PyObject *data); + QByteArray name() const; + QByteArray type() const; + uint flags() const; + bool isValid() const; + bool operator==(const PropertyData& other) const; + bool operator==(const char* name) const; + +private: + QByteArray m_name; + PyObject* m_data; +}; + class PYSIDE_API DynamicQMetaObject : public QMetaObject { public: @@ -74,9 +91,11 @@ public: void addSignal(const char* signal, const char* type=0); void addSlot(const char* slot, const char* type=0); + void addProperty(const char* property, PyObject* data); void removeSignal(uint idex); void removeSlot(uint index); + void removeProperty(uint index); //Retrieve Python metadata to create QMetaObject (class name, signals, slot) static DynamicQMetaObject* createBasedOn(PyObject* obj, PyTypeObject* type, const QMetaObject* base); @@ -84,9 +103,11 @@ public: private: QLinkedList<MethodData> m_signals; QLinkedList<MethodData> m_slots; + QLinkedList<PropertyData> m_properties; QByteArray m_className; void updateMetaObject(); + void writeMethodsData(QLinkedList<MethodData>& methods, unsigned int **data, QList<QByteArray> *strings, int *index, int max_count, int null_index, int flags); }; PYSIDE_API inline void deleteDynamicQMetaObject(void* data) diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp index 93271c8ba..744dfee3a 100644 --- a/libpyside/pyside.cpp +++ b/libpyside/pyside.cpp @@ -35,9 +35,11 @@ #include "pyside.h" #include "signalmanager.h" +#include "qproperty.h" extern "C" void init_signal(PyObject* module); extern "C" void init_slot(PyObject* module); +extern "C" void init_qproperty(PyObject* module); namespace PySide { @@ -46,6 +48,7 @@ void init(PyObject *module) { init_signal(module); init_slot(module); + init_qproperty(module); // Init signal manager, so it will register some meta types used by QVariant. SignalManager::instance(); } diff --git a/libpyside/qproperty.cpp b/libpyside/qproperty.cpp new file mode 100644 index 000000000..781c8cf3b --- /dev/null +++ b/libpyside/qproperty.cpp @@ -0,0 +1,318 @@ +/* + * This file is part of the Shiboken Python Bindings Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. Please + * review the following information to ensure the GNU Lesser General + * Public License version 2.1 requirements will be met: + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * As a special exception to the GNU Lesser General Public License + * version 2.1, the object code form of a "work that uses the Library" + * may incorporate material from a header file that is part of the + * Library. You may distribute such object code under terms of your + * choice, provided that the incorporated material (i) does not exceed + * more than 5% of the total size of the Library; and (ii) is limited to + * numerical parameters, data structure layouts, accessors, macros, + * inline functions and templates. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <shiboken.h> +#include <Python.h> +#include <QDebug> + +#include "qproperty.h" + + +#define QPROPERTY_CLASS_NAME "QProperty" + +namespace PySide +{ + +extern "C" +{ + +typedef struct { + PyObject_HEAD + char* typeName; + PyObject* type; + PyObject* fget; + PyObject* fset; + PyObject* freset; + PyObject* fdel; + char* doc; + bool designable; + bool scriptable; + bool stored; + bool user; + bool constant; + bool final; +} QPropertyData; + +static int qproperty_init(PyObject*, PyObject*, PyObject*); +static void qproperty_free(void*); + +//aux +static char* translate_type_name(PyObject*); + +PyTypeObject QProperty_Type = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + QPROPERTY_CLASS_NAME, /*tp_name*/ + sizeof(QPropertyData), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc */ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + 0, /*tp_iter */ + 0, /*tp_iternext */ + 0, /*tp_methods */ + 0, /*tp_members */ + 0, /*tp_getset */ + 0, /*tp_base */ + 0, /*tp_dict */ + 0, /*tp_descr_get */ + 0, /*tp_descr_set */ + 0, /*tp_dictoffset */ + (initproc)qproperty_init, /*tp_init */ + 0, /*tp_alloc */ + PyType_GenericNew, /*tp_new */ + qproperty_free, /*tp_free */ + 0, /*tp_is_gc */ + 0, /*tp_bases */ + 0, /*tp_mro */ + 0, /*tp_cache */ + 0, /*tp_subclasses */ + 0, /*tp_weaklist */ + 0, /*tp_del */ +}; + +void init_qproperty(PyObject* module) +{ + if (PyType_Ready(&QProperty_Type) < 0) + return; + + Py_INCREF(&QProperty_Type); + PyModule_AddObject(module, QPROPERTY_CLASS_NAME, ((PyObject*)&QProperty_Type)); +} + +} // extern "C" + +int qproperty_init(PyObject* self, PyObject* args, PyObject* kwds) +{ + PyObject* type = 0; + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + data->designable = true; + data->scriptable = true; + data->stored = true; + + static const char *kwlist[] = {"fget", "fset", "freset", "fdel", "doc", + "designable", "scriptable", "stored", "user", + "constant", "final", 0}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O|OOOOsbbbbbb:QtCore.QProperty", (char**) kwlist, + &type, &data->fget, &data->fset, &data->freset, + &data->fdel, &data->doc, &data->designable, + &data->scriptable, &data->stored, &data->user, + &data->constant, &data->final)) + return 0; + + if (!data->fset && data->fget) + data->constant = true; + + data->typeName = translate_type_name(type); + return 1; +} + +void qproperty_free(void *self) +{ + PyObject *pySelf = reinterpret_cast<PyObject*>(self); + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + + free(data->typeName); + free(data->doc); + + pySelf->ob_type->tp_base->tp_free(self); +} + +bool isQPropertyType(PyObject* pyObj) +{ + if (pyObj) { + return pyObj->ob_type == &QProperty_Type; + } + return false; +} + +int qproperty_set(PyObject* self, PyObject* source, PyObject* value) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + if (data->fset) { + Shiboken::AutoDecRef args(PyTuple_New(2)); + PyTuple_SET_ITEM(args, 0, source); + PyTuple_SET_ITEM(args, 1, value); + Py_INCREF(source); + Py_INCREF(value); + Shiboken::AutoDecRef result(PyObject_CallObject(data->fset, args)); + return (result.isNull() ? -1 : 0); + } + return -1; +} + +PyObject* qproperty_get(PyObject* self, PyObject* source) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + if (data->fget) { + Shiboken::AutoDecRef args(PyTuple_New(1)); + Py_INCREF(source); + PyTuple_SET_ITEM(args, 0, source); + PyObject *ret = PyObject_CallObject(data->fget, args); + if (!ret) { + PyErr_Print(); + } + return ret; + } + return 0; +} + +int qproperty_reset(PyObject* self, PyObject* source) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + if (data->freset) { + Shiboken::AutoDecRef args(PyTuple_New(1)); + Py_INCREF(source); + PyTuple_SET_ITEM(args, 0, source); + Shiboken::AutoDecRef result(PyObject_CallObject(data->freset, args)); + return (result.isNull() ? -1 : 0); + } + return -1; +} + + +const char* qproperty_get_type(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return data->typeName; +} + +PyObject* qproperty_get_object(PyObject* source, PyObject* name) +{ + if (PyObject_HasAttr(source, name)) { + PyObject* attr = PyObject_GenericGetAttr(source, name); + if (isQPropertyType(attr)) + return attr; + Py_DECREF(attr); + } + return 0; +} + +char* translate_type_name(PyObject* type) +{ + if (PyType_Check(type)) { + char *typeName = NULL; + if (type->ob_type == &Shiboken::SbkBaseWrapperType_Type) { + Shiboken::SbkBaseWrapperType *objType = reinterpret_cast<Shiboken::SbkBaseWrapperType*>(type); + typeName = strdup(objType->original_name); + } else { + //tp_name return the full name + Shiboken::AutoDecRef otypeName(PyObject_GetAttrString(type, "__name__")); + typeName = strdup(PyString_AS_STRING(otypeName.object())); + } + if (Shiboken::TypeResolver::getType(typeName) == Shiboken::TypeResolver::ObjectType) { + typeName = reinterpret_cast<char*>(realloc(typeName, strlen(typeName) + 1)); + typeName = strcat(typeName, "*"); + } + return typeName; + } else if (PyString_Check(type)) { + return strdup(PyString_AS_STRING(type)); + } + return 0; +} + +bool qproperty_is_readble(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return (data->fget != 0); +} + +bool qproperty_is_writable(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return (data->fset != 0); +} + +bool qproperty_has_reset(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return (data->freset != 0); +} + +bool qproperty_is_designable(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return data->designable; +} + +bool qproperty_is_scriptable(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return data->scriptable; +} + +bool qproperty_is_stored(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return data->stored; +} + +bool qproperty_is_user(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return data->user; +} + +bool qproperty_is_constant(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return data->constant; +} + +bool qproperty_is_final(PyObject* self) +{ + QPropertyData *data = reinterpret_cast<QPropertyData*>(self); + return data->final; +} + +} //namespace PySide diff --git a/libpyside/qproperty.h b/libpyside/qproperty.h new file mode 100644 index 000000000..7e0e1bc93 --- /dev/null +++ b/libpyside/qproperty.h @@ -0,0 +1,187 @@ +/* + * This file is part of the Shiboken Python Bindings Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. Please + * review the following information to ensure the GNU Lesser General + * Public License version 2.1 requirements will be met: + * http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + * + * As a special exception to the GNU Lesser General Public License + * version 2.1, the object code form of a "work that uses the Library" + * may incorporate material from a header file that is part of the + * Library. You may distribute such object code under terms of your + * choice, provided that the incorporated material (i) does not exceed + * more than 5% of the total size of the Library; and (ii) is limited to + * numerical parameters, data structure layouts, accessors, macros, + * inline functions and templates. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef PYSIDE_PROPERTY_H +#define PYSIDE_PROPERTY_H + +#include <pysidemacros.h> +#include <Python.h> +#include <QObject> + +namespace PySide +{ + +extern "C" +{ + PyAPI_DATA(PyTypeObject) QProperty_Type; +}; //extern "C" + +PYSIDE_API bool isQPropertyType(PyObject* pyObj); + +/** + * This function call set property function and pass value as arg + * This function does not check the property object type + * + * @param self The property object + * @param source The QObject witch has the property + * @param value The value to set in property + * @return Return 0 if ok or -1 if this function fail + **/ +PYSIDE_API int qproperty_set(PyObject* self, PyObject* source, PyObject* value); + +/** + * This function call get property function + * This function does not check the property object type + * + * @param self The property object + * @param source The QObject witch has the property + * @return Return the result of property get function or 0 if this fail + **/ +PYSIDE_API PyObject* qproperty_get(PyObject* self, PyObject* source); + +/** + * This function call reset property function + * This function does not check the property object type + * + * @param self The property object + * @param source The QObject witch has the property + * @return Return 0 if ok or -1 if this function fail + **/ +PYSIDE_API int qproperty_reset(PyObject* self, PyObject* source); + + +/** + * This function return the property type + * This function does not check the property object type + * + * @param self The property object + * @return Return the property type name + **/ +PYSIDE_API const char* qproperty_get_type(PyObject* self); + +/** + * This function search in the source object for desired property + * + * @param source The QObject object + * @param name The property name + * @return Return a new reference to property object + **/ +PYSIDE_API PyObject* qproperty_get_object(PyObject* source, PyObject* name); + + +/** + * This function check if property has read function + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_readble(PyObject* self); + +/** + * This function check if property has write function + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_writable(PyObject* self); + +/** + * This function check if property has reset function + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_has_reset(PyObject* self); + +/** + * This function check if property has the flag DESIGNABLE setted + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_designable(PyObject* self); + +/** + * This function check if property has the flag SCRIPTABLE setted + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_scriptable(PyObject* self); + +/** + * This function check if property has the flag STORED setted + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_stored(PyObject* self); + +/** + * This function check if property has the flag USER setted + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_user(PyObject* self); + +/** + * This function check if property has the flag CONSTANT setted + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_constant(PyObject* self); + +/** + * This function check if property has the flag FINAL setted + * This function does not check the property object type + * + * @param self The property object + * @return Return a boolean value + **/ +PYSIDE_API bool qproperty_is_final(PyObject* self); + + +} //namespace PySide + +#endif diff --git a/libpyside/qsignal.cpp b/libpyside/qsignal.cpp index b19c5658c..dff9cc184 100644 --- a/libpyside/qsignal.cpp +++ b/libpyside/qsignal.cpp @@ -229,10 +229,11 @@ PyObject* signal_instance_get_item(PyObject* self, PyObject* key) void signalUpdateSource(PyObject* source) { Shiboken::AutoDecRef attrs(PyObject_Dir(source)); + for(int i = 0, i_max = PyList_GET_SIZE(attrs.object()); i < i_max; i++) { PyObject *attrName = PyList_GET_ITEM(attrs.object(), i); - Shiboken::AutoDecRef attr(PyObject_GetAttr(source, attrName)); - if (attr->ob_type == &Signal_Type) { + Shiboken::AutoDecRef attr(PyObject_GetAttr((PyObject*)source->ob_type, attrName)); + if (!attr.isNull() && (attr->ob_type == &Signal_Type)) { Shiboken::AutoDecRef signalInstance(reinterpret_cast<PyObject*>(PyObject_New(SignalInstanceData, &SignalInstance_Type))); signal_instance_initialize(signalInstance, attrName, reinterpret_cast<SignalData*>(attr.object()), source, 0); PyObject_SetAttr(source, attrName, signalInstance); diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp index f1734001b..de0de7d86 100644 --- a/libpyside/signalmanager.cpp +++ b/libpyside/signalmanager.cpp @@ -33,6 +33,7 @@ */ #include "signalmanager.h" +#include "qproperty.h" #include <QHash> #include <QStringList> @@ -351,14 +352,87 @@ bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* ar return false; } -int PySide::SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args) +int SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, int id, void** args) { const QMetaObject* metaObject = object->metaObject(); - // only meta method invocation is supported right now. + PyObject* pp = 0; + PyObject* pp_name = 0; + QMetaProperty mp; + Shiboken::TypeResolver* typeResolver = 0; + PyObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(object); + if (call != QMetaObject::InvokeMetaMethod) { - qWarning("Only meta method invocation is supported right now by PySide."); - return id - metaObject->methodCount(); + mp = metaObject->property(id); + if (!mp.isValid()) + return id - metaObject->methodCount(); + + pp_name = PyString_FromString(mp.name()); + pp = qproperty_get_object(pySelf, pp_name); + if (!pp) { + qWarning("Invalid property."); + Py_XDECREF(pp_name); + return id - metaObject->methodCount(); + } + printf("access to property: %s-%s\n", mp.name(), mp.typeName()); + typeResolver = Shiboken::TypeResolver::get(mp.typeName()); + } + + switch(call) { +#ifndef QT_NO_PROPERTIES + case QMetaObject::ReadProperty: + { + PyObject* value = qproperty_get(pp, pySelf); + if (value) { + void *data = typeResolver->toCpp(value); + if (Shiboken::TypeResolver::getType(mp.typeName()) == Shiboken::TypeResolver::ObjectType) + args[0] = &data; + else + args[0] = data; + + Py_DECREF(value); + } + break; + } + + case QMetaObject::WriteProperty: + { + Shiboken::AutoDecRef value(typeResolver->toPython(args[0])); + qproperty_set(pp, pySelf, value); + break; + } + + case QMetaObject::ResetProperty: + qproperty_reset(pp, pp_name); + break; + + case QMetaObject::QueryPropertyDesignable: + case QMetaObject::QueryPropertyScriptable: + case QMetaObject::QueryPropertyStored: + case QMetaObject::QueryPropertyEditable: + case QMetaObject::QueryPropertyUser: + break; +#endif + case QMetaObject::InvokeMetaMethod: + id = call_method(object, id, args); + break; + + default: + qWarning("Unsupported meta invocation type."); } + + if (call == QMetaObject::InvokeMetaMethod) + id = id - metaObject->methodCount(); + else + id = id - metaObject->propertyCount(); + + Py_XDECREF(pp); + Py_XDECREF(pp_name); + return id; +} + +int SignalManager::call_method(QObject* object, int id, void** args) +{ + const QMetaObject* metaObject = object->metaObject(); QMetaMethod method = metaObject->method(id); if (method.methodType() == QMetaMethod::Signal) { @@ -403,6 +477,7 @@ int PySide::SignalManager::qt_metacall(QObject* object, QMetaObject::Call call, bool SignalManager::registerMetaMethod(QObject* source, const char* signature, QMetaMethod::MethodType type) { + Q_ASSERT(source); const QMetaObject* metaObject = source->metaObject(); int methodIndex = metaObject->indexOfMethod(signature); // Create the dynamic signal is needed diff --git a/libpyside/signalmanager.h b/libpyside/signalmanager.h index 72acd1d93..08160a5a1 100644 --- a/libpyside/signalmanager.h +++ b/libpyside/signalmanager.h @@ -94,6 +94,8 @@ private: // disable copy SignalManager(const SignalManager&); SignalManager operator=(const SignalManager&); + + static int call_method(QObject* object, int id, void** args); }; } |