Introduce QEvent::isInputEvent

This makes it easier to reliably maintain input-event related states
in widgets, in particluar the state of keyboard modifiers. Instead of
testing for all possible event types, code can just test the flag before
safely static_cast'ing to QInputEvent to access the modifiers.

Simplify the code in QAbstractItemView accordingly.

Task-number: QTBUG-73829
Change-Id: Idc7c08e2f3f1e8844f5c6693c195153038ee6490
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Volker Hilsheimer 2020-07-03 11:06:37 +02:00
parent 81159cf3f7
commit d1111632e2
4 changed files with 29 additions and 22 deletions

View File

@ -295,7 +295,7 @@ QT_BEGIN_NAMESPACE
Contructs an event object of type \a type. Contructs an event object of type \a type.
*/ */
QEvent::QEvent(Type type) QEvent::QEvent(Type type)
: d(nullptr), t(type), posted(false), spont(false), m_accept(true) : d(nullptr), t(type), posted(false), spont(false), m_accept(true), m_inputEvent(false)
{ {
Q_TRACE(QEvent_ctor, this, t); Q_TRACE(QEvent_ctor, this, t);
} }
@ -317,6 +317,14 @@ QEvent::QEvent(const QEvent &other)
Q_ASSERT_X(!d, "QEvent", "Impossible, this can't happen: QEventPrivate isn't defined anywhere"); Q_ASSERT_X(!d, "QEvent", "Impossible, this can't happen: QEventPrivate isn't defined anywhere");
} }
/*!
\internal
\since 6.0
\fn QEvent::QEvent(Type type, QEvent::InputEventTag)
Constructs an event object of type \a type, setting the inputEvent flag to true.
*/
/*! /*!
\internal \internal
Attempts to copy the \a other event. Attempts to copy the \a other event.
@ -407,6 +415,14 @@ QEvent::~QEvent()
The return value of this function is not defined for paint events. The return value of this function is not defined for paint events.
*/ */
/*!
\fn bool QEvent::isInputEvent() const
\since 6.0
Returns \c true if the event object is a QInputEvent or one of its
subclasses.
*/
namespace { namespace {
template <size_t N> template <size_t N>
struct QBasicAtomicBitField { struct QBasicAtomicBitField {

View File

@ -307,9 +307,13 @@ public:
inline void accept() { m_accept = true; } inline void accept() { m_accept = true; }
inline void ignore() { m_accept = false; } inline void ignore() { m_accept = false; }
inline bool isInputEvent() const noexcept { return m_inputEvent; }
static int registerEventType(int hint = -1) noexcept; static int registerEventType(int hint = -1) noexcept;
protected: protected:
struct InputEventTag { explicit InputEventTag() = default; };
QEvent(Type type, InputEventTag) : QEvent(type) { m_inputEvent = true; }
QEventPrivate *d; QEventPrivate *d;
ushort t; ushort t;
@ -317,7 +321,8 @@ private:
ushort posted : 1; ushort posted : 1;
ushort spont : 1; ushort spont : 1;
ushort m_accept : 1; ushort m_accept : 1;
ushort reserved : 13; ushort m_inputEvent : 1;
ushort reserved : 12;
friend class QCoreApplication; friend class QCoreApplication;
friend class QCoreApplicationPrivate; friend class QCoreApplicationPrivate;

View File

@ -163,7 +163,7 @@ QEnterEvent::~QEnterEvent()
\internal \internal
*/ */
QInputEvent::QInputEvent(Type type, const QInputDevice *dev, Qt::KeyboardModifiers modifiers) QInputEvent::QInputEvent(Type type, const QInputDevice *dev, Qt::KeyboardModifiers modifiers)
: QEvent(type), m_dev(dev), m_modState(modifiers) : QEvent(type, QEvent::InputEventTag{}), m_dev(dev), m_modState(modifiers)
{} {}
/*! /*!

View File

@ -3917,21 +3917,9 @@ QItemSelectionModel::SelectionFlags QAbstractItemView::selectionCommand(const QM
const QEvent *event) const const QEvent *event) const
{ {
Q_D(const QAbstractItemView); Q_D(const QAbstractItemView);
Qt::KeyboardModifiers keyModifiers = Qt::NoModifier; Qt::KeyboardModifiers keyModifiers = event && event->isInputEvent()
if (event) { ? static_cast<const QInputEvent*>(event)->modifiers()
switch (event->type()) { : Qt::NoModifier;
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseMove:
case QEvent::KeyPress:
case QEvent::KeyRelease:
keyModifiers = (static_cast<const QInputEvent*>(event))->modifiers();
break;
default:
break;
}
}
switch (d->selectionMode) { switch (d->selectionMode) {
case NoSelection: // Never update selection model case NoSelection: // Never update selection model
return QItemSelectionModel::NoUpdate; return QItemSelectionModel::NoUpdate;
@ -3989,16 +3977,16 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC
{ {
Qt::KeyboardModifiers modifiers = Qt::NoModifier; Qt::KeyboardModifiers modifiers = Qt::NoModifier;
if (event) { if (event) {
if (event->isInputEvent())
modifiers = static_cast<const QInputEvent*>(event)->modifiers();
switch (event->type()) { switch (event->type()) {
case QEvent::MouseMove: { case QEvent::MouseMove: {
// Toggle on MouseMove // Toggle on MouseMove
modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
if (modifiers & Qt::ControlModifier) if (modifiers & Qt::ControlModifier)
return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags(); return QItemSelectionModel::ToggleCurrent|selectionBehaviorFlags();
break; break;
} }
case QEvent::MouseButtonPress: { case QEvent::MouseButtonPress: {
modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button(); const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
const bool rightButtonPressed = button & Qt::RightButton; const bool rightButtonPressed = button & Qt::RightButton;
const bool shiftKeyPressed = modifiers & Qt::ShiftModifier; const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
@ -4016,7 +4004,6 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC
} }
case QEvent::MouseButtonRelease: { case QEvent::MouseButtonRelease: {
// ClearAndSelect on MouseButtonRelease if MouseButtonPress on selected item or empty area // ClearAndSelect on MouseButtonRelease if MouseButtonPress on selected item or empty area
modifiers = static_cast<const QMouseEvent*>(event)->modifiers();
const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button(); const Qt::MouseButton button = static_cast<const QMouseEvent*>(event)->button();
const bool rightButtonPressed = button & Qt::RightButton; const bool rightButtonPressed = button & Qt::RightButton;
const bool shiftKeyPressed = modifiers & Qt::ShiftModifier; const bool shiftKeyPressed = modifiers & Qt::ShiftModifier;
@ -4029,7 +4016,6 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC
} }
case QEvent::KeyPress: { case QEvent::KeyPress: {
// NoUpdate on Key movement and Ctrl // NoUpdate on Key movement and Ctrl
modifiers = static_cast<const QKeyEvent*>(event)->modifiers();
switch (static_cast<const QKeyEvent*>(event)->key()) { switch (static_cast<const QKeyEvent*>(event)->key()) {
case Qt::Key_Backtab: case Qt::Key_Backtab:
modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab