summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/widgets/kernel/qwidget.cpp60
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp73
2 files changed, 105 insertions, 28 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 8b225df8be..6ef3a4f163 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1,4 +1,4 @@
-/****************************************************************************
+/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
@@ -7017,37 +7017,41 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
lastFocusChild = focusNext;
}
};
+ auto setPrev = [](QWidget *w, QWidget *prev)
+ {
+ w->d_func()->focus_prev = prev;
+ };
+ auto setNext = [](QWidget *w, QWidget *next)
+ {
+ w->d_func()->focus_next = next;
+ };
- QWidget *lastFocusChildOfFirst, *lastFocusChildOfSecond;
- determineLastFocusChild(first, lastFocusChildOfFirst);
+ // remove the second widget from the chain
+ QWidget *lastFocusChildOfSecond;
determineLastFocusChild(second, lastFocusChildOfSecond);
-
- // If the tab order is already correct, exit early
- if (lastFocusChildOfFirst == second ||
- lastFocusChildOfFirst->d_func()->focus_next == second) {
- return;
+ {
+ QWidget *oldPrev = second->d_func()->focus_prev;
+ QWidget *prevWithFocus = oldPrev;
+ while (prevWithFocus->focusPolicy() == Qt::NoFocus)
+ prevWithFocus = prevWithFocus->d_func()->focus_prev;
+ // only widgets between first and second -> all is fine
+ if (prevWithFocus == first)
+ return;
+ QWidget *oldNext = lastFocusChildOfSecond->d_func()->focus_next;
+ setPrev(oldNext, oldPrev);
+ setNext(oldPrev, oldNext);
}
- // Note that we need to handle two different sections in the tab chain; The section
- // that 'first' belongs to (firstSection), where we are about to insert 'second', and
- // the section that 'second' used be a part of (secondSection). When we pull 'second'
- // out of the second section and insert it into the first, we also need to ensure
- // that we leave the second section in a connected state.
- QWidget *firstChainOldSecond = lastFocusChildOfFirst->d_func()->focus_next;
- QWidget *secondChainNewFirst = second->d_func()->focus_prev;
- QWidget *secondChainNewSecond = lastFocusChildOfSecond->d_func()->focus_next;
-
- // Insert 'second' after 'first'
- lastFocusChildOfFirst->d_func()->focus_next = second;
- second->d_func()->focus_prev = lastFocusChildOfFirst;
-
- // The widget that used to be 'second' in the first section, should now become 'third'
- lastFocusChildOfSecond->d_func()->focus_next = firstChainOldSecond;
- firstChainOldSecond->d_func()->focus_prev = lastFocusChildOfSecond;
-
- // Repair the second section after we pulled 'second' out of it
- secondChainNewFirst->d_func()->focus_next = secondChainNewSecond;
- secondChainNewSecond->d_func()->focus_prev = secondChainNewFirst;
+ // insert the second widget into the chain
+ QWidget *lastFocusChildOfFirst;
+ determineLastFocusChild(first, lastFocusChildOfFirst);
+ {
+ QWidget *oldNext = lastFocusChildOfFirst->d_func()->focus_next;
+ setPrev(second, lastFocusChildOfFirst);
+ setNext(lastFocusChildOfFirst, second);
+ setPrev(oldNext, lastFocusChildOfSecond);
+ setNext(lastFocusChildOfSecond, oldNext);
+ }
}
/*!\internal
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index c0dfaf80a3..489edb703c 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -180,6 +180,7 @@ private slots:
void tabOrderWithProxy();
void tabOrderWithCompoundWidgets();
void tabOrderNoChange();
+ void tabOrderNoChange2();
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
void activation();
#endif
@@ -1940,6 +1941,24 @@ static QVector<QWidget*> getFocusChain(QWidget *start, bool bForward)
return ret;
}
+//#define DEBUG_FOCUS_CHAIN
+static void dumpFocusChain(QWidget *start, bool bForward, const char *desc = nullptr)
+{
+#ifdef DEBUG_FOCUS_CHAIN
+ qDebug() << "Dump focus chain, start:" << start << "isForward:" << bForward << desc;
+ QWidget *cur = start;
+ do {
+ qDebug() << cur;
+ auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
+ cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
+ } while (cur != start);
+#else
+ Q_UNUSED(start)
+ Q_UNUSED(bForward)
+ Q_UNUSED(desc)
+#endif
+}
+
void tst_QWidget::tabOrderNoChange()
{
QWidget w;
@@ -1951,7 +1970,61 @@ void tst_QWidget::tabOrderNoChange()
const auto focusChainForward = getFocusChain(&w, true);
const auto focusChainBackward = getFocusChain(&w, false);
+ dumpFocusChain(&w, true);
QWidget::setTabOrder(tabWidget, tv);
+ dumpFocusChain(&w, true);
+ QCOMPARE(focusChainForward, getFocusChain(&w, true));
+ QCOMPARE(focusChainBackward, getFocusChain(&w, false));
+}
+
+void tst_QWidget::tabOrderNoChange2()
+{
+ QWidget w;
+ auto *verticalLayout = new QVBoxLayout(&w);
+ auto *tabWidget = new QTabWidget(&w);
+ tabWidget->setObjectName("tabWidget");
+ verticalLayout->addWidget(tabWidget);
+
+ auto *tab1 = new QWidget(tabWidget);
+ tab1->setObjectName("tab1");
+ auto *vLay1 = new QVBoxLayout(tab1);
+ auto *le1 = new QLineEdit(tab1);
+ le1->setObjectName("le1");
+ auto *le2 = new QLineEdit(tab1);
+ le2->setObjectName("le2");
+ vLay1->addWidget(le1);
+ vLay1->addWidget(le2);
+ tabWidget->addTab(tab1, QStringLiteral("Tab 1"));
+
+ auto *tab2 = new QWidget(tabWidget);
+ tab2->setObjectName("tab2");
+ auto *vLay2 = new QVBoxLayout(tab2);
+ auto *le3 = new QLineEdit(tab2);
+ le3->setObjectName("le3");
+ auto *le4 = new QLineEdit(tab2);
+ le4->setObjectName("le4");
+ vLay2->addWidget(le3);
+ vLay2->addWidget(le4);
+ tabWidget->addTab(tab2, QStringLiteral("Tab 2"));
+
+ const auto focusChainForward = getFocusChain(&w, true);
+ const auto focusChainBackward = getFocusChain(&w, false);
+ dumpFocusChain(&w, true);
+ dumpFocusChain(&w, false);
+ // this will screw up the focus chain order without visible changes,
+ // so don't call it here for the simplicity of the test
+ //QWidget::setTabOrder(tabWidget, le1);
+
+ QWidget::setTabOrder(le1, le2);
+ dumpFocusChain(&w, true, "QWidget::setTabOrder(le1, le2)");
+ QWidget::setTabOrder(le2, le3);
+ dumpFocusChain(&w, true, "QWidget::setTabOrder(le2, le3)");
+ QWidget::setTabOrder(le3, le4);
+ dumpFocusChain(&w, true, "QWidget::setTabOrder(le3, le4)");
+ QWidget::setTabOrder(le4, tabWidget);
+ dumpFocusChain(&w, true, "QWidget::setTabOrder(le4, tabWidget)");
+ dumpFocusChain(&w, false);
+
QCOMPARE(focusChainForward, getFocusChain(&w, true));
QCOMPARE(focusChainBackward, getFocusChain(&w, false));
}