Qt5 type of connection for QskShortcut

This commit is contained in:
Uwe Rathmann 2017-12-03 17:58:18 +01:00
parent 6644be15bd
commit 81acf6b610
4 changed files with 165 additions and 41 deletions

View File

@ -36,10 +36,10 @@ int main( int argc, char** argv )
cout << "CTRL-T to change the color scheme, when the \"Default\" skin is active." << endl; cout << "CTRL-T to change the color scheme, when the \"Default\" skin is active." << endl;
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_T ), QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_T ),
&skinFactory, SLOT(toggleScheme()), false ); false, &skinFactory, SLOT(toggleScheme()) );
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ), QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ),
&skinFactory, SLOT(rotateSkin()), false ); false, &skinFactory, SLOT(rotateSkin()) );
// With CTRL-B you can rotate a couple of visual debug modes // With CTRL-B you can rotate a couple of visual debug modes
SkinnyShortcut::enable( SkinnyShortcut::DebugBackground | SkinnyShortcut::enable( SkinnyShortcut::DebugBackground |

View File

@ -8,16 +8,18 @@
#include <QObject> #include <QObject>
#include <QKeySequence> #include <QKeySequence>
#include <QQuickWindow> #include <QQuickWindow>
#include <QtGui/private/qguiapplication_p.h>
#include <QMap> #include <QMap>
#include <QGlobalStatic>
#include <QtGui/private/qguiapplication_p.h>
class QskShortcutHandler final : public QObject class QskShortcutHandler final : public QObject
{ {
public: public:
static QskShortcutHandler* instance(); int addShortcut( QQuickWindow*, const QKeySequence&,
const QObject* receiver, const QMetaMethod& );
int addShortcut( QQuickWindow*, const QKeySequence&, int addShortcut( QQuickWindow*, const QKeySequence&,
QObject* receiver, const QMetaMethod&, Qt::ConnectionType type ); const QObject* receiver, QtPrivate::QSlotObjectBase* );
void setEnabled( int id, bool ); void setEnabled( int id, bool );
void setAutoRepeat( int id, bool repeat ); void setAutoRepeat( int id, bool repeat );
@ -26,34 +28,36 @@ protected:
virtual bool event( QEvent* event ) override final; virtual bool event( QEvent* event ) override final;
private: private:
QskShortcutHandler() = default; void cleanUp( QObject* );
static bool contextMatcher( QObject*, Qt::ShortcutContext ); static bool contextMatcher( QObject*, Qt::ShortcutContext );
static QShortcutMap& map(); static QShortcutMap& map();
struct InvokeData class InvokeData
{ {
QObject* receiver; public:
~InvokeData()
{
if ( slotObj )
slotObj->destroyIfLastRef();
}
QMetaMethod method; QMetaMethod method;
Qt::ConnectionType connectionType; QtPrivate::QSlotObjectBase* slotObj;
const QObject* receiver;
}; };
QMap< int, InvokeData > m_invokeDataMap; QMap< int, InvokeData > m_invokeDataMap;
}; };
QskShortcutHandler* QskShortcutHandler::instance()
{
static QskShortcutHandler handler;
return &handler;
}
inline QShortcutMap& QskShortcutHandler::map() inline QShortcutMap& QskShortcutHandler::map()
{ {
return QGuiApplicationPrivate::instance()->shortcutMap; return QGuiApplicationPrivate::instance()->shortcutMap;
} }
int QskShortcutHandler::addShortcut( QQuickWindow* window, const QKeySequence& key, int QskShortcutHandler::addShortcut(
QObject* receiver, const QMetaMethod& method, Qt::ConnectionType connectionType ) QQuickWindow* window, const QKeySequence& key,
const QObject* receiver, const QMetaMethod& method )
{ {
int id; int id;
@ -65,11 +69,48 @@ int QskShortcutHandler::addShortcut( QQuickWindow* window, const QKeySequence& k
InvokeData& data = m_invokeDataMap[ id ]; InvokeData& data = m_invokeDataMap[ id ];
data.receiver = receiver; data.receiver = receiver;
data.method = method; data.method = method;
data.connectionType = connectionType; data.slotObj = nullptr;
return id; return id;
} }
int QskShortcutHandler::addShortcut(
QQuickWindow* window, const QKeySequence& key,
const QObject* receiver, QtPrivate::QSlotObjectBase* slotObj )
{
int id;
if ( window )
id = map().addShortcut( window, key, Qt::WindowShortcut, contextMatcher );
else
id = map().addShortcut( this, key, Qt::ApplicationShortcut, contextMatcher );
InvokeData& data = m_invokeDataMap[ id ];
data.receiver = receiver;
data.slotObj = slotObj;
if ( receiver )
connect( receiver, &QObject::destroyed, this, &QskShortcutHandler::cleanUp );
return id;
}
void QskShortcutHandler::cleanUp( QObject* receiver )
{
map().removeShortcut( 0, receiver );
for ( auto it = m_invokeDataMap.begin(); it != m_invokeDataMap.end(); )
{
if ( it->receiver == receiver )
{
it = m_invokeDataMap.erase( it );
continue;
}
++it;
}
}
bool QskShortcutHandler::contextMatcher( QObject* obj, Qt::ShortcutContext context ) bool QskShortcutHandler::contextMatcher( QObject* obj, Qt::ShortcutContext context )
{ {
switch ( context ) switch ( context )
@ -107,7 +148,17 @@ bool QskShortcutHandler::event( QEvent* event )
if ( it != m_invokeDataMap.constEnd() ) if ( it != m_invokeDataMap.constEnd() )
{ {
const InvokeData& data = ( *it ); const InvokeData& data = ( *it );
data.method.invoke( data.receiver, data.connectionType ); auto receiver = const_cast< QObject* >( data.receiver );
if ( data.slotObj )
{
void* args[] = { 0 };
data.slotObj->call( receiver, args );
}
else
{
data.method.invoke( receiver, Qt::AutoConnection );
}
} }
return true; return true;
@ -116,16 +167,16 @@ bool QskShortcutHandler::event( QEvent* event )
return false; return false;
} }
Q_GLOBAL_STATIC( QskShortcutHandler, qskShortcutHandler )
int QskShortcut::addShortcut( const QKeySequence& key, int QskShortcut::addShortcut( const QKeySequence& key,
QObject* receiver, const char* method, bool autoRepeat, const QObject* receiver, const char* method )
bool autoRepeat, Qt::ConnectionType connectionType )
{ {
return addShortcut( nullptr, key, receiver, method, autoRepeat, connectionType ); return addShortcut( nullptr, key, autoRepeat, receiver, method );
} }
int QskShortcut::addShortcut( QQuickWindow* window, const QKeySequence& key, int QskShortcut::addShortcut( QQuickWindow* window, const QKeySequence& key,
QObject* receiver, const char* method, bool autoRepeat, const QObject* receiver, const char* method )
bool autoRepeat, Qt::ConnectionType connectionType )
{ {
int id = 0; int id = 0;
@ -139,17 +190,42 @@ int QskShortcut::addShortcut( QQuickWindow* window, const QKeySequence& key,
if ( methodIndex >= 0 ) if ( methodIndex >= 0 )
{ {
id = QskShortcutHandler::instance()->addShortcut( window, key, id = qskShortcutHandler->addShortcut(
receiver, metaObject->method( methodIndex ), connectionType ); window, key, receiver, metaObject->method( methodIndex ) );
if ( !autoRepeat ) if ( !autoRepeat )
QskShortcutHandler::instance()->setAutoRepeat( id, false ); qskShortcutHandler->setAutoRepeat( id, false );
} }
return id; return id;
} }
int QskShortcut::addShortcutImpl( const QKeySequence& key,
bool autoRepeat, const QObject* receiver, QtPrivate::QSlotObjectBase* slotObj )
{
#if 1
if ( receiver )
{
// how to call the slot in the receiver context, TODO ...
Q_ASSERT( qskShortcutHandler->thread() == receiver->thread() );
}
#endif
QQuickWindow* window = nullptr;
int id = qskShortcutHandler->addShortcut( window, key, receiver, slotObj );
if ( !autoRepeat )
qskShortcutHandler->setAutoRepeat( id, false );
return id;
}
void QskShortcut::setAutoRepeat( int id, bool on ) void QskShortcut::setAutoRepeat( int id, bool on )
{ {
QskShortcutHandler::instance()->setAutoRepeat( id, on ); qskShortcutHandler->setAutoRepeat( id, on );
}
void QskShortcut::setEnabled( int id, bool on )
{
qskShortcutHandler->setEnabled( id, on );
} }

View File

@ -7,7 +7,9 @@
#define QSK_SHORTCUT_H #define QSK_SHORTCUT_H
#include "QskGlobal.h" #include "QskGlobal.h"
#include <Qt>
#include <QArgument>
#include <QObject>
class QQuickWindow; class QQuickWindow;
class QKeySequence; class QKeySequence;
@ -15,15 +17,61 @@ class QObject;
namespace QskShortcut namespace QskShortcut
{ {
QSK_EXPORT int addShortcut( const QKeySequence&,
QObject* receiver, const char* method, bool autoRepeat = true,
Qt::ConnectionType type = Qt::AutoConnection );
QSK_EXPORT int addShortcut( QQuickWindow*, const QKeySequence&,
QObject* receiver, const char* method, bool autoRepeat = true,
Qt::ConnectionType type = Qt::AutoConnection );
QSK_EXPORT void setAutoRepeat( int, bool on ); QSK_EXPORT void setAutoRepeat( int, bool on );
QSK_EXPORT void setEnabled( int, bool on );
QSK_EXPORT int addShortcut( const QKeySequence&, bool autoRepeat,
const QObject* receiver, const char* method );
QSK_EXPORT int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat,
const QObject* receiver, const char* method );
QSK_EXPORT int addShortcutImpl( const QKeySequence&, bool autoRepeat,
const QObject* receiver, QtPrivate::QSlotObjectBase* );
// shortcut calling a QObject method
template< typename Func1 >
inline int addShortcut( const QKeySequence& key, bool autoRepeat,
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
{
typedef QtPrivate::FunctionPointer< Func1 > SlotType;
Q_STATIC_ASSERT_X( int( SlotType::ArgumentCount ) == 0,
"The slot must not have any arguments.");
auto slotObj = new QtPrivate::QSlotObject< Func1,
typename SlotType::Arguments, void >(slot);
return addShortcutImpl( key, autoRepeat, receiver, slotObj );
}
// shortcut calling a functor or function pointer
template< typename Func1 >
int addShortcut( const QKeySequence& key, 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." );
auto slotObj = new QFunctorSlotObject< Func1, 0,
typename List_Left< void, 0 >::Value, void >( std::move( slot ) );
return addShortcutImpl( key, autoRepeat, context, slotObj );
}
// shortcut calling a functor or function pointer
template< typename Func1 >
int addShortcut( const QKeySequence& key, bool autoRepeat, Func1 slot )
{
return addShortcut( key, autoRepeat, nullptr, slot );
}
} }
#endif #endif

View File

@ -32,21 +32,21 @@ void SkinnyShortcut::enable( Types types )
if ( types & RotateSkin ) if ( types & RotateSkin )
{ {
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ), QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ),
&s_shortcut, SLOT( rotateSkin() ) ); false, &s_shortcut, SLOT( rotateSkin() ) );
cout << "CTRL-S to change the skin." << endl; cout << "CTRL-S to change the skin." << endl;
} }
if ( types & DebugBackground ) if ( types & DebugBackground )
{ {
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_B ), QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_B ),
&s_shortcut, SLOT( showBackground() ) ); false, &s_shortcut, SLOT( showBackground() ) );
cout << "CTRL-B to enable visual debugging modes." << endl; cout << "CTRL-B to enable visual debugging modes." << endl;
} }
if ( types & DebugStatistics ) if ( types & DebugStatistics )
{ {
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_K ), QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_K ),
&s_shortcut, SLOT( debugStatistics() ) ); false, &s_shortcut, SLOT( debugStatistics() ) );
cout << "CTRL-K to dump statistics about the items/nodes being currently used." << endl; cout << "CTRL-K to dump statistics about the items/nodes being currently used." << endl;
} }
@ -56,7 +56,7 @@ void SkinnyShortcut::enable( Types types )
// when not being implemented by the platform !! // when not being implemented by the platform !!
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_Q ), QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_Q ),
QGuiApplication::instance(), SLOT( quit() ) ); false, QGuiApplication::instance(), SLOT( quit() ) );
cout << "CTRL-Q to terminate the application." << endl; cout << "CTRL-Q to terminate the application." << endl;
} }
} }