~ubuntu-branches/ubuntu/utopic/pyside/utopic

« back to all changes in this revision

Viewing changes to libpyside/pyside.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Didier Raboud
  • Date: 2011-02-18 18:01:00 UTC
  • mfrom: (1.2.3 upstream) (6.1.6 experimental)
  • Revision ID: james.westby@ubuntu.com-20110218180100-vaczjij7g08fzfme
Tags: 1.0.0~rc1-1
* New 1.0.0~rc1 upstream release
  - Bump the B-D chain versions:
    + apiextractor to 0.10.0-2~
    + generatorrunner to 0.6.6
    + shiboken to 1.0.0~rc1
* Update patches to ~rc1.
* debian/watch: update to handle Release Candidates too.
* Bump XS-Python-Version to >= 2.6.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
21
 */
22
22
 
23
 
 
24
23
#include "pyside.h"
25
24
#include "signalmanager.h"
26
 
#include "qproperty.h"
27
 
#include "qsignal.h"
 
25
#include "pysideproperty_p.h"
 
26
#include "pysideproperty.h"
 
27
#include "pysidesignal.h"
 
28
#include "pysidesignal_p.h"
 
29
#include "pysideslot_p.h"
 
30
#include "pysidemetafunction_p.h"
 
31
#include "pysidemetafunction.h"
 
32
#include "dynamicqmetaobject.h"
 
33
 
28
34
#include <basewrapper.h>
29
35
#include <conversions.h>
 
36
#include <typeresolver.h>
 
37
#include <bindingmanager.h>
30
38
#include <algorithm>
31
39
#include <cctype>
32
40
#include <QStack>
33
 
 
34
 
extern "C" void init_signal(PyObject* module);
35
 
extern "C" void init_slot(PyObject* module);
36
 
extern "C" void init_qproperty(PyObject* module);
 
41
#include <QCoreApplication>
37
42
 
38
43
static QStack<PySide::CleanupFunction> cleanupFunctionList;
39
44
 
42
47
 
43
48
void init(PyObject *module)
44
49
{
45
 
    init_signal(module);
46
 
    init_slot(module);
47
 
    init_qproperty(module);
 
50
    Signal::init(module);
 
51
    Slot::init(module);
 
52
    Property::init(module);
 
53
    MetaFunction::init(module);
48
54
    // Init signal manager, so it will register some meta types used by QVariant.
49
55
    SignalManager::instance();
50
56
}
68
74
                    Shiboken::AutoDecRef retval(PyObject_CallObject(propSetter, args));
69
75
                } else {
70
76
                    PyObject* attr = PyObject_GenericGetAttr(qObj, key);
71
 
                    if (isQPropertyType(attr))
72
 
                        PySide::qproperty_set(attr, qObj, value);
 
77
                    if (PySide::Property::isPropertyType(attr))
 
78
                        PySide::Property::setValue(reinterpret_cast<PySideProperty*>(attr), qObj, value);
73
79
                }
74
80
            } else {
75
81
                propName.append("()");
76
82
                if (metaObj->indexOfSignal(propName) != -1) {
77
83
                    propName.prepend('2');
78
 
                    PySide::signal_connect(qObj, propName, value);
 
84
                    PySide::Signal::connect(qObj, propName, value);
79
85
                } else {
80
86
                    PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal", propName.constData());
81
87
                    return false;
99
105
    }
100
106
}
101
107
 
 
108
static void destructionVisitor(SbkObject* pyObj, void* data)
 
109
{
 
110
    void** realData = reinterpret_cast<void**>(data);
 
111
    SbkObject* pyQApp = reinterpret_cast<SbkObject*>(realData[0]);
 
112
    PyTypeObject* pyQObjectType = reinterpret_cast<PyTypeObject*>(realData[1]);
 
113
 
 
114
    if (pyObj != pyQApp && PyObject_TypeCheck(pyObj, pyQObjectType)) {
 
115
        if (Shiboken::Object::hasOwnership(pyObj) && Shiboken::Object::isValid(pyObj, false)) {
 
116
            Py_BEGIN_ALLOW_THREADS
 
117
            Shiboken::callCppDestructor<QObject>(Shiboken::Object::cppPointer(pyObj, pyQObjectType));
 
118
            Py_END_ALLOW_THREADS
 
119
            Shiboken::Object::setValidCpp(pyObj, false);
 
120
        }
 
121
    }
 
122
};
 
