From b00e63dbe8d0acaae503e63d614ee20b9e9ede2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sat, 6 Sep 2014 21:01:23 +0200 Subject: More sync from quickmods Also a small VersionSelectDialog refactor --- depends/LogicalGui/LogicalGui.h | 254 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 depends/LogicalGui/LogicalGui.h (limited to 'depends/LogicalGui/LogicalGui.h') diff --git a/depends/LogicalGui/LogicalGui.h b/depends/LogicalGui/LogicalGui.h new file mode 100644 index 00000000..4034459e --- /dev/null +++ b/depends/LogicalGui/LogicalGui.h @@ -0,0 +1,254 @@ +/* Copyright 2014 Jan Dalheimer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#if QT_VERSION == QT_VERSION_CHECK(5, 1, 1) +#include <5.1.1/QtCore/private/qobject_p.h> +#elif QT_VERSION == QT_VERSION_CHECK(5, 2, 0) +#include <5.2.0/QtCore/private/qobject_p.h> +#elif QT_VERSION == QT_VERSION_CHECK(5, 2, 1) +#include <5.2.1/QtCore/private/qobject_p.h> +#elif QT_VERSION == QT_VERSION_CHECK(5, 3, 0) +#include <5.3.0/QtCore/private/qobject_p.h> +#elif QT_VERSION == QT_VERSION_CHECK(5, 3, 1) +#include <5.3.1/QtCore/private/qobject_p.h> +#else +#error Please add support for this version of Qt +#endif + +class Bindable +{ + friend class tst_LogicalGui; + +public: + Bindable(Bindable *parent = 0) : m_parent(parent) + { + } + virtual ~Bindable() + { + } + + void setBindableParent(Bindable *parent) + { + m_parent = parent; + } + + void bind(const QString &id, const QObject *receiver, const char *methodSignature) + { + auto mo = receiver->metaObject(); + Q_ASSERT_X(mo, "Bindable::bind", + "Invalid metaobject. Did you forget the QObject macro?"); + const QMetaMethod method = mo->method(mo->indexOfMethod( + QMetaObject::normalizedSignature(methodSignature + 1).constData())); + Q_ASSERT_X(method.isValid(), "Bindable::bind", "Invalid method signature"); + m_bindings.insert(id, Binding(receiver, method)); + } + template + void bind(const QString &id, + const typename QtPrivate::FunctionPointer::Object *receiver, Func slot) + { + typedef QtPrivate::FunctionPointer SlotType; + m_bindings.insert( + id, + Binding(receiver, new QtPrivate::QSlotObject(slot))); + } + template void bind(const QString &id, Func slot) + { + typedef QtPrivate::FunctionPointer SlotType; + m_bindings.insert( + id, + Binding(nullptr, new QtPrivate::QSlotObject(slot))); + } + void unbind(const QString &id) + { + m_bindings.remove(id); + } + +private: + struct Binding + { + Binding(const QObject *receiver, const QMetaMethod &method) + : receiver(receiver), method(method) + { + } + Binding(const QObject *receiver, QtPrivate::QSlotObjectBase *object) + : receiver(receiver), object(object) + { + } + Binding() + { + } + const QObject *receiver; + QMetaMethod method; + QtPrivate::QSlotObjectBase *object = nullptr; + }; + QMap m_bindings; + + Bindable *m_parent; + +private: + inline Qt::ConnectionType connectionType(const QObject *receiver) + { + return receiver == nullptr ? Qt::DirectConnection + : (QThread::currentThread() == receiver->thread() + ? Qt::DirectConnection + : Qt::BlockingQueuedConnection); + } + +protected: + template Ret wait(const QString &id, Params... params) + { + static_assert(!std::is_same::value, "You need to use Bindable::waitVoid"); + + if (!m_bindings.contains(id) && m_parent) + { + return m_parent->wait(id, params...); + } + Q_ASSERT(m_bindings.contains(id)); + const auto binding = m_bindings[id]; + const Qt::ConnectionType type = connectionType(binding.receiver); + Ret ret; + if (binding.object) + { + void *args[] = {&ret, + const_cast(reinterpret_cast(¶ms))...}; + if (type == Qt::BlockingQueuedConnection) + { + QSemaphore semaphore; + QMetaCallEvent *ev = + new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore); + QCoreApplication::postEvent(const_cast(binding.receiver), ev); + semaphore.acquire(); + } + else + { + binding.object->call(const_cast(binding.receiver), args); + } + } + else + { + const QMetaMethod method = binding.method; + Q_ASSERT_X(method.parameterCount() == sizeof...(params), "Bindable::wait", + qPrintable(QString("Incompatible argument count (expected %1, got %2)") + .arg(method.parameterCount(), sizeof...(params)))); + Q_ASSERT_X( + qMetaTypeId() != QMetaType::UnknownType, "Bindable::wait", + "Requested return type is not registered, please use the Q_DECLARE_METATYPE " + "macro to make it known to Qt's meta-object system"); + Q_ASSERT_X( + method.returnType() == qMetaTypeId() || + QMetaType::hasRegisteredConverterFunction(method.returnType(), + qMetaTypeId()), + "Bindable::wait", + qPrintable( + QString( + "Requested return type (%1) is incompatible method return type (%2)") + .arg(QMetaType::typeName(qMetaTypeId()), + QMetaType::typeName(method.returnType())))); + const auto retArg = QReturnArgument( + QMetaType::typeName(qMetaTypeId()), + ret); // because Q_RETURN_ARG doesn't work with templates... + method.invoke(const_cast(binding.receiver), type, retArg, + Q_ARG(Params, params)...); + } + return ret; + } + template + typename std::enable_if::type waitVoid(const QString &id, + Params... params) + { + if (!m_bindings.contains(id) && m_parent) + { + m_parent->waitVoid(id, params...); + return; + } + Q_ASSERT(m_bindings.contains(id)); + const auto binding = m_bindings[id]; + const Qt::ConnectionType type = connectionType(binding.receiver); + if (binding.object) + { + void *args[] = {0, const_cast(reinterpret_cast(¶ms))...}; + if (type == Qt::BlockingQueuedConnection) + { + QSemaphore semaphore; + QMetaCallEvent *ev = + new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore); + QCoreApplication::postEvent(const_cast(binding.receiver), ev); + semaphore.acquire(); + } + else + { + binding.object->call(const_cast(binding.receiver), args); + } + } + else + { + const QMetaMethod method = binding.method; + Q_ASSERT_X(method.parameterCount() == sizeof...(params), "Bindable::wait", + qPrintable(QString("Incompatible argument count (expected %1, got %2)") + .arg(method.parameterCount(), sizeof...(params)))); + method.invoke(const_cast(binding.receiver), type, + Q_ARG(Params, params)...); + } + } + void waitVoid(const QString &id) + { + if (!m_bindings.contains(id) && m_parent) + { + m_parent->waitVoid(id); + return; + } + Q_ASSERT(m_bindings.contains(id)); + const auto binding = m_bindings[id]; + const Qt::ConnectionType type = connectionType(binding.receiver); + if (binding.object) + { + void *args[] = {0}; + if (type == Qt::BlockingQueuedConnection) + { + QSemaphore semaphore; + QMetaCallEvent *ev = + new QMetaCallEvent(binding.object, nullptr, -1, 0, 0, args, &semaphore); + QCoreApplication::postEvent(const_cast(binding.receiver), ev); + semaphore.acquire(); + } + else + { + binding.object->call(const_cast(binding.receiver), args); + } + } + else + { + const QMetaMethod method = binding.method; + Q_ASSERT_X(method.parameterCount() == 0, "Bindable::wait", + qPrintable(QString("Incompatible argument count (expected %1, got %2)") + .arg(method.parameterCount(), 0))); + method.invoke(const_cast(binding.receiver), type); + } + } +}; + +// used frequently +Q_DECLARE_METATYPE(bool *) -- cgit v1.2.3