diff options
author | Axel Spoerl <axel.spoerl@qt.io> | 2023-04-19 18:46:33 +0200 |
---|---|---|
committer | Axel Spoerl <axel.spoerl@qt.io> | 2023-04-22 14:57:46 +0200 |
commit | b1802a164b8682ed9e8956a5a19a90ade65c25d0 (patch) | |
tree | 579cf82bfae53fc2b135bbf3bc606b56779e2452 /src/widgets | |
parent | 544464c3d173246e58d39351599b0ffa87ec43df (diff) |
Handle parent being a child's focus procy in QWidget::setFocusProxy
When a parent became a new child's focus proxy in an existing focus
chain, the child was appended at the end of the chain.
That leads to broken tab order, e.g. with a QComboBox which became
editable after a focus chain has been set.
This patch captures the case and insertes the new child after its
parent in the focus chain.
A corresponding test function is added in tst_QWidget.
Fixes: QTBUG-111978
Pick-to: 6.5
Change-Id: I3a426c0560fa830b7b7ffead54f26dd0adef499f
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index cde0542eee..d5dbc3f21a 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -6412,6 +6412,30 @@ void QWidget::setFocusProxy(QWidget * w) d->focus_prev = oldPrev; oldPrev->d_func()->focus_next = this; firstChild->d_func()->focus_prev = this; + } else if (w->isAncestorOf(this)) { + // If the focus proxy is a parent, 'this' has to be inserted directly after its parent in the focus chain + // remove it from the chain and insert this into the focus chain after its parent + + // is this the case already? + QWidget *parentsNext = w->d_func()->focus_next; + if (parentsNext == this) { + // nothing to do. + Q_ASSERT(d->focus_prev == w); + } else { + // Remove 'this' from the focus chain by making prev and next point directly to each other + QWidget *myOldNext = d->focus_next; + QWidget *myOldPrev = d->focus_prev; + if (myOldNext && myOldPrev) { + myOldNext->d_func()->focus_prev = myOldPrev; + myOldPrev->d_func()->focus_next = myOldNext; + } + + // Insert 'this' behind the parent + w->d_func()->focus_next = this; + d->focus_prev = w; + d->focus_next = parentsNext; + parentsNext->d_func()->focus_prev = this; + } } if (moveFocusToProxy) |