123
 
 
124
void destroyQCoreApplication()
 
125
{
 
126
    SignalManager::instance().clear();
 
127
    QCoreApplication* app = QCoreApplication::instance();
 
128
    if (!app)
 
129
        return;
 
130
 
 
131
    Shiboken::BindingManager& bm = Shiboken::BindingManager::instance();
 
132
    SbkObject* pyQApp = bm.retrieveWrapper(app);
 
133
    PyTypeObject* pyQObjectType = Shiboken::TypeResolver::get("QObject*")->pythonType();
 
134
    assert(pyQObjectType);
 
135
 
 
136
    void* data[2] = {pyQApp, pyQObjectType};
 
137
    bm.visitAllPyObjects(&destructionVisitor, &data);
 
138
 
 
139
    // in the end destroy app
 
140
    delete app;
 
141
}
 
142
 
 
143
void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base)
 
144
{
 
145
    QByteArray typeName = QByteArray(type->super.ht_type.tp_name).split('.').last();
 
146
    DynamicQMetaObject* mo = new PySide::DynamicQMetaObject(typeName, base);
 
147
    Shiboken::ObjectType::setTypeUserData(type, mo, &Shiboken::callCppDestructor<DynamicQMetaObject>);
 
148
}
 
149
 
 
150
void initQObjectSubType(SbkObjectType* type, PyObject* args, PyObject* kwds)
 
151
{
 
152
    PyTypeObject* qObjType = Shiboken::TypeResolver::get("QObject*")->pythonType();
 
153
    QByteArray className(PyString_AS_STRING(PyTuple_GET_ITEM(args, 0)));
 
154
 
 
155
    PyObject* bases = PyTuple_GET_ITEM(args, 1);
 
156
    int numBases = PyTuple_GET_SIZE(args);
 
157
    QMetaObject* baseMo = 0;
 
158
 
 
159
    for (int i = 0; i < numBases; ++i) {
 
160
        PyTypeObject* base = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
 
161
        if (PyType_IsSubtype(base, qObjType)) {
 
162
            baseMo = reinterpret_cast<QMetaObject*>(Shiboken::ObjectType::getTypeUserData(reinterpret_cast<SbkObjectType*>(base)));
 
163
            // If it's a class like QObject, QWidget, etc, use the original QMetaObject instead of the dynamic one
 
164
            // IMO this if is a bug, however it keeps the current behaviour.
 
165
            if (!Shiboken::ObjectType::isUserType(base))
 
166
                baseMo = const_cast<QMetaObject*>(baseMo->d.superdata);
 
167
            break;
 
168
        }
 
169
    }
 
170
    if (!baseMo) {
 
171
        qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData());
 
172
        return;
 
173
    }
 
174
 
 
175
    DynamicQMetaObject* mo = new PySide::DynamicQMetaObject(className.constData(), baseMo);
 
176
 
 
177
    Shiboken::ObjectType::setTypeUserData(type, mo, &Shiboken::callCppDestructor<DynamicQMetaObject>);
 
178
 
 
179
    PyObject* attrs = PyTuple_GET_ITEM(args, 2);
 
180
    PyObject* key;
 
181
    PyObject* value;
 
182
    Py_ssize_t pos = 0;
 
183
 
 
184
    typedef std::pair<const char*, PyObject*> PropPair;
 
185
    QList<PropPair> properties;
 
186
 
 
187
    Shiboken::AutoDecRef slotAttrName(PyString_FromString(PYSIDE_SLOT_LIST_ATTR));
 
