diff options
author | Hugo Lima <hugo.lima@openbossa.org> | 2009-12-15 19:24:30 -0200 |
---|---|---|
committer | Hugo Lima <hugo.lima@openbossa.org> | 2009-12-16 15:02:42 -0200 |
commit | c8e908097207d8852e17e99585ae88a17e3af144 (patch) | |
tree | d9aaf4d99ad3711654c98ef5ae6af8da2d4b9e9f /libpyside/signalmanager.cpp | |
parent | d90b6ba47409c7cc461bb6c200f8e41b9a917088 (diff) |
Initial port of signal slots infrastructure from PySide to the Shiboken version.
Diffstat (limited to 'libpyside/signalmanager.cpp')
-rw-r--r-- | libpyside/signalmanager.cpp | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/libpyside/signalmanager.cpp b/libpyside/signalmanager.cpp new file mode 100644 index 000000000..711465549 --- /dev/null +++ b/libpyside/signalmanager.cpp @@ -0,0 +1,172 @@ +/* +* 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 "signalmanager.h" +#include "proxyslot.h" +#include <QHash> +#include <QStringList> +#include <QDebug> + +#if QSLOT_CODE != 1 || QSIGNAL_CODE != 2 +#error QSLOT_CODE and/or QSIGNAL_CODE changed! change the hardcoded stuff to the correct value! +#endif +#define PYSIDE_SLOT '1' +#define PYSIDE_SIGNAL '2' +#include "typeresolver.h" +#include "signalslotconnection.h" + +using namespace PySide; + +static bool checkSignal(const char* signal) +{ + if (signal[0] != PYSIDE_SIGNAL) { + PyErr_SetString(PyExc_TypeError, "Use the function PySide.QtCore.SIGNAL on signals"); + return false; + } + return true; +} + +QStringList PySide::getArgsFromSignature(const char* signature) +{ + QString qsignature(signature); + QStringList result; + QRegExp splitRegex("\\s*,\\s*"); + + if (qsignature.contains("()") || qsignature.contains("(void)")) { + return result; + } else if (qsignature.contains('(')) { + //get args types + QString types = qsignature.replace(QRegExp(".+\\((.*)\\)"), "\\1"); + result = types.split(splitRegex); + } + return result; +} + +struct SignalManager::SignalManagerPrivate +{ + QHash<QObject*, ProxySlot*> m_proxies; + + ProxySlot* findProxy(QObject* signalSource) + { + ProxySlot* proxy = m_proxies.value(signalSource); + if (!proxy) { + proxy = new ProxySlot(signalSource); + m_proxies[signalSource] = proxy; + QObject::connect(signalSource, SIGNAL(destroyed()), proxy, SLOT(deleteLater())); + } + return proxy; + } +}; + +SignalManager::SignalManager() : m_d(new SignalManagerPrivate) +{ +} + +SignalManager::~SignalManager() +{ + delete m_d; +} + +SignalManager& SignalManager::instance() +{ + static SignalManager me; + return me; +} + +bool SignalManager::connect(QObject* source, const char* signal, PyObject* callback, Qt::ConnectionType type) +{ + if (!checkSignal(signal)) + return false; + signal++; + + ProxySlot* proxy = m_d->findProxy(source); + AbstractQObjectConnection* connection = new SignalSlotConnection(source, signal, callback, type); + return proxy->connect(connection); +} + +bool SignalManager::connect(QObject* source, const char* signal, QObject* receiver, const char* slot, Qt::ConnectionType type) +{ + if (!checkSignal(signal)) + return false; + + if (!QMetaObject::checkConnectArgs(signal, slot)) + return false; + int signal_index = source->metaObject()->indexOfSignal(signal); + int slot_index = receiver->metaObject()->indexOfSlot(slot); + + bool retval; + if (signal_index != -1 && slot_index != -1) { + // C++ -> C++ connection + retval = QMetaObject::connect(source, signal_index, + receiver, slot_index, type); + } else { + // We have a python slot or signal + ProxySlot* proxy = m_d->findProxy(source); + AbstractQObjectConnection* connection = 0; + retval = proxy->connect(connection); + } + return retval; + +} + +bool SignalManager::emitSignal(QObject* source, const char* signal, PyObject* args) +{ + if (checkSignal(signal)) + return false; + + int argsGiven = PySequence_Size(args); + + //search native signal + int signalIndex = source->metaObject()->indexOfSignal(signal+1); + if (signalIndex == -1) { + // dynamic signal + qDebug() << "Dynamic signal not implemented yet!"; + } else { + // a C++ signal + QStringList argTypes = getArgsFromSignature(signal); + void* signalArgs[argsGiven+1]; + + for (int i = 0; i < argsGiven; i++) + signalArgs[i] = TypeResolver::get(argTypes[i])->toCpp(PySequence_GetItem(args, i)); + + QMetaObject::activate(source, signalIndex, signalArgs); + return true; + } + return false; +} + +void PySide::SignalManager::removeProxySlot(QObject* signalSource) +{ + m_d->m_proxies.remove(signalSource); +} |