qskinny/src/controls/QskShortcut.cpp

232 lines
5.8 KiB
C++
Raw Normal View History

2017-07-21 16:21:34 +00:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskShortcut.h"
#include <QObject>
#include <QKeySequence>
#include <QQuickWindow>
#include <QMap>
2017-12-03 16:58:18 +00:00
#include <QGlobalStatic>
#include <QtGui/private/qguiapplication_p.h>
2017-07-21 16:21:34 +00:00
class QskShortcutHandler final : public QObject
{
public:
2017-12-03 16:58:18 +00:00
int addShortcut( QQuickWindow*, const QKeySequence&,
const QObject* receiver, const QMetaMethod& );
2017-07-21 16:21:34 +00:00
int addShortcut( QQuickWindow*, const QKeySequence&,
2017-12-03 16:58:18 +00:00
const QObject* receiver, QtPrivate::QSlotObjectBase* );
2017-07-21 16:21:34 +00:00
void setEnabled( int id, bool );
void setAutoRepeat( int id, bool repeat );
protected:
virtual bool event( QEvent* event ) override final;
private:
2017-12-03 16:58:18 +00:00
void cleanUp( QObject* );
2017-07-21 16:21:34 +00:00
static bool contextMatcher( QObject*, Qt::ShortcutContext );
static QShortcutMap& map();
2017-12-03 16:58:18 +00:00
class InvokeData
2017-07-21 16:21:34 +00:00
{
2017-12-03 16:58:18 +00:00
public:
~InvokeData()
{
if ( slotObj )
slotObj->destroyIfLastRef();
}
2017-07-21 16:21:34 +00:00
QMetaMethod method;
2017-12-03 16:58:18 +00:00
QtPrivate::QSlotObjectBase* slotObj;
const QObject* receiver;
2017-07-21 16:21:34 +00:00
};
QMap< int, InvokeData > m_invokeDataMap;
};
inline QShortcutMap& QskShortcutHandler::map()
{
return QGuiApplicationPrivate::instance()->shortcutMap;
}
2017-12-03 16:58:18 +00:00
int QskShortcutHandler::addShortcut(
QQuickWindow* window, const QKeySequence& key,
const QObject* receiver, const QMetaMethod& method )
2017-07-21 16:21:34 +00:00
{
int id;
if ( window )
id = map().addShortcut( window, key, Qt::WindowShortcut, contextMatcher );
else
2017-10-23 08:19:49 +00:00
id = map().addShortcut( this, key, Qt::ApplicationShortcut, contextMatcher );
2017-07-21 16:21:34 +00:00
2017-10-23 08:19:49 +00:00
InvokeData& data = m_invokeDataMap[ id ];
2017-07-21 16:21:34 +00:00
data.receiver = receiver;
data.method = method;
2017-12-03 16:58:18 +00:00
data.slotObj = nullptr;
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 );
2017-07-21 16:21:34 +00:00
return id;
}
2017-12-03 16:58:18 +00:00
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;
}
}
2017-07-21 16:21:34 +00:00
bool QskShortcutHandler::contextMatcher( QObject* obj, Qt::ShortcutContext context )
{
switch ( context )
{
case Qt::ApplicationShortcut:
{
return true;
}
case Qt::WindowShortcut:
{
return obj == QGuiApplication::focusWindow();
}
default:
return false;
}
}
void QskShortcutHandler::setEnabled( int id, bool enabled )
{
map().setShortcutEnabled( enabled, id, this );
}
void QskShortcutHandler::setAutoRepeat( int id, bool repeat )
{
map().setShortcutAutoRepeat( repeat, id, this );
}
bool QskShortcutHandler::event( QEvent* event )
{
if ( event->type() == QEvent::Shortcut )
{
const QShortcutEvent* se = static_cast< const QShortcutEvent* >( event );
2017-10-29 13:01:06 +00:00
const auto it = m_invokeDataMap.constFind( se->shortcutId() );
2017-07-21 16:21:34 +00:00
if ( it != m_invokeDataMap.constEnd() )
{
const InvokeData& data = ( *it );
2017-12-03 16:58:18 +00:00
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 );
}
2017-07-21 16:21:34 +00:00
}
return true;
}
return false;
}
2017-12-03 16:58:18 +00:00
Q_GLOBAL_STATIC( QskShortcutHandler, qskShortcutHandler )
2017-07-21 16:21:34 +00:00
int QskShortcut::addShortcut( const QKeySequence& key,
2017-12-03 16:58:18 +00:00
bool autoRepeat, const QObject* receiver, const char* method )
2017-07-21 16:21:34 +00:00
{
2017-12-03 16:58:18 +00:00
return addShortcut( nullptr, key, autoRepeat, receiver, method );
2017-07-21 16:21:34 +00:00
}
int QskShortcut::addShortcut( QQuickWindow* window, const QKeySequence& key,
2017-12-03 16:58:18 +00:00
bool autoRepeat, const QObject* receiver, const char* method )
2017-07-21 16:21:34 +00:00
{
int id = 0;
if ( receiver == nullptr )
return id;
const QMetaObject* metaObject = receiver->metaObject();
const int methodIndex = metaObject->indexOfMethod(
2017-10-30 07:33:43 +00:00
QMetaObject::normalizedSignature( method ).constData() + 1 );
2017-07-21 16:21:34 +00:00
if ( methodIndex >= 0 )
{
2017-12-03 16:58:18 +00:00
id = qskShortcutHandler->addShortcut(
window, key, receiver, metaObject->method( methodIndex ) );
2017-07-21 16:21:34 +00:00
if ( !autoRepeat )
2017-12-03 16:58:18 +00:00
qskShortcutHandler->setAutoRepeat( id, false );
2017-07-21 16:21:34 +00:00
}
return id;
}
2017-12-03 16:58:18 +00:00
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;
}
2017-07-21 16:21:34 +00:00
void QskShortcut::setAutoRepeat( int id, bool on )
{
2017-12-03 16:58:18 +00:00
qskShortcutHandler->setAutoRepeat( id, on );
}
void QskShortcut::setEnabled( int id, bool on )
{
qskShortcutHandler->setEnabled( id, on );
2017-07-21 16:21:34 +00:00
}