188
 
 
189
    while (PyDict_Next(attrs, &pos, &key, &value)) {
 
190
        if (PyType_IsSubtype(value->ob_type, &PySidePropertyType)) {
 
191
            // Leave the properties to be register after signals because they may depend on notify signals
 
192
            properties << PropPair(PyString_AS_STRING(key), value);
 
193
        } else if (value->ob_type == &PySideSignalType) { // Register signals
 
194
            PySideSignal* data = reinterpret_cast<PySideSignal*>(value);
 
195
            const char* signalName = PyString_AS_STRING(key);
 
196
            data->signalName = strdup(signalName);
 
197
            QByteArray sig;
 
198
            sig.reserve(128);
 
199
            for (int i = 0; i < data->signaturesSize; ++i) {
 
200
                sig = signalName;
 
201
                sig += '(';
 
202
                if (data->signatures[i])
 
203
                    sig += data->signatures[i];
 
204
                sig += ')';
 
205
                if (baseMo->indexOfSignal(sig) == -1)
 
206
                    mo->addSignal(sig);
 
207
            }
 
208
        } else if (PyFunction_Check(value)) { // Register slots
 
209
            if (PyObject_HasAttr(value, slotAttrName)) {
 
210
                PyObject* signatureList = PyObject_GetAttr(value, slotAttrName);
 
211
                for(Py_ssize_t i = 0, i_max = PyList_Size(signatureList); i < i_max; ++i) {
 
212
                    PyObject* signature = PyList_GET_ITEM(signatureList, i);
 
213
                    QByteArray sig(PyString_AS_STRING(signature));
 
214
                    //slot the slot type and signature
 
215
                    QList<QByteArray> slotInfo = sig.split(' ');
 
216
                    int index = baseMo->indexOfSlot(slotInfo[1]);
 
217
                    if (index == -1)
 
218
                        mo->addSlot(slotInfo[1], slotInfo[0]);
 
219
                }
 
220
            }
 
221
        }
 
222
    }
 
223
 
 
224
    // Register properties
 
225
    foreach (PropPair propPair, properties)
 
226
        mo->addProperty(propPair.first, propPair.second);
 
227
}
 
228
 
 
229
PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name)
 
230
{
 
231
    PyObject* attr = PyObject_GenericGetAttr(self, name);
 
232
    if (attr && Property::isPropertyType(attr)) {
 
233
        PyObject *value = Property::getValue(reinterpret_cast<PySideProperty*>(attr), self);
 
234
        if (!value)
 
235
            return 0;
 
236
        Py_DECREF(attr);
 
237
        Py_INCREF(value);
 
238
        attr = value;
 
239
    }
 
240
 
 
241
    //mutate native signals to signal instance type
 
242
    if (attr && PyObject_TypeCheck(attr, &PySideSignalType)) {
 
243
        PyObject* signal = reinterpret_cast<PyObject*>(Signal::initialize(reinterpret_cast<PySideSignal*>(attr), name, self));
 
244
        PyObject_SetAttr(self, name, reinterpret_cast<PyObject*>(signal));
 
245
        return signal;
 
246
    }
 
247
 
 
248
    //search on metaobject (avoid internal attributes started with '__')
 
249
    if (!attr && !QString(PyString_AS_STRING(name)).startsWith("__")) {
 
250
        const QMetaObject* metaObject = cppSelf->metaObject();
 
251
        QByteArray cname(PyString_AS_STRING(name));
 
252
        cname += '(';
 
253
        //signal
 
254
        QList<QMetaMethod> signalList;
 
255
        for(int i=0, i_max = metaObject->methodCount(); i < i_max; i++) {
 
256
            QMetaMethod method = metaObject->method(i);
 
257
            if (QString(method.signature()).startsWith(cname)) {
 
258
                if (method.methodType() == QMetaMethod::Signal) {
 
259
                    signalList.append(method);
 
260
                } else {
 
261
                    PySideMetaFunction* func = MetaFunction::newObject(cppSelf, i);
 
262
                    if (func) {
 
263
                        PyObject_SetAttr(self, name, (PyObject*)func);
 
264
                        return (PyObject*)func;
 
265
                    }
 
266
                }
 
267
            }
 
268
        }
 
269
        if (signalList.size() > 0) {
 
270
            PyObject* pySignal = reinterpret_cast<PyObject*>(Signal::newObjectFromMethod(self, signalList));
 
271
            PyObject_SetAttr(self, name, pySignal);
 
272
            return pySignal;
 
273
        }
 
274
    }
 
275
    return attr;
 
276
}
 
277
 
102
278
} //namespace PySide
103
279