aboutsummaryrefslogtreecommitdiffstats
path: root/libpyside/signalmanager.cpp
diff options
context:
space:
mode:
authorHugo Lima <hugo.lima@openbossa.org>2009-12-15 19:24:30 -0200
committerHugo Lima <hugo.lima@openbossa.org>2009-12-16 15:02:42 -0200
commitc8e908097207d8852e17e99585ae88a17e3af144 (patch)
treed9aaf4d99ad3711654c98ef5ae6af8da2d4b9e9f /libpyside/signalmanager.cpp
parentd90b6ba47409c7cc461bb6c200f8e41b9a917088 (diff)
Initial port of signal slots infrastructure from PySide to the Shiboken version.
Diffstat (limited to 'libpyside/signalmanager.cpp')
-rw-r--r--libpyside/signalmanager.cpp172
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);
+}