/*
Copyright (C) 2019 Filippo Cucchetto.
Contact: https://github.com/filcuc/dotherside
This file is part of the DOtherSide library.
The DOtherSide library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the license, or (at your opinion) any later version.
The DOtherSide library 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 the DOtherSide library. If not, see .
*/
#include "DOtherSide/DosQObjectImpl.h"
#include "DOtherSide/DosQMetaObject.h"
#include
#include
#include
namespace DOS {
DosQObjectImpl::DosQObjectImpl(ParentMetaCall parentMetaCall,
std::shared_ptr metaObject,
void *dObjectPointer,
DObjectCallback dObjectCallback)
: m_parentMetaCall(std::move(parentMetaCall))
, m_metaObject(std::move(metaObject))
, m_dObjectPointer(dObjectPointer)
, m_dObjectCallback(dObjectCallback)
{
}
bool DosQObjectImpl::emitSignal(QObject *emitter, const QString &name, const std::vector &args)
{
const QMetaMethod method = m_metaObject->signal(name);
if (!method.isValid())
return false;
Q_ASSERT(name.toUtf8() == method.name());
std::vector arguments(args.size() + 1, nullptr); // +1 for the result at pos 0
for (size_t i = 0; i < args.size(); ++i)
arguments[i + 1] = const_cast(args[i].constData()); // Extract inner void*
QMetaObject::activate(emitter, method.methodIndex(), arguments.data());
return true;
}
const QMetaObject *DosQObjectImpl::metaObject() const
{
return m_metaObject->metaObject();
}
int DosQObjectImpl::qt_metacall(QMetaObject::Call callType, int index, void **args)
{
if (m_parentMetaCall(callType, index, args) < 0)
return -1;
switch (callType) {
case QMetaObject::InvokeMetaMethod:
executeSlot(index, args);
break;
case QMetaObject::ReadProperty:
readProperty(index, args);
break;
case QMetaObject::WriteProperty:
writeProperty(index, args);
break;
default:
return -1;
}
return -1;
}
bool DosQObjectImpl::executeSlot(int index, void **args)
{
const QMetaObject *const mo = this->metaObject();
const QMetaMethod method = mo->method(index);
if (!method.isValid()) {
qDebug() << "C++: executeSlot: invalid method";
return false;
}
return executeSlot(method, args);
}
bool DosQObjectImpl::executeSlot(const QMetaMethod &method, void **args, int argumentsOffset)
{
Q_ASSERT(method.isValid());
const bool hasReturnType = method.returnType() != QMetaType::Void;
std::vector arguments;
arguments.reserve(method.parameterCount());
for (int i = 0, j = argumentsOffset; i < method.parameterCount(); ++i, ++j) {
QVariant argument(method.parameterType(i), args[j]);
arguments.emplace_back(std::move(argument));
}
const QVariant result = executeSlot(method.name(), arguments); // Execute method
if (hasReturnType && result.isValid()) {
QMetaType::construct(method.returnType(), args[0], result.constData());
}
return true;
}
QVariant DosQObjectImpl::executeSlot(const QString &name, const std::vector &args)
{
QVariant result;
if (!m_dObjectCallback || !m_dObjectPointer)
return result;
// prepare slot name
QVariant slotName(name);
// prepare void* for the QVariants
std::vector argumentsAsVoidPointers;
argumentsAsVoidPointers.reserve(args.size() + 1);
argumentsAsVoidPointers.emplace_back(&result);
for (size_t i = 0; i < args.size(); ++i)
argumentsAsVoidPointers.emplace_back((void *)(&args[i]));
// send them to the binding handler
m_dObjectCallback(m_dObjectPointer, &slotName, static_cast(argumentsAsVoidPointers.size()), &argumentsAsVoidPointers[0]);
return result;
}
bool DosQObjectImpl::readProperty(int index, void **args)
{
const QMetaObject *const mo = metaObject();
const QMetaProperty property = mo->property(index);
if (!property.isValid() || !property.isReadable())
return false;
const QMetaMethod method = m_metaObject->readSlot(property.name());
if (!method.isValid()) {
qDebug() << "C++: readProperty: invalid read method for property " << property.name();
return false;
}
return executeSlot(method, args);
}
bool DosQObjectImpl::writeProperty(int index, void **args)
{
const QMetaObject *const mo = metaObject();
const QMetaProperty property = mo->property(index);
if (!property.isValid() || !property.isWritable())
return false;
const QMetaMethod method = m_metaObject->writeSlot(property.name());
if (!method.isValid()) {
qDebug() << "C++: writeProperty: invalid write method for property " << property.name();
return false;
}
return executeSlot(method, args, 0);
}
}