QskShortcutMap using QskMetaInvokable

This commit is contained in:
Uwe Rathmann 2018-03-12 09:27:54 +01:00
parent 42a09813ed
commit ee3ac13e36
5 changed files with 137 additions and 277 deletions

View File

@ -43,26 +43,26 @@ void Invoker::invoke( qreal realValue, int intValue,
{ {
void* args[4] = { nullptr }; void* args[4] = { nullptr };
const auto types = callback.invokable().parameterTypes(); void **a = args + 1;
const auto& invokable = callback.invokable();
int i = 1; for ( int i = 0; i < invokable.parameterCount(); i++ )
for ( auto type : types )
{ {
switch ( type ) switch ( invokable.parameterType( i ) )
{ {
case QMetaType::Int: case QMetaType::Int:
{ {
args[i++] = reinterpret_cast< void* >( &intValue ); *a++ = reinterpret_cast< void* >( &intValue );
break; break;
} }
case QMetaType::Double: case QMetaType::Double:
{ {
args[i++] = reinterpret_cast< void* >( &realValue ); *a++ = reinterpret_cast< void* >( &realValue );
break; break;
} }
case QMetaType::QString: case QMetaType::QString:
{ {
args[i++] = reinterpret_cast< void* >( &s ); *a++ = reinterpret_cast< void* >( &s );
break; break;
} }
default: default:

View File

@ -467,55 +467,55 @@ void QskMetaInvokable::reset()
m_type = Invalid; m_type = Invalid;
} }
QVector< int > QskMetaInvokable::parameterTypes() const int QskMetaInvokable::parameterCount() const
{ {
QVector< int > paramTypes;
switch( m_type ) switch( m_type )
{ {
case MetaMethod: case MetaMethod:
{ {
// should be doable without QMetaMethod. TODO ... // should be doable without QMetaMethod. TODO ...
const auto method = QskMetaInvokable::method(); const auto method = QskMetaInvokable::method();
return method.parameterCount();
const int paramCount = method.parameterCount();
if ( paramCount > 0 )
{
paramTypes.reserve( paramCount );
for ( int i = 0; i < paramCount; i++ )
paramTypes += method.parameterType( i );
}
break;
} }
case MetaProperty: case MetaProperty:
{ {
// should be doable without QMetaProperty. TODO ... return 1;
const auto property = QskMetaInvokable::property();
if ( property.isWritable() )
{
paramTypes.reserve( 1 );
paramTypes += property.userType();
}
break;
} }
case MetaFunction: case MetaFunction:
{ {
auto types = function().parameterTypes(); return function().parameterCount();
if ( types )
{
while ( *types )
paramTypes += *types++;
}
break;
} }
default: default:
break; break;
} }
return paramTypes; return 0;
}
int QskMetaInvokable::parameterType( int index ) const
{
switch( m_type )
{
case MetaMethod:
{
const auto method = QskMetaInvokable::method();
return method.parameterType( index );
}
case MetaProperty:
{
const auto property = QskMetaInvokable::property();
return property.userType();
}
case MetaFunction:
{
auto types = function().parameterTypes();
return types[index];
}
default:
{
return QMetaType::UnknownType;
}
}
} }
int QskMetaInvokable::returnType() const int QskMetaInvokable::returnType() const
@ -531,6 +531,9 @@ int QskMetaInvokable::returnType() const
return function().returnType(); return function().returnType();
} }
case MetaProperty: case MetaProperty:
{
return QMetaType::Void;
}
default: default:
{ {
return QMetaType::Void; return QMetaType::Void;
@ -560,7 +563,6 @@ QByteArray QskMetaInvokable::name() const
return QByteArray(); return QByteArray();
} }
} }
} }
QMetaMethod QskMetaInvokable::method() const QMetaMethod QskMetaInvokable::method() const

View File

