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:
parent
fc331f37e3
commit
78e120ec02
3 changed files with 79 additions and 126 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue