Description: QWidget: fix setTabOrder for compound widgets
Origin: upstream, commits:
 https://code.qt.io/cgit/qt/qtbase.git/commit/?id=81e298a51d08c510
 https://code.qt.io/cgit/qt/qtbase.git/commit/?id=a7cbb8c639487edb
Last-Update: 2022-02-13

--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -6975,35 +6975,41 @@ void QWidget::setTabOrder(QWidget* first
                 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);
+    {
+        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);
+    }
 
-    // If the tab order is already correct, exit early
-    if (lastFocusChildOfFirst->d_func()->focus_next == second)
-        return;
-
-    // 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