@ -11,8 +11,6 @@
#include <QMetaType> #include <QMetaType>
#include <Qt> #include <Qt>
template< typename T > class QVector;
class QskMetaFunction; class QskMetaFunction;
class QMetaObject; class QMetaObject;
class QMetaMethod; class QMetaMethod;
@ -60,7 +58,9 @@ public:
Type type() const; Type type() const;
bool isNull() const; bool isNull() const;
QVector< int > parameterTypes() const; int parameterCount() const;
int parameterType( int index ) const;
int returnType() const; int returnType() const;
void invoke( QObject*, void* args[], void invoke( QObject*, void* args[],

View File

@ -5,9 +5,9 @@
#include "QskShortcutMap.h" #include "QskShortcutMap.h"
#include "QskControl.h" #include "QskControl.h"
#include "QskMetaInvokable.h"
#include <QQuickWindow> #include <QQuickWindow>
#include <QMetaMethod>
#include <QKeySequence> #include <QKeySequence>
#include <QGlobalStatic> #include <QGlobalStatic>
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
@ -24,11 +24,8 @@ class QskShortcutHandler final : public QObject
public: public:
QskShortcutHandler(); QskShortcutHandler();
int add( QQuickItem*, const QKeySequence&, int insert( QQuickItem*, const QKeySequence&, bool autoRepeat,
const QObject* receiver, const char* method ); const QObject*, const QskMetaInvokable& );
int add( QQuickItem*, const QKeySequence&,
const QObject* receiver, QtPrivate::QSlotObjectBase* );
void remove( int id ); void remove( int id );
@ -38,8 +35,6 @@ public:
virtual bool eventFilter( QObject*, QEvent* ) override final; virtual bool eventFilter( QObject*, QEvent* ) override final;
private: private:
int insert( QQuickItem*, const QKeySequence&,
const QObject* receiver, const QMetaMethod&, QtPrivate::QSlotObjectBase* );
void cleanUp( QObject* ); void cleanUp( QObject* );
@ -48,21 +43,13 @@ private:
public: public:
InvokeData(): InvokeData():
item( nullptr ), item( nullptr ),
receiver( nullptr ), receiver( nullptr )
slotObject( nullptr )
{ {
} }
~InvokeData()
{
if ( slotObject )
slotObject->destroyIfLastRef();
}
QQuickItem* item; QQuickItem* item;
const QObject* receiver; const QObject* receiver;
QMetaMethod method; QskMetaInvokable invokable;
QtPrivate::QSlotObjectBase* slotObject;
}; };
std::map< int, InvokeData > m_invokeDataMap; std::map< int, InvokeData > m_invokeDataMap;
@ -82,7 +69,7 @@ static bool qskContextMatcher( QObject* object, Qt::ShortcutContext context )
{ {
/* /*
Unfortunatley there is no way to have to know about Unfortunatley there is no way to have to know about
the contextItem without making it the receiver of the contextItem without making it the receiver of
the following QShortcutEvent. So we have to install the following QShortcutEvent. So we have to install
an event handler to process and swallow it in QskShortcutHandler. an event handler to process and swallow it in QskShortcutHandler.
*/ */
@ -101,39 +88,25 @@ QskShortcutHandler::QskShortcutHandler()
installEventFilter( this ); installEventFilter( this );
} }
int QskShortcutHandler::add( QQuickItem* item, const QKeySequence& sequence, int QskShortcutHandler::insert(
const QObject* receiver, const char* method ) QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
const QObject* receiver, const QskMetaInvokable& invokable )
{ {
int id = 0; if ( sequence.isEmpty() )
if ( receiver )
{ {
const QMetaObject* metaObject = receiver->metaObject(); qDebug() << "QskShortcutMap: invalid shortcut key sequence";
return 0;
const int methodIndex = metaObject->indexOfMethod(
QMetaObject::normalizedSignature( method ).constData() + 1 );
if ( methodIndex >= 0 )
{
id = insert( item, sequence,
receiver, metaObject->method( methodIndex ), nullptr );
}
} }
return id; #if 1
} // should be a compile time check for functor based slots
if ( invokable.parameterCount() > 0 )
{
qDebug() << "QskShortcutMap: invalid slot parameter count";
return 0;
}
#endif
int QskShortcutHandler::add( QQuickItem* item, const QKeySequence& sequence,
const QObject* receiver, QtPrivate::QSlotObjectBase* slotObj )
{
return insert( item, sequence, receiver, QMetaMethod(), slotObj );
}
int QskShortcutHandler::insert(
QQuickItem* item, const QKeySequence& sequence,
const QObject* receiver, const QMetaMethod& method,
QtPrivate::QSlotObjectBase* slotObject )
{
if ( receiver ) if ( receiver )
{ {
connect( receiver, &QObject::destroyed, connect( receiver, &QObject::destroyed,
@ -163,11 +136,10 @@ int QskShortcutHandler::insert(
data.item = item; data.item = item;
data.receiver = receiver; data.receiver = receiver;
data.invokable = invokable;
if ( slotObject ) if ( !autoRepeat )
data.slotObject = slotObject; setAutoRepeat( id, false );
else
data.method = method;
return id; return id;
} }
@ -266,30 +238,14 @@ bool QskShortcutHandler::eventFilter( QObject* object, QEvent* event )
const auto it = m_invokeDataMap.find( se->shortcutId() ); const auto it = m_invokeDataMap.find( se->shortcutId() );
if ( it != m_invokeDataMap.end() ) if ( it != m_invokeDataMap.end() )
{ {
const auto& invokeData = it->second; auto& data = it->second;
Q_ASSERT( invokeData.item == nullptr || invokeData.item == object ); Q_ASSERT( data.item == nullptr || data.item == object );
auto receiver = const_cast< QObject* >( invokeData.receiver ); auto receiver = const_cast< QObject* > ( data.receiver );
void* args[] = { nullptr };
if ( invokeData.slotObject ) data.invokable.invoke( receiver, args, Qt::AutoConnection );
{
void* args[] = { 0 };
if ( receiver && receiver->thread() != thread() )
{
QCoreApplication::postEvent( receiver,
new QMetaCallEvent( invokeData.slotObject, nullptr, 0, 0, nullptr, args ) );
}
else
{
invokeData.slotObject->call( receiver, args );
}
}
else
{
invokeData.method.invoke( receiver, Qt::AutoConnection );
}
return true; return true;
} }
@ -303,24 +259,26 @@ int QskShortcutMap::addMethod( QQuickItem* item, const QKeySequence& sequence,
{ {
if ( receiver == nullptr ) if ( receiver == nullptr )
{ {
qDebug() << "QskShortcutMap: bad receiver for shortcut:" << sequence;
return 0; return 0;
} }
int id = qskShortcutHandler->add( item, sequence, receiver, method ); return qskShortcutHandler->insert(
if ( id && !autoRepeat ) item, sequence, autoRepeat, receiver, qskMetaMethod( receiver, method ) );
qskShortcutHandler->setAutoRepeat( id, false );
return id;
} }
int QskShortcutMap::addSlotObject( QQuickItem* item, const QKeySequence& sequence, int QskShortcutMap::addFunction( QQuickItem* item, const QKeySequence& sequence,
bool autoRepeat, const QObject* receiver, QtPrivate::QSlotObjectBase* slotObject ) bool autoRepeat, const QObject* receiver, const QskMetaFunction& function )
{ {
int id = qskShortcutHandler->add( item, sequence, receiver, slotObject ); if ( ( receiver == nullptr )
if ( id && !autoRepeat ) && ( function.functionType() == QskMetaFunction::Member ) )
qskShortcutHandler->setAutoRepeat( id, false ); {
qDebug() << "QskShortcutMap: bad receiver for shortcut:" << sequence;
return 0;
}
return id; return qskShortcutHandler->insert(
item, sequence, autoRepeat, receiver, function );
} }
void QskShortcutMap::setAutoRepeat( int id, bool on ) void QskShortcutMap::setAutoRepeat( int id, bool on )

View File

@ -7,6 +7,8 @@
#define QSK_SHORTCUT_MAP_H #define QSK_SHORTCUT_MAP_H
#include "QskGlobal.h" #include "QskGlobal.h"
#include "QskMetaFunction.h"
#include <QQuickWindow> #include <QQuickWindow>
class QQuickItem; class QQuickItem;
@ -20,51 +22,34 @@ public:
static void removeShortcut( int ); static void removeShortcut( int );
// -- traditional slots // string based slots
static int addShortcut( const QKeySequence&, bool autoRepeat, static int addShortcut( const QKeySequence&,
const QObject* receiver, const char* method ); bool autoRepeat, const QObject* receiver, const char* method );
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat, static int addShortcut( QQuickWindow*, const QKeySequence&,
const QObject* receiver, const char* method ); bool autoRepeat, const QObject* receiver, const char* method );
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat, static int addShortcut( QQuickItem*, const QKeySequence&,
const QObject* receiver, const char* method ); bool autoRepeat, const QObject* receiver, const char* method );
// -- calling a QObject method // functor based slots
template< typename Func1 > static int addShortcut( const QKeySequence&,
static int addShortcut( const QKeySequence&, bool autoRepeat, bool autoRepeat, const QskMetaFunction& );
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
template< typename Func1 > static int addShortcut( const QKeySequence&,
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat, bool autoRepeat, const QObject* context, const QskMetaFunction& );
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
template< typename Func1 > static int addShortcut( QQuickItem*, const QKeySequence&,
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat, bool autoRepeat, const QskMetaFunction& );
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
// -- calling a functor or function pointer inside a thread context static int addShortcut( QQuickItem*, const QKeySequence&,
template< typename Func1 > bool autoRepeat, const QObject* context, const QskMetaFunction& );
static int addShortcut( const QKeySequence&, bool autoRepeat,
const QObject* context, Func1 slot );
template< typename Func1 > static int addShortcut( QQuickWindow*, const QKeySequence&,
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat, bool autoRepeat, const QskMetaFunction& );
const QObject* context, Func1 slot );
template< typename Func1 > static int addShortcut( QQuickWindow*, const QKeySequence&,
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat, bool autoRepeat, const QObject* context, const QskMetaFunction& );
const QObject* context, Func1 slot );
// -- calling a functor or function pointer
template< typename Func1 >
static int addShortcut( const QKeySequence&, bool autoRepeat, Func1 slot );
template< typename Func1 >
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat, Func1 slot );
template< typename Func1 >
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat, Func1 slot );
static bool contextMatcher( const QQuickItem*, Qt::ShortcutContext ); static bool contextMatcher( const QQuickItem*, Qt::ShortcutContext );
@ -72,66 +57,15 @@ private:
QskShortcutMap() = delete; QskShortcutMap() = delete;
~QskShortcutMap() = delete; ~QskShortcutMap() = delete;
static int addMethod( QQuickItem*, const QKeySequence&, bool autoRepeat, static int addFunction(
const QObject* receiver, const char* method );
template< typename Func1 >
static int addMemberSlot( QQuickItem*, const QKeySequence&, bool autoRepeat,
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
template< typename Func1 >
static int addFunctorSlot( QQuickItem*, const QKeySequence&,
bool autoRepeat, const QObject* context, Func1 slot );
static int addSlotObject(
QQuickItem* item, const QKeySequence&, bool autoRepeat, QQuickItem* item, const QKeySequence&, bool autoRepeat,
const QObject* receiver, QtPrivate::QSlotObjectBase* ); const QObject* receiver, const QskMetaFunction& );
static int addMethod(
QQuickItem* item, const QKeySequence&, bool autoRepeat,
const QObject* receiver, const char* );
}; };
template< typename Func1 >
inline int QskShortcutMap::addMemberSlot(
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
{
using namespace QtPrivate;
typedef FunctionPointer< Func1 > SlotType;
Q_STATIC_ASSERT_X( int( SlotType::ArgumentCount ) == 0,
"The slot must not have any arguments.");
return addSlotObject( item, sequence, autoRepeat, receiver,
new QSlotObject< Func1, typename SlotType::Arguments, void >( slot ) );
}
template< typename Func1 >
inline int QskShortcutMap::addFunctorSlot(
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
const QObject* context, Func1 slot )
{
using namespace QtPrivate;
typedef FunctionPointer< Func1 > SlotType;
Q_STATIC_ASSERT_X( int( SlotType::ArgumentCount ) <= 0,
"The slot must not have any arguments.");
Q_STATIC_ASSERT_X( !SlotType::IsPointerToMemberFunction,
"The slot must be no member function." );
using Args = List_Left< void, 0 >::Value;
return addSlotObject( item, sequence, autoRepeat, context,
new QFunctorSlotObject< Func1, 0, Args, void >( slot ) );
}
// -- traditional slots
inline int QskShortcutMap::addShortcut(
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
const QObject* receiver, const char* method )
{
return addMethod( item, sequence, autoRepeat, receiver, method );
}
inline int QskShortcutMap::addShortcut( inline int QskShortcutMap::addShortcut(
const QKeySequence& sequence, bool autoRepeat, const QKeySequence& sequence, bool autoRepeat,
const QObject* receiver, const char* method ) const QObject* receiver, const char* method )
@ -140,89 +74,55 @@ inline int QskShortcutMap::addShortcut(
} }
inline int QskShortcutMap::addShortcut( inline int QskShortcutMap::addShortcut(
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat, QQuickWindow* window, const QKeySequence& sequence,
const QObject* receiver, const char* method ) bool autoRepeat, const QObject* receiver, const char* method )
{ {
auto item = window ? window->contentItem() : nullptr; auto item = window ? window->contentItem() : nullptr;
return addMethod( item, sequence, autoRepeat, receiver, method ); return addMethod( item, sequence, autoRepeat, receiver, method );
} }
// -- calling a QObject method
template< typename Func1 >
inline int QskShortcutMap::addShortcut(
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
{
return addMemberSlot( item, sequence, autoRepeat, receiver, slot );
}
template< typename Func1 >
inline int QskShortcutMap::addShortcut(
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat,
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
{
auto item = window ? window->contentItem() : nullptr;
return addMemberSlot( item, sequence, autoRepeat, receiver, slot );
}
template< typename Func1 >
inline int QskShortcutMap::addShortcut( inline int QskShortcutMap::addShortcut(
const QKeySequence& sequence, bool autoRepeat, const QKeySequence& sequence, bool autoRepeat,
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot ) const QskMetaFunction& function )
{ {
return addMemberSlot( nullptr, sequence, autoRepeat, receiver, slot ); return addFunction( nullptr, sequence, autoRepeat, nullptr, function );
} }
// -- calling a functor or function pointer with context inline int QskShortcutMap::addShortcut(
const QKeySequence& sequence, bool autoRepeat,
const QObject* context, const QskMetaFunction& function )
{
return addFunction( nullptr, sequence, autoRepeat, context, function );
}
template< typename Func1 >
inline int QskShortcutMap::addShortcut( inline int QskShortcutMap::addShortcut(
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat, QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
const QObject* context, Func1 slot ) const QskMetaFunction& function )
{ {
return addFunctorSlot( item, sequence, autoRepeat, context, slot ); return addFunction( item, sequence, autoRepeat, nullptr, function );
}
inline int QskShortcutMap::addShortcut(
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
const QObject* context, const QskMetaFunction& function )
{
return addFunction( item, sequence, autoRepeat, context, function );
} }
template< typename Func1 >
inline int QskShortcutMap::addShortcut( inline int QskShortcutMap::addShortcut(
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat, QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat,
const QObject* context, Func1 slot ) const QskMetaFunction& function )
{ {
auto item = window ? window->contentItem() : nullptr; auto item = window ? window->contentItem() : nullptr;
return addFunctorSlot( item, sequence, autoRepeat, context, slot ); return addFunction( item, sequence, autoRepeat, nullptr, function );
} }
template< typename Func1 >
inline int QskShortcutMap::addShortcut( const QKeySequence& sequence, bool autoRepeat,
const QObject* context, Func1 slot )
{
return addFunctorSlot( nullptr, sequence, autoRepeat, context, slot );
}
// -- calling a functor or function pointer
template< typename Func1 >
inline int QskShortcutMap::addShortcut( inline int QskShortcutMap::addShortcut(
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat, Func1 slot ) QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat,
{ const QObject* context, const QskMetaFunction& function )
return addFunctorSlot( item, sequence, autoRepeat, nullptr, slot );
}
template< typename Func1 >
inline int QskShortcutMap::addShortcut(
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat, Func1 slot )
{ {
auto item = window ? window->contentItem() : nullptr; auto item = window ? window->contentItem() : nullptr;
return addFunctorSlot( item, sequence, autoRepeat, nullptr, autoRepeat, slot ); return addFunction( item, sequence, autoRepeat, context, function );
}
template< typename Func1 >
int QskShortcutMap::addShortcut(
const QKeySequence& sequence, bool autoRepeat, Func1 slot )
{
return addFunctorSlot( nullptr, sequence, autoRepeat, nullptr, slot );
} }
#endif #endif