diff --git a/playground/invoker/Invoker.cpp b/playground/invoker/Invoker.cpp index 504013f2..3befea8d 100644 --- a/playground/invoker/Invoker.cpp +++ b/playground/invoker/Invoker.cpp @@ -4,25 +4,35 @@ *****************************************************************************/ #include "Invoker.h" + #include +#include Invoker::Invoker( QObject* parent ): QObject( parent ) { } -void Invoker::addCallback( const QObject* object, +void Invoker::addFunctionCall( const QObject* object, const QskMetaFunction& function ) { m_callbacks.append( QskMetaCallback( object, function ) ); } -void Invoker::addCallback( const QObject* object, +void Invoker::addMethodCall( const QObject* object, const char* 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, Qt::ConnectionType connectionType ) { diff --git a/playground/invoker/Invoker.h b/playground/invoker/Invoker.h index 9df4b266..fe6fbb7b 100644 --- a/playground/invoker/Invoker.h +++ b/playground/invoker/Invoker.h @@ -17,9 +17,11 @@ class Invoker : public QObject public: Invoker( QObject* parent = nullptr ); - void addCallback( const QskMetaFunction& ); - void addCallback( const QObject*, const QskMetaFunction& ); - void addCallback( const QObject*, const char* methodName ); + void addFunctionCall( const QskMetaFunction& ); + void addFunctionCall( const QObject*, const QskMetaFunction& ); + + void addMethodCall( const QObject*, const char* methodName ); + void addPropertyCall( const QObject*, const char* property ); void invoke( qreal d, int i, Qt::ConnectionType ); @@ -27,9 +29,9 @@ private: 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 diff --git a/playground/invoker/invoker.pro b/playground/invoker/invoker.pro index f1cf4476..8f484ec3 100644 --- a/playground/invoker/invoker.pro +++ b/playground/invoker/invoker.pro @@ -1,5 +1,7 @@ include( $${PWD}/../playground.pri ) +QMAKE_MOC_OPTIONS += -nw # disable warning about missing READ + TARGET = invoker HEADERS += \ diff --git a/playground/invoker/main.cpp b/playground/invoker/main.cpp index b785120d..e8680e2a 100644 --- a/playground/invoker/main.cpp +++ b/playground/invoker/main.cpp @@ -43,6 +43,10 @@ class MyObject : public QObject { Q_OBJECT + Q_PROPERTY( int number WRITE setNumber ) + Q_PROPERTY( qreal value WRITE setValue ) + Q_PROPERTY( QString valueString WRITE setValueString ) + public: MyObject( QObject* parent = nullptr ): QObject( parent ) @@ -54,6 +58,21 @@ public: 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: void print0( double d, int i ) const { @@ -97,46 +116,52 @@ public: m_thread( new QThread( this ) ) { #if 1 - m_invoker.addCallback( m_object, "print0(double,int)" ); - m_invoker.addCallback( m_object, "print1(double,int)" ); - m_invoker.addCallback( m_object, SLOT(print2(int,double)) ); - m_invoker.addCallback( m_object, "print3(double)" ); - m_invoker.addCallback( m_object, "print4(int)" ); - m_invoker.addCallback( m_object, "print4(int)" ); - m_invoker.addCallback( m_object, "printS(QString)" ); - m_invoker.addCallback( m_object, "printInvokable(double,int)" ); + m_invoker.addPropertyCall( m_object, "number" ); + m_invoker.addPropertyCall( m_object, "value" ); + m_invoker.addPropertyCall( m_object, "valueString" ); +#endif + +#if 1 + m_invoker.addMethodCall( m_object, "print0(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 #if 1 auto f = [this]( int i, double d ) { qDebug() << i << d << ( ++m_num ); }; - m_invoker.addCallback( m_object, &MyObject::print0 ); - m_invoker.addCallback( m_object, &MyObject::print1 ); - m_invoker.addCallback( QskMetaFunction() ); - m_invoker.addCallback( debugNone1 ); - m_invoker.addCallback( debugNone2 ); - m_invoker.addCallback( debugValue ); - m_invoker.addCallback( debugValueI1 ); - m_invoker.addCallback( debugValueI2 ); - m_invoker.addCallback( debugValueD ); - m_invoker.addCallback( m_object, &MyObject::print0 ); - m_invoker.addCallback( m_object, &MyObject::print1 ); - m_invoker.addCallback( m_object, &MyObject::print2 ); - m_invoker.addCallback( m_object, &MyObject::print3 ); - m_invoker.addCallback( m_object, &MyObject::print4 ); - m_invoker.addCallback( m_object, &MyObject::printS ); - m_invoker.addCallback( m_object, []( double d, int i ) { qDebug() << d << i; } ); + m_invoker.addFunctionCall( m_object, &MyObject::print0 ); + m_invoker.addFunctionCall( m_object, &MyObject::print1 ); + m_invoker.addFunctionCall( QskMetaFunction() ); + m_invoker.addFunctionCall( debugNone1 ); + m_invoker.addFunctionCall( debugNone2 ); + m_invoker.addFunctionCall( debugValue ); + m_invoker.addFunctionCall( debugValueI1 ); + m_invoker.addFunctionCall( debugValueI2 ); + m_invoker.addFunctionCall( debugValueD ); + m_invoker.addFunctionCall( m_object, &MyObject::print0 ); + m_invoker.addFunctionCall( m_object, &MyObject::print1 ); + m_invoker.addFunctionCall( m_object, &MyObject::print2 ); + m_invoker.addFunctionCall( m_object, &MyObject::print3 ); + m_invoker.addFunctionCall( m_object, &MyObject::print4 ); + m_invoker.addFunctionCall( m_object, &MyObject::printS ); + m_invoker.addFunctionCall( m_object, []( double d, int i ) { qDebug() << d << i; } ); - m_invoker.addCallback( m_object, f ); - m_invoker.addCallback( m_object, fs ); + m_invoker.addFunctionCall( m_object, f ); + m_invoker.addFunctionCall( m_object, fs ); - m_invoker.addCallback( m_object, []( double d ) { qDebug() << d; } ); - m_invoker.addCallback( []() { qDebug() << "HERE"; } ); - m_invoker.addCallback( []( int i, double d ) { qDebug() << i << d; } ); - m_invoker.addCallback( []( int i ) { qDebug() << "I1" << i; } ); - m_invoker.addCallback( []( int i ) { qDebug() << "I2" << i; } ); - m_invoker.addCallback( []( double d ) { qDebug() << "V" << d; } ); - m_invoker.addCallback( []( const double& d ) { qDebug() << "R" << d; } ); + m_invoker.addFunctionCall( m_object, []( double d ) { qDebug() << d; } ); + m_invoker.addFunctionCall( []() { qDebug() << "HERE"; } ); + m_invoker.addFunctionCall( []( int i, double d ) { qDebug() << i << d; } ); + m_invoker.addFunctionCall( []( int i ) { qDebug() << "I1" << i; } ); + m_invoker.addFunctionCall( []( int i ) { qDebug() << "I2" << i; } ); + m_invoker.addFunctionCall( []( double d ) { qDebug() << "V" << d; } ); + m_invoker.addFunctionCall( []( const double& d ) { qDebug() << "R" << d; } ); #endif } diff --git a/src/common/QskMetaCallback.cpp b/src/common/QskMetaCallback.cpp index f287d63a..4c4bb03c 100644 --- a/src/common/QskMetaCallback.cpp +++ b/src/common/QskMetaCallback.cpp @@ -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, const QskMetaFunction& function, Qt::ConnectionType connectionType ): m_object( const_cast< QObject* >( object ) ), diff --git a/src/common/QskMetaCallback.h b/src/common/QskMetaCallback.h index 820617b8..f456eeff 100644 --- a/src/common/QskMetaCallback.h +++ b/src/common/QskMetaCallback.h @@ -23,6 +23,9 @@ public: QskMetaCallback( const QObject*, const QMetaMethod&, Qt::ConnectionType = Qt::AutoConnection ); + QskMetaCallback( const QObject*, const QMetaProperty&, + Qt::ConnectionType = Qt::AutoConnection ); + QskMetaCallback( const QObject*, const char* methodName, Qt::ConnectionType = Qt::AutoConnection ); diff --git a/src/common/QskMetaInvokable.cpp b/src/common/QskMetaInvokable.cpp index 42990b45..db2b4633 100644 --- a/src/common/QskMetaInvokable.cpp +++ b/src/common/QskMetaInvokable.cpp @@ -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 ): - m_methodData { method.enclosingMetaObject(), method.methodIndex() }, + m_metaData { method.enclosingMetaObject(), method.methodIndex() }, 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 ): m_functionData { function.functionCall() }, m_type( MetaFunction ) @@ -65,9 +94,10 @@ QskMetaInvokable::QskMetaInvokable( const QskMetaInvokable& other ): switch( m_type ) { case MetaMethod: + case MetaProperty: { - m_methodData.metaObject = other.m_methodData.metaObject; - m_methodData.methodIndex = other.m_methodData.methodIndex; + m_metaData.metaObject = other.m_metaData.metaObject; + m_metaData.index = other.m_metaData.index; break; } @@ -95,12 +125,13 @@ QskMetaInvokable& QskMetaInvokable::operator=( const QskMetaInvokable& other ) switch( other.m_type ) { case MetaMethod: + case MetaProperty: { if ( m_type == MetaFunction ) Function::deref( m_functionData.functionCall ); - m_methodData.metaObject = other.m_methodData.metaObject; - m_methodData.methodIndex = other.m_methodData.methodIndex; + m_metaData.metaObject = other.m_metaData.metaObject; + m_metaData.index = other.m_metaData.index; break; } @@ -127,20 +158,26 @@ QskMetaInvokable& QskMetaInvokable::operator=( const QskMetaInvokable& other ) 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 ) - && ( m_methodData.methodIndex == other.m_methodData.methodIndex ); + return ( m_metaData.metaObject == other.m_metaData.metaObject ) + && ( m_metaData.index == other.m_metaData.index ); } - if ( m_type == MetaFunction ) + case MetaFunction: { return m_functionData.functionCall == other.m_functionData.functionCall; } + default: + { + return true; + } } - - return true; } bool QskMetaInvokable::isNull() const @@ -148,17 +185,18 @@ bool QskMetaInvokable::isNull() const switch( m_type ) { case MetaMethod: + case MetaProperty: { - const auto& d = m_methodData; - if ( d.metaObject && ( d.methodIndex >= 0 ) - && ( d.methodIndex < d.metaObject->methodCount() ) ) - { - return false; - } + const auto& d = m_metaData; - 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: { return m_functionData.functionCall == nullptr; @@ -199,6 +237,18 @@ QVector< int > QskMetaInvokable::parameterTypes() const 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: { auto types = function().parameterTypes(); @@ -228,6 +278,7 @@ int QskMetaInvokable::returnType() const { return function().returnType(); } + case MetaProperty: default: { return QMetaType::Void; @@ -237,12 +288,20 @@ int QskMetaInvokable::returnType() const QMetaMethod QskMetaInvokable::method() const { - if ( m_type == MetaMethod ) - return m_methodData.metaObject->method( m_methodData.methodIndex ); + if ( m_type == MetaMethod && m_metaData.metaObject ) + return m_metaData.metaObject->method( m_metaData.index ); 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 { if ( m_type == MetaFunction && m_functionData.functionCall ) @@ -264,8 +323,16 @@ void QskMetaInvokable::invoke( QObject* object, void* args[], { case MetaMethod: { - QskMetaMethod::invoke( object, m_methodData.metaObject, - m_methodData.methodIndex, args, connectionType ); + QskMetaMethod::invoke( object, m_metaData.metaObject, + m_metaData.index, args, connectionType ); + + break; + } + case MetaProperty: + { + qskInvokeSetProperty( object, + m_metaData.metaObject, m_metaData.index, + args, connectionType ); break; } diff --git a/src/common/QskMetaInvokable.h b/src/common/QskMetaInvokable.h index be373317..183b4d06 100644 --- a/src/common/QskMetaInvokable.h +++ b/src/common/QskMetaInvokable.h @@ -16,6 +16,7 @@ template< typename T > class QVector; class QskMetaFunction; class QMetaObject; class QMetaMethod; +class QMetaProperty; class QObject; class QSK_EXPORT QskMetaInvokable @@ -28,6 +29,9 @@ public: // A QMetaMethod MetaMethod, + // The WRITE accessor of a QMetaProperty + MetaProperty, + // A function pointer, for what Qt calls "functor based" callbacks MetaFunction }; @@ -35,10 +39,13 @@ public: QskMetaInvokable(); QskMetaInvokable( const QskMetaFunction& ); + QskMetaInvokable( const QMetaMethod& ); QskMetaInvokable( const QObject*, const char* methodName ); QskMetaInvokable( const QMetaObject*, const char* methodName ); + QskMetaInvokable( const QMetaProperty& ); + QskMetaInvokable( const QskMetaInvokable& ); ~QskMetaInvokable(); @@ -62,6 +69,7 @@ public: void reset(); QMetaMethod method() const; + QMetaProperty property() const; QskMetaFunction function() const; private: @@ -70,16 +78,16 @@ private: void* functionCall; }; - struct MethodData + struct MetaData { const QMetaObject* metaObject; - int methodIndex; + int index; // method or property index }; union { FunctionData m_functionData; - MethodData m_methodData; + MetaData m_metaData; }; int m_type : 3;