Uses QMetaObject revision 3.

This allow to register signal and slot in any order.

Fixes bug #312

Reviewer: Marcelo Lira <marcelo.lira@openbossa.org>
          Hugo Parente Lima <hugo.pl@gmail.com>
This commit is contained in:
Renato Filho 2011-05-10 16:42:32 -03:00
commit 78e120ec02
3 changed files with 79 additions and 126 deletions

View file

@ -38,12 +38,6 @@
#include <QDebug> #include <QDebug>
#include <QMetaMethod> #include <QMetaMethod>
#define MAX_SIGNALS_COUNT 50
#define MAX_SLOTS_COUNT 50
#define MAX_GLOBAL_SIGNALS_COUNT 500
#define MAX_GLOBAL_SLOTS_COUNT 500
#define EMPTY_META_METHOD "0()" #define EMPTY_META_METHOD "0()"
using namespace PySide; using namespace PySide;
@ -71,16 +65,29 @@ enum PropertyFlags {
Notify = 0x00400000 Notify = 0x00400000
}; };
// these values are from moc source code, generator.cpp:66
enum MethodFlags {
AccessPrivate = 0x00,
AccessProtected = 0x01,
AccessPublic = 0x02,
MethodMethod = 0x00,
MethodSignal = 0x04,
MethodSlot = 0x08,
MethodConstructor = 0x0c,
MethodCompatibility = 0x10,
MethodCloned = 0x20,
MethodScriptable = 0x40
};
class DynamicQMetaObject::DynamicQMetaObjectPrivate class DynamicQMetaObject::DynamicQMetaObjectPrivate
{ {
public: public:
QList<MethodData> m_signals; QList<MethodData> m_methods;
QList<MethodData> m_slots;
QList<PropertyData> m_properties; QList<PropertyData> m_properties;
QByteArray m_className; QByteArray m_className;
void updateMetaObject(QMetaObject* metaObj); void updateMetaObject(QMetaObject* metaObj);
void writeMethodsData(const QList<MethodData>& methods, unsigned int** data, QList<QByteArray>* strings, int* prtIndex, int maxCount, int nullIndex, int flags); void writeMethodsData(const QList<MethodData>& methods, unsigned int** data, QList<QByteArray>* strings, int* prtIndex, int nullIndex, int flags);
}; };
static int registerString(const QByteArray& s, QList<QByteArray>* strings) static int registerString(const QByteArray& s, QList<QByteArray>* strings)
@ -132,20 +139,6 @@ static bool isQRealType(const char *type)
return strcmp(type, "qreal") == 0; return strcmp(type, "qreal") == 0;
} }
/*
* Avoid API break keep this on cpp
*/
static inline int maxSlotsCount(const QByteArray& className)
{
return className == GLOBAL_RECEIVER_CLASS_NAME ? MAX_GLOBAL_SIGNALS_COUNT : MAX_SLOTS_COUNT;
}
static inline int maxSignalsCount(const QByteArray& className)
{
return className == GLOBAL_RECEIVER_CLASS_NAME ? MAX_GLOBAL_SIGNALS_COUNT : MAX_SIGNALS_COUNT;
}
uint PropertyData::flags() const uint PropertyData::flags() const
{ {
const char* typeName = type().data(); const char* typeName = type().data();
@ -206,7 +199,7 @@ MethodData::MethodData() : m_signature(m_emptySig)
{ {
} }
MethodData::MethodData(const char* signature, const char* type) : m_signature(signature), m_type(type) MethodData::MethodData(QMetaMethod::MethodType mtype, const char* signature, const char* type) : m_signature(signature), m_type(type), m_mtype(mtype)
{ {
} }
@ -218,12 +211,7 @@ void MethodData::clear()
bool MethodData::operator==(const MethodData& other) const bool MethodData::operator==(const MethodData& other) const
{ {
return m_signature == other.signature(); return ((m_signature == other.signature()) && (m_mtype == other.methodType()));
}
bool MethodData::operator==(const char* other) const
{
return m_signature == other;
} }
QByteArray MethodData::signature() const QByteArray MethodData::signature() const
@ -243,6 +231,11 @@ bool MethodData::isValid() const
return m_signature.size(); return m_signature.size();
} }
QMetaMethod::MethodType MethodData::methodType() const
{
return m_mtype;
}
PropertyData::PropertyData() PropertyData::PropertyData()
: m_notifyId(0), m_data(0) : m_notifyId(0), m_data(0)
{ {
@ -302,57 +295,36 @@ DynamicQMetaObject::~DynamicQMetaObject()
delete m_d; delete m_d;
} }
void DynamicQMetaObject::addSignal(const char* signal, const char* type) void DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type)
{ {
int index = m_d->m_signals.indexOf(signal); int index = -1;
if (index != -1) int counter = 0;
return;
//search for a empty space
MethodData blank; MethodData blank;
index = m_d->m_signals.indexOf(blank);
if (index != -1) { QList<MethodData>::iterator it = m_d->m_methods.begin();
m_d->m_signals[index] = MethodData(signal, type); for (; it != m_d->m_methods.end(); ++it) {
m_d->updateMetaObject(this); if ((it->signature() == signature) && (it->methodType() == mtype))
return; return;
else if (*it == blank)
index = counter;
counter++;
} }
int maxSignals = maxSignalsCount(m_d->m_className); //has blank method
if (m_d->m_signals.size() >= maxSignals) { if (index != -1)
qWarning() << "Fail to add dynamic signal to QObject. PySide support at most" << maxSignals << "dynamic signals."; m_d->m_methods[index] = MethodData(mtype, signature, type);
return; else
} m_d->m_methods << MethodData(mtype, signature, type);
m_d->m_signals << MethodData(signal, type);
m_d->updateMetaObject(this); m_d->updateMetaObject(this);
} }
void DynamicQMetaObject::addSlot(const char* slot, const char* type) void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index)
{
int index = m_d->m_slots.indexOf(slot);
if (index != -1)
return;
//search for a empty space
MethodData blank;
index = m_d->m_slots.indexOf(blank);
if (index != -1) {
m_d->m_slots[index] = MethodData(slot, type);
} else if (m_d->m_slots.size() < maxSlotsCount(m_d->m_className)) {
m_d->m_slots << MethodData(slot, type);
} else {
qWarning() << "Fail to add dynamic slot to QObject. PySide support at most" << maxSlotsCount(m_d->m_className) << "dynamic slots.";
return;
}
m_d->updateMetaObject(this);
}
void DynamicQMetaObject::removeSlot(uint index)
{ {
const char* methodSig = method(index).signature(); const char* methodSig = method(index).signature();
QList<MethodData>::iterator it = m_d->m_slots.begin(); QList<MethodData>::iterator it = m_d->m_methods.begin();
for (; it != m_d->m_slots.end(); ++it) { for (; it != m_d->m_methods.end(); ++it) {
if (it->signature() == methodSig) { if ((it->signature() == methodSig) && (it->methodType() == mtype)){
it->clear(); it->clear();
m_d->updateMetaObject(this); m_d->updateMetaObject(this);
break; break;
@ -360,6 +332,26 @@ void DynamicQMetaObject::removeSlot(uint index)
} }
} }
void DynamicQMetaObject::addSignal(const char* signal, const char* type)
{
addMethod(QMetaMethod::Signal, signal, type);
}
void DynamicQMetaObject::addSlot(const char* slot, const char* type)
{
addMethod(QMetaMethod::Slot, slot, type);
}
void DynamicQMetaObject::removeSlot(uint index)
{
removeMethod(QMetaMethod::Slot, index);
}
void DynamicQMetaObject::removeSignal(uint index)
{
removeMethod(QMetaMethod::Signal, index);
}
void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data) void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data)
{ {
int index = m_d->m_properties.indexOf(propertyName); int index = m_d->m_properties.indexOf(propertyName);
@ -372,8 +364,8 @@ void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data)
if (property->d->notify) { if (property->d->notify) {
const char* signalNotify = PySide::Property::getNotifyName(property); const char* signalNotify = PySide::Property::getNotifyName(property);
if (signalNotify) { if (signalNotify) {
QByteArray signalSignature(signalNotify); MethodData signalObject(QMetaMethod::Signal, signalNotify, "");
notifyId = m_d->m_signals.indexOf(signalNotify); notifyId = m_d->m_methods.indexOf(signalObject);
} }
} }
@ -388,31 +380,16 @@ void DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data)
m_d->updateMetaObject(this); m_d->updateMetaObject(this);
} }
void DynamicQMetaObject::removeSignal(uint index)
{
//Current Qt implementation does not support runtime remove signal
QMetaMethod m = method(index);
foreach(MethodData md, m_d->m_signals) {
if (md.signature() == m.signature()) {
md.clear();
m_d->updateMetaObject(this);
break;
}
}
}
void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods, void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods,
unsigned int** data, unsigned int** data,
QList<QByteArray>* strings, QList<QByteArray>* strings,
int* prtIndex, int* prtIndex,
int maxCount,
int nullIndex, int nullIndex,
int flags) int flags)
{ {
int index = *prtIndex; int index = *prtIndex;
int emptyIndex = registerString(EMPTY_META_METHOD, strings); int emptyIndex = registerString(EMPTY_META_METHOD, strings);
QList<MethodData>::const_iterator it = methods.begin(); QList<MethodData>::const_iterator it = methods.begin();
for (; it != methods.end(); ++it) { for (; it != methods.end(); ++it) {
@ -423,50 +400,23 @@ void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList
(*data)[index++] = nullIndex; // arguments (*data)[index++] = nullIndex; // arguments
(*data)[index++] = (it->type().size() > 0 ? registerString(it->type(), strings) : nullIndex); // normalized type (*data)[index++] = (it->type().size() > 0 ? registerString(it->type(), strings) : nullIndex); // normalized type
(*data)[index++] = nullIndex; // tags (*data)[index++] = nullIndex; // tags
(*data)[index++] = flags; (*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot);
}
for (int i = methods.count(); i < maxCount; ++i) {
(*data)[index++] = emptyIndex; // func name
(*data)[index++] = nullIndex; // arguments
(*data)[index++] = nullIndex; // normalized type
(*data)[index++] = nullIndex; // tags
(*data)[index++] = flags;
} }
*prtIndex = index; *prtIndex = index;
} }
void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj) void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj)
{ {
// these values are from moc source code, generator.cpp:66 uint n_methods = m_methods.size();
enum MethodFlags {
AccessPrivate = 0x00,
AccessProtected = 0x01,
AccessPublic = 0x02,
MethodMethod = 0x00,
MethodSignal = 0x04,
MethodSlot = 0x08,
MethodConstructor = 0x0c,
MethodCompatibility = 0x10,
MethodCloned = 0x20,
MethodScriptable = 0x40
};
int maxSignals = maxSignalsCount(m_className);
int maxSlots = maxSlotsCount(m_className);
uint n_signals = maxSignals;
uint n_methods = n_signals + maxSlots;
uint n_properties = m_properties.size(); uint n_properties = m_properties.size();
int header[] = {5, // revision int header[] = {3, // revision
0, // class name index in m_metadata 0, // class name index in m_metadata
0, 0, // classinfo and classinfo index, not used by us 0, 0, // classinfo and classinfo index, not used by us
n_methods, 0, // method count and method list index n_methods, 0, // method count and method list index
n_properties, 0, // prop count and prop indexes n_properties, 0, // prop count and prop indexes
0, 0, // enum count and enum index 0, 0, // enum count and enum index
0, 0, // constructors 0, 0, // constructors
0, // flags 0}; // flags
n_signals};
const int HEADER_LENGHT = sizeof(header)/sizeof(int); const int HEADER_LENGHT = sizeof(header)/sizeof(int);
header[5] = HEADER_LENGHT; header[5] = HEADER_LENGHT;
@ -481,11 +431,8 @@ void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject
const int NULL_INDEX = registerString("", &strings); // register a null string const int NULL_INDEX = registerString("", &strings); // register a null string
int index = HEADER_LENGHT; int index = HEADER_LENGHT;
//write signals //write signals/slots
writeMethodsData(m_signals, &data, &strings, &index, maxSignals, NULL_INDEX, AccessPublic | MethodSignal); writeMethodsData(m_methods, &data, &strings, &index, NULL_INDEX, AccessPublic);
//write slots
writeMethodsData(m_slots, &data, &strings, &index, maxSlots, NULL_INDEX, AccessPublic | MethodSlot);
if (m_properties.size()) if (m_properties.size())
data[7] = index; data[7] = index;

View file

@ -26,6 +26,7 @@
#include "pysidemacros.h" #include "pysidemacros.h"
#include <Python.h> #include <Python.h>
#include <QMetaObject> #include <QMetaObject>
#include <QMetaMethod>
namespace PySide namespace PySide
{ {
@ -36,6 +37,9 @@ public:
DynamicQMetaObject(const char* className, const QMetaObject* metaObject); DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
~DynamicQMetaObject(); ~DynamicQMetaObject();
void addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type);
void removeMethod(QMetaMethod::MethodType mtype, uint index);
void addSignal(const char* signal, const char* type = 0); void addSignal(const char* signal, const char* type = 0);
void addSlot(const char* slot, const char* type = 0); void addSlot(const char* slot, const char* type = 0);
void addProperty(const char* property, PyObject* data); void addProperty(const char* property, PyObject* data);

View file

@ -25,6 +25,7 @@
#include <Python.h> #include <Python.h>
#include <QByteArray> #include <QByteArray>
#include <QMetaMethod>
#define GLOBAL_RECEIVER_CLASS_NAME "__GlobalReceiver__" #define GLOBAL_RECEIVER_CLASS_NAME "__GlobalReceiver__"
@ -39,17 +40,18 @@ namespace PySide
* \param signature method signature * \param signature method signature
* \param type method return type * \param type method return type
*/ */
MethodData(const char* signature, const char* type = 0); MethodData(QMetaMethod::MethodType mtype, const char* signature, const char* type = 0);
void clear(); void clear();
bool isValid() const; bool isValid() const;
QByteArray signature() const; QByteArray signature() const;
QByteArray type() const; QByteArray type() const;
QMetaMethod::MethodType methodType() const;
bool operator==(const MethodData& other) const; bool operator==(const MethodData& other) const;
bool operator==(const char* other) const;
private: private:
QByteArray m_signature; QByteArray m_signature;
QByteArray m_type; QByteArray m_type;
QMetaMethod::MethodType m_mtype;
static const QByteArray m_emptySig; static const QByteArray m_emptySig;
}; };