2018-03-04 13:31:49 +01:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskMetaInvokable.h"
|
|
|
|
#include "QskMetaFunction.h"
|
|
|
|
#include "QskMetaMethod.h"
|
|
|
|
|
|
|
|
#include <QMetaMethod>
|
|
|
|
#include <QVector>
|
|
|
|
#include <QObject>
|
2018-03-09 16:20:33 +01:00
|
|
|
#include <QThread>
|
2018-03-04 13:31:49 +01:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
class Function : public QskMetaFunction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
inline Function( void* functionCall ):
|
|
|
|
QskMetaFunction( static_cast< FunctionCall* >( functionCall ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void ref( void* functionCall )
|
|
|
|
{
|
|
|
|
if ( functionCall )
|
|
|
|
static_cast< FunctionCall* >( functionCall )->ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void deref( void* functionCall )
|
|
|
|
{
|
|
|
|
if ( functionCall )
|
|
|
|
static_cast< FunctionCall* >( functionCall )->destroyIfLastRef();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-03-09 12:24:18 +01:00
|
|
|
static void qskInvokeSetProperty( QObject* object,
|
|
|
|
const QMetaObject* metaObject, int propertyIndex,
|
|
|
|
void* args[], Qt::ConnectionType connectionType )
|
|
|
|
{
|
2018-03-09 16:20:33 +01:00
|
|
|
int invokeType = connectionType & 0x3;
|
|
|
|
|
|
|
|
if ( invokeType == Qt::AutoConnection )
|
|
|
|
{
|
|
|
|
invokeType = ( object->thread() != QThread::currentThread() )
|
|
|
|
? Qt::QueuedConnection : Qt::DirectConnection;
|
|
|
|
}
|
|
|
|
|
2018-03-09 12:24:18 +01:00
|
|
|
#if 1
|
2018-03-09 16:20:33 +01:00
|
|
|
if ( invokeType != Qt::DirectConnection )
|
2018-03-09 12:24:18 +01:00
|
|
|
return; // TODO ...
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( propertyIndex >= 0 && object->metaObject() == metaObject )
|
|
|
|
{
|
|
|
|
int status = -1;
|
|
|
|
int flags = 0;
|
2018-03-09 16:20:33 +01:00
|
|
|
void* argv[] = { args[1], nullptr, &status, &flags };
|
2018-03-09 12:24:18 +01:00
|
|
|
|
|
|
|
QMetaObject::metacall( object,
|
|
|
|
QMetaObject::WriteProperty, propertyIndex, argv );
|
|
|
|
}
|
|
|
|
}
|
2018-03-04 13:31:49 +01:00
|
|
|
|
|
|
|
QskMetaInvokable::QskMetaInvokable( const QMetaMethod& method ):
|
2018-03-09 12:24:18 +01:00
|
|
|
m_metaData { method.enclosingMetaObject(), method.methodIndex() },
|
2018-03-04 13:31:49 +01:00
|
|
|
m_type( MetaMethod )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaInvokable::QskMetaInvokable( const QObject* object, const char* methodName ):
|
|
|
|
QskMetaInvokable( QskMetaMethod::method( object, methodName ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaInvokable::QskMetaInvokable( const QMetaObject* metaObject, const char* methodName ):
|
|
|
|
QskMetaInvokable( QskMetaMethod::method( metaObject, methodName ) )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-03-09 12:24:18 +01:00
|
|
|
QskMetaInvokable::QskMetaInvokable( const QMetaProperty& property ):
|
|
|
|
m_metaData { property.enclosingMetaObject(), property.propertyIndex() },
|
|
|
|
m_type( MetaProperty )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-03-04 13:31:49 +01:00
|
|
|
QskMetaInvokable::QskMetaInvokable( const QskMetaFunction& function ):
|
|
|
|
m_functionData { function.functionCall() },
|
|
|
|
m_type( MetaFunction )
|
|
|
|
{
|
|
|
|
Function::ref( m_functionData.functionCall );
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaInvokable::QskMetaInvokable( const QskMetaInvokable& other ):
|
|
|
|
m_type( other.m_type )
|
|
|
|
{
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
2018-03-09 12:24:18 +01:00
|
|
|
case MetaProperty:
|
2018-03-04 13:31:49 +01:00
|
|
|
{
|
2018-03-09 12:24:18 +01:00
|
|
|
m_metaData.metaObject = other.m_metaData.metaObject;
|
|
|
|
m_metaData.index = other.m_metaData.index;
|
2018-03-04 13:31:49 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MetaFunction:
|
|
|
|
{
|
|
|
|
m_functionData.functionCall = other.m_functionData.functionCall;
|
|
|
|
Function::ref( m_functionData.functionCall );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaInvokable::~QskMetaInvokable()
|
|
|
|
{
|
|
|
|
if ( m_type == MetaFunction )
|
|
|
|
Function::deref( m_functionData.functionCall );
|
|
|
|
}
|
|
|
|
|
|
|
|
QskMetaInvokable& QskMetaInvokable::operator=( const QskMetaInvokable& other )
|
|
|
|
{
|
|
|
|
switch( other.m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
2018-03-09 12:24:18 +01:00
|
|
|
case MetaProperty:
|
2018-03-04 13:31:49 +01:00
|
|
|
{
|
|
|
|
if ( m_type == MetaFunction )
|
|
|
|
Function::deref( m_functionData.functionCall );
|
|
|
|
|
2018-03-09 12:24:18 +01:00
|
|
|
m_metaData.metaObject = other.m_metaData.metaObject;
|
|
|
|
m_metaData.index = other.m_metaData.index;
|
2018-03-04 13:31:49 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MetaFunction:
|
|
|
|
{
|
|
|
|
if ( m_type == MetaFunction )
|
|
|
|
Function::deref( m_functionData.functionCall );
|
|
|
|
|
|
|
|
m_functionData.functionCall = other.m_functionData.functionCall;
|
|
|
|
Function::ref( m_functionData.functionCall );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
if ( m_type == MetaFunction )
|
|
|
|
Function::deref( m_functionData.functionCall );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_type = other.m_type;
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskMetaInvokable::operator==( const QskMetaInvokable& other ) const
|
|
|
|
{
|
2018-03-09 12:24:18 +01:00
|
|
|
if ( m_type != other.m_type )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch( m_type )
|
2018-03-04 13:31:49 +01:00
|
|
|
{
|
2018-03-09 12:24:18 +01:00
|
|
|
case MetaMethod:
|
|
|
|
case MetaProperty:
|
2018-03-04 13:31:49 +01:00
|
|
|
{
|
2018-03-09 12:24:18 +01:00
|
|
|
return ( m_metaData.metaObject == other.m_metaData.metaObject )
|
|
|
|
&& ( m_metaData.index == other.m_metaData.index );
|
2018-03-04 13:31:49 +01:00
|
|
|
}
|
2018-03-09 12:24:18 +01:00
|
|
|
case MetaFunction:
|
2018-03-04 13:31:49 +01:00
|
|
|
{
|
|
|
|
return m_functionData.functionCall == other.m_functionData.functionCall;
|
|
|
|
}
|
2018-03-09 12:24:18 +01:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2018-03-04 13:31:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskMetaInvokable::isNull() const
|
|
|
|
{
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
2018-03-09 12:24:18 +01:00
|
|
|
case MetaProperty:
|
2018-03-04 13:31:49 +01:00
|
|
|
{
|
2018-03-09 12:24:18 +01:00
|
|
|
const auto& d = m_metaData;
|
2018-03-04 13:31:49 +01:00
|
|
|
|
2018-03-09 12:24:18 +01:00
|
|
|
if ( d.metaObject == nullptr || d.index < 0 )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const int count = ( m_type == MetaMethod )
|
|
|
|
? d.metaObject->methodCount() : d.metaObject->propertyCount();
|
2018-03-04 13:31:49 +01:00
|
|
|
|
2018-03-09 12:24:18 +01:00
|
|
|
return d.index >= count;
|
|
|
|
}
|
2018-03-04 13:31:49 +01:00
|
|
|
case MetaFunction:
|
|
|
|
{
|
|
|
|
return m_functionData.functionCall == nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskMetaInvokable::reset()
|
|
|
|
{
|
|
|
|
if ( m_type == MetaFunction )
|
|
|
|
Function::deref( m_functionData.functionCall );
|
|
|
|
|
|
|
|
m_type = Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector< int > QskMetaInvokable::parameterTypes() const
|
|
|
|
{
|
|
|
|
QVector< int > paramTypes;
|
|
|
|
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
|
|
|
{
|
2018-03-08 08:37:44 +01:00
|
|
|
// should be doable without QMetaMethod. TODO ...
|
|
|
|
const auto method = QskMetaInvokable::method();
|
2018-03-04 13:31:49 +01:00
|
|
|
|
2018-03-08 08:37:44 +01:00
|
|
|
const int paramCount = method.parameterCount();
|
|
|
|
if ( paramCount > 0 )
|
|
|
|
{
|
2018-03-04 13:31:49 +01:00
|
|
|
paramTypes.reserve( paramCount );
|
2018-03-08 08:37:44 +01:00
|
|
|
|
2018-03-04 13:31:49 +01:00
|
|
|
for ( int i = 0; i < paramCount; i++ )
|
|
|
|
paramTypes += method.parameterType( i );
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2018-03-09 12:24:18 +01:00
|
|
|
case MetaProperty:
|
|
|
|
{
|
|
|
|
// should be doable without QMetaProperty. TODO ...
|
|
|
|
const auto property = QskMetaInvokable::property();
|
|
|
|
if ( property.isWritable() )
|
|
|
|
{
|
|
|
|
paramTypes.reserve( 1 );
|
|
|
|
paramTypes += property.userType();
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2018-03-04 13:31:49 +01:00
|
|
|
case MetaFunction:
|
|
|
|
{
|
2018-03-08 08:37:44 +01:00
|
|
|
auto types = function().parameterTypes();
|
2018-03-04 13:31:49 +01:00
|
|
|
if ( types )
|
|
|
|
{
|
|
|
|
while ( *types )
|
|
|
|
paramTypes += *types++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return paramTypes;
|
|
|
|
}
|
|
|
|
|
2018-03-08 08:37:44 +01:00
|
|
|
int QskMetaInvokable::returnType() const
|
|
|
|
{
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
|
|
|
{
|
|
|
|
return method().returnType();
|
|
|
|
}
|
|
|
|
case MetaFunction:
|
|
|
|
{
|
|
|
|
return function().returnType();
|
|
|
|
}
|
2018-03-09 12:24:18 +01:00
|
|
|
case MetaProperty:
|
2018-03-08 08:37:44 +01:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
return QMetaType::Void;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 16:20:33 +01:00
|
|
|
QByteArray QskMetaInvokable::name() const
|
|
|
|
{
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
|
|
|
{
|
|
|
|
return method().name();
|
|
|
|
}
|
|
|
|
case MetaProperty:
|
|
|
|
{
|
|
|
|
return property().name();
|
|
|
|
}
|
|
|
|
case MetaFunction:
|
|
|
|
{
|
|
|
|
// what to do here ???
|
|
|
|
return QByteArray();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return QByteArray();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-03-08 08:37:44 +01:00
|
|
|
QMetaMethod QskMetaInvokable::method() const
|
|
|
|
{
|
2018-03-09 12:24:18 +01:00
|
|
|
if ( m_type == MetaMethod && m_metaData.metaObject )
|
|
|
|
return m_metaData.metaObject->method( m_metaData.index );
|
2018-03-08 08:37:44 +01:00
|
|
|
|
|
|
|
return QMetaMethod();
|
|
|
|
}
|
|
|
|
|
2018-03-09 12:24:18 +01:00
|
|
|
QMetaProperty QskMetaInvokable::property() const
|
|
|
|
{
|
|
|
|
if ( m_type == MetaProperty && m_metaData.metaObject )
|
|
|
|
return m_metaData.metaObject->property( m_metaData.index );
|
|
|
|
|
|
|
|
return QMetaProperty();
|
|
|
|
}
|
|
|
|
|
2018-03-08 08:37:44 +01:00
|
|
|
QskMetaFunction QskMetaInvokable::function() const
|
|
|
|
{
|
|
|
|
if ( m_type == MetaFunction && m_functionData.functionCall )
|
|
|
|
{
|
|
|
|
Function function( m_functionData.functionCall );
|
|
|
|
return *static_cast< QskMetaFunction* >( &function );
|
|
|
|
}
|
|
|
|
|
|
|
|
return QskMetaFunction();
|
|
|
|
}
|
2018-03-04 13:31:49 +01:00
|
|
|
|
|
|
|
void QskMetaInvokable::invoke( QObject* object, void* args[],
|
|
|
|
Qt::ConnectionType connectionType )
|
|
|
|
{
|
|
|
|
if ( isNull() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch( m_type )
|
|
|
|
{
|
|
|
|
case MetaMethod:
|
|
|
|
{
|
2018-03-09 12:24:18 +01:00
|
|
|
QskMetaMethod::invoke( object, m_metaData.metaObject,
|
|
|
|
m_metaData.index, args, connectionType );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MetaProperty:
|
|
|
|
{
|
|
|
|
qskInvokeSetProperty( object,
|
|
|
|
m_metaData.metaObject, m_metaData.index,
|
|
|
|
args, connectionType );
|
2018-03-04 13:31:49 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MetaFunction:
|
|
|
|
{
|
|
|
|
if ( m_functionData.functionCall )
|
|
|
|
{
|
|
|
|
Function function( m_functionData.functionCall );
|
|
|
|
function.invoke( object, args, connectionType );
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|