property WRITE accessors added to QskMetaInvokable

This commit is contained in:
Uwe Rathmann 2018-03-09 12:24:18 +01:00
parent 0e832e27f8
commit b788f7da2c
8 changed files with 193 additions and 67 deletions

View File

@ -4,25 +4,35 @@
*****************************************************************************/ *****************************************************************************/
#include "Invoker.h" #include "Invoker.h"
#include <QThread> #include <QThread>
#include <QMetaProperty>
Invoker::Invoker( QObject* parent ): Invoker::Invoker( QObject* parent ):
QObject( parent ) QObject( parent )
{ {
} }
void Invoker::addCallback( const QObject* object, void Invoker::addFunctionCall( const QObject* object,
const QskMetaFunction& function ) const QskMetaFunction& function )
{ {
m_callbacks.append( QskMetaCallback( object, function ) ); m_callbacks.append( QskMetaCallback( object, function ) );
} }
void Invoker::addCallback( const QObject* object, void Invoker::addMethodCall( const QObject* object,
const char* methodName ) const char* methodName )
{ {
m_callbacks.append( QskMetaCallback( object, methodName ) ); m_callbacks.append( QskMetaCallback( object, methodName ) );
} }
void Invoker::addPropertyCall( const QObject* object,
const char* property )
{
const auto* mo = object->metaObject();
auto metaProperty = mo->property( mo->indexOfProperty( property ) );
m_callbacks.append( QskMetaCallback( object, metaProperty ) );
}
void Invoker::invoke( qreal realValue, int intValue, void Invoker::invoke( qreal realValue, int intValue,
Qt::ConnectionType connectionType ) Qt::ConnectionType connectionType )
{ {

View File

@ -17,9 +17,11 @@ class Invoker : public QObject
public: public:
Invoker( QObject* parent = nullptr ); Invoker( QObject* parent = nullptr );
void addCallback( const QskMetaFunction& ); void addFunctionCall( const QskMetaFunction& );
void addCallback( const QObject*, const QskMetaFunction& ); void addFunctionCall( const QObject*, const QskMetaFunction& );
void addCallback( const QObject*, const char* methodName );
void addMethodCall( const QObject*, const char* methodName );
void addPropertyCall( const QObject*, const char* property );
void invoke( qreal d, int i, Qt::ConnectionType ); void invoke( qreal d, int i, Qt::ConnectionType );
@ -27,9 +29,9 @@ private:
QVector< QskMetaCallback > m_callbacks; QVector< QskMetaCallback > m_callbacks;
}; };
inline void Invoker::addCallback( const QskMetaFunction& function ) inline void Invoker::addFunctionCall( const QskMetaFunction& function )
{ {
addCallback( this, function ); addFunctionCall( this, function );
} }
#endif #endif

View File

@ -1,5 +1,7 @@
include( $${PWD}/../playground.pri ) include( $${PWD}/../playground.pri )
QMAKE_MOC_OPTIONS += -nw # disable warning about missing READ
TARGET = invoker TARGET = invoker
HEADERS += \ HEADERS += \

View File

