diff options
author | Renato Filho <renato.filho@openbossa.org> | 2011-05-19 18:12:52 -0300 |
---|---|---|
committer | Hugo Parente Lima <hugo.pl@gmail.com> | 2012-03-08 16:54:25 -0300 |
commit | e13ce9212afb46f86e11f78fee98a1d1e1b1557e (patch) | |
tree | 75b6a9c5e616596b2fa5ccda2573d34f22a7dcd3 | |
parent | 5805ea4e01c463e5eae029a51978bdb1b910aad4 (diff) |
Implemented PySide::ClassInfo Object.
This class reproduce the Qt macro Q_CLASSINFO behavior.
Eg.:
@QtCore.ClassInfo(author='PySide', url='http://www.pyside.org')
fixes bug #705.
Reviewer: Marcelo Lira <marcelo.lira@openbossa.org>
Hugo Parente Lima <hugo.pl@gmail.com>
-rw-r--r-- | libpyside/CMakeLists.txt | 2 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.cpp | 47 | ||||
-rw-r--r-- | libpyside/dynamicqmetaobject.h | 2 | ||||
-rw-r--r-- | libpyside/pyside.cpp | 6 | ||||
-rw-r--r-- | libpyside/pysideclassinfo.cpp | 166 | ||||
-rw-r--r-- | libpyside/pysideclassinfo.h | 51 | ||||
-rw-r--r-- | libpyside/pysideclassinfo_p.h | 54 |
7 files changed, 317 insertions, 11 deletions
diff --git a/libpyside/CMakeLists.txt b/libpyside/CMakeLists.txt index c3d3f8611..2d2a61375 100644 --- a/libpyside/CMakeLists.txt +++ b/libpyside/CMakeLists.txt @@ -4,6 +4,7 @@ set(libpyside_SRC dynamicqmetaobject.cpp signalmanager.cpp globalreceiver.cpp + pysideclassinfo.cpp pysidemetafunction.cpp pysidesignal.cpp pysideslot.cpp @@ -35,6 +36,7 @@ set_target_properties(pyside PROPERTIES set(libpyside_HEADERS dynamicqmetaobject.h globalreceiver.h + pysideclassinfo.h pysideconversions.h pysidemacros.h signalmanager.h diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index 73572e3b4..86190fa5d 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -84,6 +84,7 @@ class DynamicQMetaObject::DynamicQMetaObjectPrivate public: QList<MethodData> m_methods; QList<PropertyData> m_properties; + QMap<QByteArray, QByteArray> m_info; QByteArray m_className; void updateMetaObject(QMetaObject* metaObj); @@ -380,6 +381,20 @@ void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data) m_d->updateMetaObject(this); } +void DynamicQMetaObject::addInfo(const char* key, const char* value) +{ + m_d->m_info[key] = value; +} + +void DynamicQMetaObject::addInfo(QMap<QByteArray, QByteArray> info) +{ + QMap<QByteArray, QByteArray>::const_iterator i = info.constBegin(); + while (i != info.constEnd()) { + m_d->m_info[i.key()] = i.value(); + ++i; + } + m_d->updateMetaObject(this); +} void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods, unsigned int** data, @@ -409,21 +424,22 @@ void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject { uint n_methods = m_methods.size(); uint n_properties = m_properties.size(); - int header[] = {3, // 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 - n_properties, 0, // prop count and prop indexes - 0, 0, // enum count and enum index - 0, 0, // constructors - 0}; // flags + uint n_info = m_info.size(); + int header[] = {3, // revision + 0, // class name index in m_metadata + n_info, 0, // classinfo and classinfo index + n_methods, 0, // method count and method list index + n_properties, 0, // prop count and prop indexes + 0, 0, // enum count and enum index + 0, 0, // constructors + 0}; // flags const int HEADER_LENGHT = sizeof(header)/sizeof(int); header[5] = HEADER_LENGHT; // header size + 5 indexes per method + an ending zero delete[] metaObj->d.data; unsigned int* data; - data = new unsigned int[HEADER_LENGHT + n_methods*5 + n_properties*4 + 1]; + data = new unsigned int[HEADER_LENGHT + n_methods*5 + n_properties*4 + n_info*2 + 1]; std::memcpy(data, header, sizeof(header)); QList<QByteArray> strings; @@ -431,6 +447,19 @@ void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject const int NULL_INDEX = registerString("", &strings); // register a null string int index = HEADER_LENGHT; + //write class info + if (n_info) { + data[3] = index; + QMap<QByteArray, QByteArray>::const_iterator i = m_info.constBegin(); + while (i != m_info.constEnd()) { + int valueIndex = registerString(i.value(), &strings); + int keyIndex = registerString(i.key(), &strings); + data[index++] = keyIndex; + data[index++] = valueIndex; + i++; + } + } + //write signals/slots writeMethodsData(m_methods, &data, &strings, &index, NULL_INDEX, AccessPublic); diff --git a/libpyside/dynamicqmetaobject.h b/libpyside/dynamicqmetaobject.h index 2efeef165..d137e3057 100644 --- a/libpyside/dynamicqmetaobject.h +++ b/libpyside/dynamicqmetaobject.h @@ -43,6 +43,8 @@ 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 addInfo(const char* key, const char* value); + void addInfo(QMap<QByteArray, QByteArray> info); void removeSignal(uint idex); void removeSlot(uint index); diff --git a/libpyside/pyside.cpp b/libpyside/pyside.cpp index 4b1c17b6a..a4fcbccf0 100644 --- a/libpyside/pyside.cpp +++ b/libpyside/pyside.cpp @@ -22,6 +22,7 @@ #include "pyside.h" #include "signalmanager.h" +#include "pysideclassinfo_p.h" #include "pysideproperty_p.h" #include "pysideproperty.h" #include "pysidesignal.h" @@ -47,6 +48,7 @@ namespace PySide void init(PyObject *module) { + ClassInfo::init(module); Signal::init(module); Slot::init(module); Property::init(module); @@ -188,10 +190,10 @@ void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds) Shiboken::AutoDecRef slotAttrName(PyString_FromString(PYSIDE_SLOT_LIST_ATTR)); while (PyDict_Next(attrs, &pos, &key, &value)) { - if (PyType_IsSubtype(value->ob_type, &PySidePropertyType)) { + if (Property::checkType(value)) { // Leave the properties to be register after signals because they may depend on notify signals properties << PropPair(PyString_AS_STRING(key), value); - } else if (value->ob_type == &PySideSignalType) { // Register signals + } else if (Signal::checkType(value)) { // Register signals PySideSignal* data = reinterpret_cast<PySideSignal*>(value); const char* signalName = PyString_AS_STRING(key); data->signalName = strdup(signalName); diff --git a/libpyside/pysideclassinfo.cpp b/libpyside/pysideclassinfo.cpp new file mode 100644 index 000000000..023f4d723 --- /dev/null +++ b/libpyside/pysideclassinfo.cpp @@ -0,0 +1,166 @@ +/* + * This file is part of the PySide project. + * + * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <Python.h> +#include "pysideclassinfo.h" +#include "pysideclassinfo_p.h" +#include "dynamicqmetaobject.h" + +#include <shiboken.h> +#include <QDebug> + +#define CLASSINFO_CLASS_NAME "ClassInfo" + +extern "C" +{ + +static PyObject* classInfoTpNew(PyTypeObject* subtype, PyObject* args, PyObject* kwds); +static int classInfoTpInit(PyObject*, PyObject*, PyObject*); +static void classInfoFree(void*); +static PyObject* classCall(PyObject*, PyObject*, PyObject*); + +PyTypeObject PySideClassInfoType = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + CLASSINFO_CLASS_NAME, /*tp_name*/ + sizeof(PySideClassInfo), /*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 */ + classCall, /*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 */ + classInfoTpInit, /*tp_init */ + 0, /*tp_alloc */ + classInfoTpNew, /*tp_new */ + classInfoFree, /*tp_free */ + 0, /*tp_is_gc */ + 0, /*tp_bases */ + 0, /*tp_mro */ + 0, /*tp_cache */ + 0, /*tp_subclasses */ + 0, /*tp_weaklist */ + 0, /*tp_del */ +}; + +PyObject* classCall(PyObject* self, PyObject* args, PyObject* kw) +{ + PyObject* klass; + klass = PyTuple_GetItem(args, 0); + + if (Shiboken::ObjectType::checkType(reinterpret_cast<PyTypeObject*>(klass))) { + PySide::DynamicQMetaObject* mo = reinterpret_cast<PySide::DynamicQMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(klass))); + if (mo) + mo->addInfo(PySide::ClassInfo::getMap(reinterpret_cast<PySideClassInfo*>(self))); + } + + Py_INCREF(klass); + return klass; +} + +static PyObject* classInfoTpNew(PyTypeObject* subtype, PyObject* args, PyObject* kwds) +{ + PySideClassInfo* me = reinterpret_cast<PySideClassInfo*>(subtype->tp_alloc(subtype, 0)); + me->d = new PySideClassInfoPrivate; + return (PyObject*) me; +} + +int classInfoTpInit(PyObject* self, PyObject* args, PyObject* kwds) +{ + PySideClassInfo* data = reinterpret_cast<PySideClassInfo*>(self); + PySideClassInfoPrivate* pData = data->d; + + PyObject* key; + PyObject* value; + Py_ssize_t pos = 0; + while (PyDict_Next(kwds, &pos, &key, &value)) { + if (PyString_Check(key) && PyString_Check(value)) + pData->m_data[PyString_AS_STRING(key)] = PyString_AS_STRING(value); + } + + return PyErr_Occurred() ? -1 : 1; +} + +void classInfoFree(void *self) +{ + PyObject* pySelf = reinterpret_cast<PyObject*>(self); + PySideClassInfo* data = reinterpret_cast<PySideClassInfo*>(self); + + delete data->d; + pySelf->ob_type->tp_base->tp_free(self); +} + + +} // extern "C" + + +namespace PySide { namespace ClassInfo { + +void init(PyObject* module) +{ + if (PyType_Ready(&PySideClassInfoType) < 0) + return; + + Py_INCREF(&PySideClassInfoType); + PyModule_AddObject(module, CLASSINFO_CLASS_NAME, ((PyObject*)&PySideClassInfoType)); +} + +bool checkType(PyObject* pyObj) +{ + if (pyObj) + return PyType_IsSubtype(pyObj->ob_type, &PySideClassInfoType); + return false; +} + +QMap<QByteArray, QByteArray> getMap(PySideClassInfo* obj) +{ + return obj->d->m_data; +} + +} //namespace Property +} //namespace PySide diff --git a/libpyside/pysideclassinfo.h b/libpyside/pysideclassinfo.h new file mode 100644 index 000000000..e13049ed3 --- /dev/null +++ b/libpyside/pysideclassinfo.h @@ -0,0 +1,51 @@ +/* + * This file is part of the PySide project. + * + * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PYSIDE_CLASSINFO_H +#define PYSIDE_CLASSINFO_H + +#include <pysidemacros.h> +#include <Python.h> +#include <QMap> +#include <QByteArray> + +extern "C" +{ + extern PYSIDE_API PyTypeObject PySideClassInfoType; + + struct PySideClassInfoPrivate; + struct PYSIDE_API PySideClassInfo + { + PyObject_HEAD + PySideClassInfoPrivate* d; + }; +}; + +namespace PySide { namespace ClassInfo { + +PYSIDE_API bool checkType(PyObject* pyObj); +PYSIDE_API QMap<QByteArray, QByteArray> getMap(PySideClassInfo* obj); + +} //namespace ClassInfo +} //namespace PySide + +#endif diff --git a/libpyside/pysideclassinfo_p.h b/libpyside/pysideclassinfo_p.h new file mode 100644 index 000000000..3b96342f4 --- /dev/null +++ b/libpyside/pysideclassinfo_p.h @@ -0,0 +1,54 @@ +/* + * This file is part of the PySide project. + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PYSIDE_CLASSINFO_P_H +#define PYSIDE_CLASSINFO_P_H + +#include <Python.h> +#include <QMetaObject> +#include "pysideclassinfo.h" + +#define __INFO_ATTR_NAME__ "__classInfo__" + +struct PySideClassInfo; + +extern "C" +{ + +struct PySideClassInfoPrivate { + QMap<QByteArray, QByteArray> m_data; +}; + +} // extern "C" + +namespace PySide { namespace ClassInfo { + +/** + * Init PySide QProperty support system + */ +void init(PyObject* module); + + +} // namespace ClassInfo +} // namespace PySide + +#endif |