summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAxel Spoerl <axel.spoerl@qt.io>2023-04-19 18:46:33 +0200
committerAxel Spoerl <axel.spoerl@qt.io>2023-04-22 14:57:46 +0200
commitb1802a164b8682ed9e8956a5a19a90ade65c25d0 (patch)
tree579cf82bfae53fc2b135bbf3bc606b56779e2452 /src
parent544464c3d173246e58d39351599b0ffa87ec43df (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')
-rw-r--r--src/widgets/kernel/qwidget.cpp24
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)