@ -43,6 +43,10 @@ class MyObject : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY( int number WRITE setNumber )
Q_PROPERTY( qreal value WRITE setValue )
Q_PROPERTY( QString valueString WRITE setValueString )
public: public:
MyObject( QObject* parent = nullptr ): MyObject( QObject* parent = nullptr ):
QObject( parent ) QObject( parent )
@ -54,6 +58,21 @@ public:
qDebug() << "invokable" << d << i; qDebug() << "invokable" << d << i;
} }
void setNumber( int number )
{
qDebug() << "setNumber" << number;
}
void setValue( qreal value )
{
qDebug() << "setValue" << value;
}
void setValueString( const QString& s )
{
qDebug() << "setValueString" << s;
}
public Q_SLOTS: public Q_SLOTS:
void print0( double d, int i ) const void print0( double d, int i ) const
{ {
@ -97,46 +116,52 @@ public:
m_thread( new QThread( this ) ) m_thread( new QThread( this ) )
{ {
#if 1 #if 1
m_invoker.addCallback( m_object, "print0(double,int)" ); m_invoker.addPropertyCall( m_object, "number" );
m_invoker.addCallback( m_object, "print1(double,int)" ); m_invoker.addPropertyCall( m_object, "value" );
m_invoker.addCallback( m_object, SLOT(print2(int,double)) ); m_invoker.addPropertyCall( m_object, "valueString" );
m_invoker.addCallback( m_object, "print3(double)" ); #endif
m_invoker.addCallback( m_object, "print4(int)" );
m_invoker.addCallback( m_object, "print4(int)" ); #if 1
m_invoker.addCallback( m_object, "printS(QString)" ); m_invoker.addMethodCall( m_object, "print0(double,int)" );
m_invoker.addCallback( m_object, "printInvokable(double,int)" ); m_invoker.addMethodCall( m_object, "print1(double,int)" );
m_invoker.addMethodCall( m_object, SLOT(print2(int,double)) );
m_invoker.addMethodCall( m_object, "print3(double)" );
m_invoker.addMethodCall( m_object, "print4(int)" );
m_invoker.addMethodCall( m_object, "print4(int)" );
m_invoker.addMethodCall( m_object, "printS(QString)" );
m_invoker.addMethodCall( m_object, "printInvokable(double,int)" );
#endif #endif
#if 1 #if 1
auto f = [this]( int i, double d ) { qDebug() << i << d << ( ++m_num ); }; auto f = [this]( int i, double d ) { qDebug() << i << d << ( ++m_num ); };
m_invoker.addCallback( m_object, &MyObject::print0 ); m_invoker.addFunctionCall( m_object, &MyObject::print0 );
m_invoker.addCallback( m_object, &MyObject::print1 ); m_invoker.addFunctionCall( m_object, &MyObject::print1 );
m_invoker.addCallback( QskMetaFunction() ); m_invoker.addFunctionCall( QskMetaFunction() );
m_invoker.addCallback( debugNone1 ); m_invoker.addFunctionCall( debugNone1 );
m_invoker.addCallback( debugNone2 ); m_invoker.addFunctionCall( debugNone2 );
m_invoker.addCallback( debugValue ); m_invoker.addFunctionCall( debugValue );
m_invoker.addCallback( debugValueI1 ); m_invoker.addFunctionCall( debugValueI1 );
m_invoker.addCallback( debugValueI2 ); m_invoker.addFunctionCall( debugValueI2 );
m_invoker.addCallback( debugValueD ); m_invoker.addFunctionCall( debugValueD );
m_invoker.addCallback( m_object, &MyObject::print0 ); m_invoker.addFunctionCall( m_object, &MyObject::print0 );
m_invoker.addCallback( m_object, &MyObject::print1 ); m_invoker.addFunctionCall( m_object, &MyObject::print1 );
m_invoker.addCallback( m_object, &MyObject::print2 ); m_invoker.addFunctionCall( m_object, &MyObject::print2 );
m_invoker.addCallback( m_object, &MyObject::print3 ); m_invoker.addFunctionCall( m_object, &MyObject::print3 );
m_invoker.addCallback( m_object, &MyObject::print4 ); m_invoker.addFunctionCall( m_object, &MyObject::print4 );
m_invoker.addCallback( m_object, &MyObject::printS ); m_invoker.addFunctionCall( m_object, &MyObject::printS );
m_invoker.addCallback( m_object, []( double d, int i ) { qDebug() << d << i; } ); m_invoker.addFunctionCall( m_object, []( double d, int i ) { qDebug() << d << i; } );
m_invoker.addCallback( m_object, f ); m_invoker.addFunctionCall( m_object, f );
m_invoker.addCallback( m_object, fs ); m_invoker.addFunctionCall( m_object, fs );
m_invoker.addCallback( m_object, []( double d ) { qDebug() << d; } ); m_invoker.addFunctionCall( m_object, []( double d ) { qDebug() << d; } );
m_invoker.addCallback( []() { qDebug() << "HERE"; } ); m_invoker.addFunctionCall( []() { qDebug() << "HERE"; } );
m_invoker.addCallback( []( int i, double d ) { qDebug() << i << d; } ); m_invoker.addFunctionCall( []( int i, double d ) { qDebug() << i << d; } );
m_invoker.addCallback( []( int i ) { qDebug() << "I1" << i; } ); m_invoker.addFunctionCall( []( int i ) { qDebug() << "I1" << i; } );
m_invoker.addCallback( []( int i ) { qDebug() << "I2" << i; } ); m_invoker.addFunctionCall( []( int i ) { qDebug() << "I2" << i; } );
m_invoker.addCallback( []( double d ) { qDebug() << "V" << d; } ); m_invoker.addFunctionCall( []( double d ) { qDebug() << "V" << d; } );
m_invoker.addCallback( []( const double& d ) { qDebug() << "R" << d; } ); m_invoker.addFunctionCall( []( const double& d ) { qDebug() << "R" << d; } );
#endif #endif
} }

View File

@ -21,6 +21,15 @@ QskMetaCallback::QskMetaCallback( const QObject* object,
{ {
} }
QskMetaCallback::QskMetaCallback( const QObject* object,
const QMetaProperty& property, Qt::ConnectionType connectionType ):
m_object( const_cast< QObject* >( object ) ),
m_invokable( property ),
m_hasObject( object != nullptr ),
m_connectionType( static_cast< ushort >( connectionType & 0x3 ) )
{
}
QskMetaCallback::QskMetaCallback( const QObject* object, QskMetaCallback::QskMetaCallback( const QObject* object,
const QskMetaFunction& function, Qt::ConnectionType connectionType ): const QskMetaFunction& function, Qt::ConnectionType connectionType ):
m_object( const_cast< QObject* >( object ) ), m_object( const_cast< QObject* >( object ) ),

View File

@ -23,6 +23,9 @@ public:
QskMetaCallback( const QObject*, const QMetaMethod&, QskMetaCallback( const QObject*, const QMetaMethod&,
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );
QskMetaCallback( const QObject*, const QMetaProperty&,
Qt::ConnectionType = Qt::AutoConnection );
QskMetaCallback( const QObject*, const char* methodName, QskMetaCallback( const QObject*, const char* methodName,
Qt::ConnectionType = Qt::AutoConnection ); Qt::ConnectionType = Qt::AutoConnection );

View File

@ -35,9 +35,32 @@ namespace
}; };
} }
static void qskInvokeSetProperty( QObject* object,
const QMetaObject* metaObject, int propertyIndex,
void* args[], Qt::ConnectionType connectionType )
{
#if 1
if ( connectionType != Qt::DirectConnection )
return; // TODO ...
#endif
if ( propertyIndex >= 0 && object->metaObject() == metaObject )
{
int status = -1;
int flags = 0;
void *argv[] = { args[1], nullptr, &status, &flags };
#if 1
QMetaObject::metacall( object,
QMetaObject::WriteProperty, propertyIndex, argv );
#else
metaObject->d.static_metacall(object, QMetaObject::WriteProperty, idx, argv);
#endif
}
}
QskMetaInvokable::QskMetaInvokable( const QMetaMethod& method ): QskMetaInvokable::QskMetaInvokable( const QMetaMethod& method ):
m_methodData { method.enclosingMetaObject(), method.methodIndex() }, m_metaData { method.enclosingMetaObject(), method.methodIndex() },
m_type( MetaMethod ) m_type( MetaMethod )
{ {
} }
@ -52,6 +75,12 @@ QskMetaInvokable::QskMetaInvokable( const QMetaObject* metaObject, const char* m
{ {
} }
QskMetaInvokable::QskMetaInvokable( const QMetaProperty& property ):
m_metaData { property.enclosingMetaObject(), property.propertyIndex() },
m_type( MetaProperty )
{
}
QskMetaInvokable::QskMetaInvokable( const QskMetaFunction& function ): QskMetaInvokable::QskMetaInvokable( const QskMetaFunction& function ):
m_functionData { function.functionCall() }, m_functionData { function.functionCall() },
m_type( MetaFunction ) m_type( MetaFunction )
@ -65,9 +94,10 @@ QskMetaInvokable::QskMetaInvokable( const QskMetaInvokable& other ):
switch( m_type ) switch( m_type )
{ {
case MetaMethod: case MetaMethod:
case MetaProperty:
{ {
m_methodData.metaObject = other.m_methodData.metaObject; m_metaData.metaObject = other.m_metaData.metaObject;
m_methodData.methodIndex = other.m_methodData.methodIndex; m_metaData.index = other.m_metaData.index;
break; break;
} }
@ -95,12 +125,13 @@ QskMetaInvokable& QskMetaInvokable::operator=( const QskMetaInvokable& other )
switch( other.m_type ) switch( other.m_type )
{ {
case MetaMethod: case MetaMethod:
case MetaProperty:
{ {
if ( m_type == MetaFunction ) if ( m_type == MetaFunction )
Function::deref( m_functionData.functionCall ); Function::deref( m_functionData.functionCall );
m_methodData.metaObject = other.m_methodData.metaObject; m_metaData.metaObject = other.m_metaData.metaObject;
m_methodData.methodIndex = other.m_methodData.methodIndex; m_metaData.index = other.m_metaData.index;
break; break;
} }
@ -127,20 +158,26 @@ QskMetaInvokable& QskMetaInvokable::operator=( const QskMetaInvokable& other )
bool QskMetaInvokable::operator==( const QskMetaInvokable& other ) const bool QskMetaInvokable::operator==( const QskMetaInvokable& other ) const
{ {
if ( m_type == other.m_type ) if ( m_type != other.m_type )
return false;
switch( m_type )
{ {
if ( m_type == MetaMethod ) case MetaMethod:
case MetaProperty:
{ {
return ( m_methodData.metaObject == other.m_methodData.metaObject ) return ( m_metaData.metaObject == other.m_metaData.metaObject )
&& ( m_methodData.methodIndex == other.m_methodData.methodIndex ); && ( m_metaData.index == other.m_metaData.index );
} }
if ( m_type == MetaFunction ) case MetaFunction:
{ {
return m_functionData.functionCall == other.m_functionData.functionCall; return m_functionData.functionCall == other.m_functionData.functionCall;
} }
default:
{
return true;
}
} }
return true;
} }
bool QskMetaInvokable::isNull() const bool QskMetaInvokable::isNull() const
@ -148,17 +185,18 @@ bool QskMetaInvokable::isNull() const
switch( m_type ) switch( m_type )
{ {
case MetaMethod: case MetaMethod:
case MetaProperty:
{ {
const auto& d = m_methodData; const auto& d = m_metaData;
if ( d.metaObject && ( d.methodIndex >= 0 )
&& ( d.methodIndex < d.metaObject->methodCount() ) )
{
return false;
}
return true; if ( d.metaObject == nullptr || d.index < 0 )
return true;
const int count = ( m_type == MetaMethod )
? d.metaObject->methodCount() : d.metaObject->propertyCount();
return d.index >= count;
} }
case MetaFunction: case MetaFunction:
{ {
return m_functionData.functionCall == nullptr; return m_functionData.functionCall == nullptr;
@ -199,6 +237,18 @@ QVector< int > QskMetaInvokable::parameterTypes() const
break; break;
} }
case MetaProperty:
{
// should be doable without QMetaProperty. TODO ...
const auto property = QskMetaInvokable::property();
if ( property.isWritable() )
{
paramTypes.reserve( 1 );
paramTypes += property.userType();
}
break;
}
case MetaFunction: case MetaFunction:
{ {
auto types = function().parameterTypes(); auto types = function().parameterTypes();
@ -228,6 +278,7 @@ int QskMetaInvokable::returnType() const
{ {
return function().returnType(); return function().returnType();
} }
case MetaProperty:
default: default:
{ {
return QMetaType::Void; return QMetaType::Void;
@ -237,12 +288,20 @@ int QskMetaInvokable::returnType() const
QMetaMethod QskMetaInvokable::method() const QMetaMethod QskMetaInvokable::method() const
{ {
if ( m_type == MetaMethod ) if ( m_type == MetaMethod && m_metaData.metaObject )
return m_methodData.metaObject->method( m_methodData.methodIndex ); return m_metaData.metaObject->method( m_metaData.index );
return QMetaMethod(); return QMetaMethod();
} }
QMetaProperty QskMetaInvokable::property() const
{
if ( m_type == MetaProperty && m_metaData.metaObject )
return m_metaData.metaObject->property( m_metaData.index );
return QMetaProperty();
}
QskMetaFunction QskMetaInvokable::function() const QskMetaFunction QskMetaInvokable::function() const
{ {
if ( m_type == MetaFunction && m_functionData.functionCall ) if ( m_type == MetaFunction && m_functionData.functionCall )
@ -264,8 +323,16 @@ void QskMetaInvokable::invoke( QObject* object, void* args[],
{ {
case MetaMethod: case MetaMethod:
{ {
QskMetaMethod::invoke( object, m_methodData.metaObject, QskMetaMethod::invoke( object, m_metaData.metaObject,
m_methodData.methodIndex, args, connectionType ); m_metaData.index, args, connectionType );
break;
}
case MetaProperty:
{
qskInvokeSetProperty( object,
m_metaData.metaObject, m_metaData.index,
args, connectionType );
break; break;
} }

View File

@ -16,6 +16,7 @@ template< typename T > class QVector;
class QskMetaFunction; class QskMetaFunction;
class QMetaObject; class QMetaObject;
class QMetaMethod; class QMetaMethod;
class QMetaProperty;
class QObject; class QObject;
class QSK_EXPORT QskMetaInvokable class QSK_EXPORT QskMetaInvokable
@ -28,6 +29,9 @@ public:
// A QMetaMethod // A QMetaMethod
MetaMethod, MetaMethod,
// The WRITE accessor of a QMetaProperty
MetaProperty,
// A function pointer, for what Qt calls "functor based" callbacks // A function pointer, for what Qt calls "functor based" callbacks
MetaFunction MetaFunction
}; };
@ -35,10 +39,13 @@ public:
QskMetaInvokable(); QskMetaInvokable();
QskMetaInvokable( const QskMetaFunction& ); QskMetaInvokable( const QskMetaFunction& );
QskMetaInvokable( const QMetaMethod& ); QskMetaInvokable( const QMetaMethod& );
QskMetaInvokable( const QObject*, const char* methodName ); QskMetaInvokable( const QObject*, const char* methodName );
QskMetaInvokable( const QMetaObject*, const char* methodName ); QskMetaInvokable( const QMetaObject*, const char* methodName );
QskMetaInvokable( const QMetaProperty& );
QskMetaInvokable( const QskMetaInvokable& ); QskMetaInvokable( const QskMetaInvokable& );
~QskMetaInvokable(); ~QskMetaInvokable();
@ -62,6 +69,7 @@ public:
void reset(); void reset();
QMetaMethod method() const; QMetaMethod method() const;
QMetaProperty property() const;
QskMetaFunction function() const; QskMetaFunction function() const;
private: private:
@ -70,16 +78,16 @@ private:
void* functionCall; void* functionCall;
}; };
struct MethodData struct MetaData
{ {
const QMetaObject* metaObject; const QMetaObject* metaObject;
int methodIndex; int index; // method or property index
}; };
union union
{ {
FunctionData m_functionData; FunctionData m_functionData;
MethodData m_methodData; MetaData m_metaData;
}; };
int m_type : 3; int m_type : 3;