aboutsummaryrefslogtreecommitdiffstats
path: root/libpyside
diff options
context:
space:
mode:
authorRenato Filho <renato.filho@openbossa.org>2010-07-06 18:44:00 -0300
committerRenato Filho <renato.filho@openbossa.org>2010-07-08 11:27:38 -0300
commit1c4ee915c07daae9919e890072593b51e54c9aec (patch)
tree19424c508a942a202711fe65530894c10aaa7282 /libpyside
parent693ae6d6c4073a483524af48e7a1a0ad1fba1131 (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.txt2
-rw-r--r--libpyside/dynamicqmetaobject.cpp242
-rw-r--r--libpyside/dynamicqmetaobject.h21
-rw-r--r--libpyside/pyside.cpp3
-rw-r--r--libpyside/qproperty.cpp318
-rw-r--r--libpyside/qproperty.h187
-rw-r--r--libpyside/qsignal.cpp5
-rw-r--r--libpyside/signalmanager.cpp83
-rw-r--r--libpyside/signalmanager.h2
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);
};
}