diff options
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 556 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 35 |
2 files changed, 455 insertions, 136 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 30daee1b79..a7a0b0362f 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -6,6 +6,7 @@ #include "qapplication_p.h" #include "qbrush.h" #include "qcursor.h" +#include "private/qduplicatetracker_p.h" #include "qevent.h" #include "qlayout.h" #if QT_CONFIG(menu) @@ -84,6 +85,7 @@ using namespace Qt::StringLiterals; Q_LOGGING_CATEGORY(lcWidgetPainting, "qt.widgets.painting", QtWarningMsg); Q_LOGGING_CATEGORY(lcWidgetShowHide, "qt.widgets.showhide", QtWarningMsg); Q_LOGGING_CATEGORY(lcWidgetWindow, "qt.widgets.window", QtWarningMsg); +Q_LOGGING_CATEGORY(lcFocus, "qt.widgets.focus") #ifndef QT_NO_DEBUG_STREAM namespace { @@ -818,12 +820,7 @@ struct QWidgetExceptionCleaner Q_UNUSED(d); #else QWidgetPrivate::allWidgets->remove(that); - if (d->focus_next != that) { - if (d->focus_next) - d->focus_next->d_func()->focus_prev = d->focus_prev; - if (d->focus_prev) - d->focus_prev->d_func()->focus_next = d->focus_next; - } + d->removeFromFocusChain(); #endif } }; @@ -991,7 +988,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) //give potential windows a bigger "pre-initial" size; create() will give them a new size later data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480); - focus_next = focus_prev = q; + initFocusChain(); if ((f & Qt::WindowType_Mask) == Qt::Desktop) q->create(); @@ -1477,17 +1474,9 @@ QWidget::~QWidget() // delete layout while we still are a valid widget delete d->layout; d->layout = nullptr; - // Remove myself from focus list - - Q_ASSERT(d->focus_next->d_func()->focus_prev == this); - Q_ASSERT(d->focus_prev->d_func()->focus_next == this); - - if (d->focus_next != this) { - d->focus_next->d_func()->focus_prev = d->focus_prev; - d->focus_prev->d_func()->focus_next = d->focus_next; - d->focus_next = d->focus_prev = nullptr; - } + // Remove this from focus list + d->removeFromFocusChain(QWidgetPrivate::FocusChainRemovalRule::AssertConsistency); QT_TRY { #if QT_CONFIG(graphicsview) @@ -6406,39 +6395,18 @@ void QWidget::setFocusProxy(QWidget * w) break; } Q_ASSERT(firstChild); // can't be nullptr since w is a child - QWidget *oldNext = d->focus_next; - QWidget *oldPrev = d->focus_prev; - oldNext->d_func()->focus_prev = oldPrev; - oldPrev->d_func()->focus_next = oldNext; - - oldPrev = firstChild->d_func()->focus_prev; - d->focus_next = firstChild; - d->focus_prev = oldPrev; - oldPrev->d_func()->focus_next = this; - firstChild->d_func()->focus_prev = this; + d->insertIntoFocusChainBefore(firstChild); } else if (w && 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; + QWidget *parentsNext = w->nextInFocusChain(); if (parentsNext == this) { // nothing to do. - Q_ASSERT(d->focus_prev == w); + Q_ASSERT(previousInFocusChain() == 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; + d->QWidgetPrivate::insertIntoFocusChainAfter(w); } } @@ -6871,7 +6839,8 @@ QObject *QWidgetPrivate::focusObject() */ QWidget *QWidget::nextInFocusChain() const { - return const_cast<QWidget *>(d_func()->focus_next); + Q_D(const QWidget); + return d->nextPrevElementInFocusChain(QWidgetPrivate::FocusDirection::Next); } /*! @@ -6884,7 +6853,8 @@ QWidget *QWidget::nextInFocusChain() const */ QWidget *QWidget::previousInFocusChain() const { - return const_cast<QWidget *>(d_func()->focus_prev); + Q_D(const QWidget); + return d->nextPrevElementInFocusChain(QWidgetPrivate::FocusDirection::Previous); } /*! @@ -7039,9 +7009,9 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second) } } else if (target->isAncestorOf(focusProxy)) { lastFocusChild = focusProxy; - for (QWidget *focusNext = lastFocusChild->d_func()->focus_next; + for (QWidget *focusNext = lastFocusChild->nextInFocusChain(); focusNext != focusProxy && target->isAncestorOf(focusNext) && focusNext->window() == focusProxy->window(); - focusNext = focusNext->d_func()->focus_next) { + focusNext = focusNext->nextInFocusChain()) { if (focusNext == noFurtherThan) break; if (focusNext->focusPolicy() != Qt::NoFocus) @@ -7050,13 +7020,6 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second) } return lastFocusChild; }; - auto setPrev = [](QWidget *w, QWidget *prev) { - w->d_func()->focus_prev = prev; - }; - auto setNext = [](QWidget *w, QWidget *next) { - w->d_func()->focus_next = next; - }; - // detect inflection in case we have compound widgets QWidget *lastFocusChildOfFirst = determineLastFocusChild(first, second); if (lastFocusChildOfFirst == second) @@ -7065,28 +7028,15 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second) if (lastFocusChildOfSecond == first) lastFocusChildOfSecond = second; - // remove the second widget from the chain - { - 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); - } - - // insert the second widget into the chain - { - QWidget *oldNext = lastFocusChildOfFirst->d_func()->focus_next; - setPrev(second, lastFocusChildOfFirst); - setNext(lastFocusChildOfFirst, second); - setPrev(oldNext, lastFocusChildOfSecond); - setNext(lastFocusChildOfSecond, oldNext); - } + // Return if only NoFocus widgets are between first and second + QWidget *oldPrev = second->previousInFocusChain(); + QWidget *prevWithFocus = oldPrev; + while (prevWithFocus->focusPolicy() == Qt::NoFocus) + prevWithFocus = prevWithFocus->previousInFocusChain(); + if (prevWithFocus == first) + return; + const QWidgetList chain = QWidgetPrivate::takeFromFocusChain(second, lastFocusChildOfSecond); + QWidgetPrivate::insertIntoFocusChain(chain, QWidgetPrivate::FocusDirection::Next, lastFocusChildOfFirst); } void QWidget::setTabOrder(std::initializer_list<QWidget *> widgets) @@ -7124,67 +7074,8 @@ void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw) if (focus_child) focus_child->clearFocus(); - // separate the focus chain into new (children of myself) and old (the rest) - QWidget *firstOld = nullptr; - //QWidget *firstNew = q; //invariant - QWidget *o = nullptr; // last in the old list - QWidget *n = q; // last in the new list - - bool prevWasNew = true; - QWidget *w = focus_next; - - //Note: for efficiency, we do not maintain the list invariant inside the loop - //we append items to the relevant list, and we optimize by not changing pointers - //when subsequent items are going into the same list. - while (w != q) { - bool currentIsNew = q->isAncestorOf(w); - if (currentIsNew) { - if (!prevWasNew) { - //prev was old -- append to new list - n->d_func()->focus_next = w; - w->d_func()->focus_prev = n; - } - n = w; - } else { - if (prevWasNew) { - //prev was new -- append to old list, if there is one - if (o) { - o->d_func()->focus_next = w; - w->d_func()->focus_prev = o; - } else { - // "create" the old list - firstOld = w; - } - } - o = w; - } - w = w->d_func()->focus_next; - prevWasNew = currentIsNew; - } - - //repair the old list: - if (firstOld) { - o->d_func()->focus_next = firstOld; - firstOld->d_func()->focus_prev = o; - } - - if (!q->isWindow()) { - QWidget *topLevel = q->window(); - //insert new chain into toplevel's chain - - QWidget *prev = topLevel->d_func()->focus_prev; - - topLevel->d_func()->focus_prev = n; - prev->d_func()->focus_next = q; - - focus_prev = prev; - n->d_func()->focus_next = topLevel; - } else { - //repair the new list - n->d_func()->focus_next = q; - focus_prev = n; - } - + insertIntoFocusChain(QWidgetPrivate::FocusDirection::Previous, q->window()); + reparentFocusChildren(QWidgetPrivate::FocusDirection::Next); } /*! @@ -13371,6 +13262,399 @@ QDebug operator<<(QDebug debug, const QWidget *widget) } #endif // !QT_NO_DEBUG_STREAM + +// *************************** Focus abstraction ************************************ + +#define FOCUS_NEXT(w) w->d_func()->focus_next +#define FOCUS_PREV(w) w->d_func()->focus_prev + +/*! + \internal + \return next or previous element in the focus chain, depending on + \param direction, irrespective of focus proxies or widgets with Qt::NoFocus. + */ +QWidget *QWidgetPrivate::nextPrevElementInFocusChain(FocusDirection direction) const +{ + Q_Q(const QWidget); + return direction == FocusDirection::Next ? FOCUS_NEXT(q) : FOCUS_PREV(q); +} + +/*! + \internal + Removes a widget from the focus chain, respecting the flags set in \param rules. + \list + \li EnsureFocusOut: If the widget has input focus, transfer focus to the next or previous widget + in the focus chain, depending on \param direction. + \li RemoveInconsistent: Remove the widget, even if its focus chain is inconsistent. + \li AssertConsistency: qFatal, if the focus chain is inconsistent. This is used in the QWidget destructor. + \endlist + \return \c true if the widget has been removed, otherwise \c false. + */ +bool QWidgetPrivate::removeFromFocusChain(FocusChainRemovalRules rules, FocusDirection direction) +{ + Q_Q(QWidget); + if (!isFocusChainConsistent()) { +#ifdef QT_DEBUG + if (rules.testFlag(FocusChainRemovalRule::AssertConsistency)) + qFatal() << q << "has inconsistent focus chain."; +#endif + qCDebug(lcFocus) << q << "wasn't removed, because of inconsistent focus chain."; + return false; + } + + if (!isInFocusChain()) { + qCDebug(lcFocus) << q << "wasn't removed, because it is not part of a focus chain."; + return false; + } + + if (rules.testFlag(FocusChainRemovalRule::EnsureFocusOut)) + q->focusNextPrevChild(direction == FocusDirection::Next); + + FOCUS_NEXT(FOCUS_PREV(q)) = FOCUS_NEXT(q); + FOCUS_PREV(FOCUS_NEXT(q)) = FOCUS_PREV(q); + initFocusChain(); + qCDebug(lcFocus) << q << "removed from focus chain."; + return true; +} + +/*! + \internal + Initialises the focus chain by making the widget point to itself. + */ +void QWidgetPrivate::initFocusChain() +{ + Q_Q(QWidget); + qCDebug(lcFocus) << "Initializing focus chain of" << q; + FOCUS_PREV(q) = q; + FOCUS_NEXT(q) = q; +} + +/*! + \internal + Reads QWidget children, which are not part of a focus chain yet. + Inserts them into the focus chain before or after the widget, + depending on \param direction and in the order of their creation. + This is used, when QWidget::setParent() causes a widget to change toplevel windows. + */ +void QWidgetPrivate::reparentFocusChildren(FocusDirection direction) +{ + Q_Q(QWidget); + QWidgetList focusChildrenInsideChain; + QDuplicateTracker<QWidget *> seen; + QWidget *widget = q->nextInFocusChain(); + while (q->isAncestorOf(widget) + && !seen.hasSeen(widget) + && widget != q->window()) { + if (widget->focusPolicy() != Qt::NoFocus) + focusChildrenInsideChain << widget; + + widget = direction == FocusDirection::Next ? widget->nextInFocusChain() + : widget->previousInFocusChain(); + } + + const QWidgetList children = q->findChildren<QWidget *>(Qt::FindDirectChildrenOnly); + QWidgetList focusChildrenOutsideChain; + for (auto *child : children) { + if (!focusChildrenInsideChain.contains(child)) + focusChildrenOutsideChain << child; + } + if (focusChildrenOutsideChain.isEmpty()) + return; + + QWidget *previous = q; + for (auto *child : focusChildrenOutsideChain) { + child->d_func()->insertIntoFocusChain(direction, previous); + previous = child; + } +} + +/*! + \internal + Inserts a widget into the focus chain before or after \param position, depending on + \param direction. + \return \c true, if the insertion has changed the focus chain, otherwise \c false. + */ +bool QWidgetPrivate::insertIntoFocusChain(FocusDirection direction, QWidget *position) +{ + Q_Q(QWidget); + Q_ASSERT(position); + QWidget *next = FOCUS_NEXT(q); + QWidget *previous = FOCUS_PREV(q); + + switch (direction) { + case FocusDirection::Next: + if (previous == position) { + qCDebug(lcFocus) << "No-op insertion." << q << "is already before" << position; + return false; + } + + removeFromFocusChain(FocusChainRemovalRule::AssertConsistency); + + FOCUS_NEXT(q) = FOCUS_NEXT(position); + FOCUS_PREV(FOCUS_NEXT(position)) = q; + FOCUS_NEXT(position) = q; + FOCUS_PREV(q) = position; + qCDebug(lcFocus) << q << "inserted after" << position; + break; + + case FocusDirection::Previous: + if (next == position) { + qCDebug(lcFocus) << "No-op insertion." << q << "is already after" << position; + return false; + } + + removeFromFocusChain(FocusChainRemovalRule::AssertConsistency); + + FOCUS_PREV(q) = FOCUS_PREV(position); + FOCUS_NEXT(FOCUS_PREV(position)) = q; + FOCUS_PREV(position) = q; + FOCUS_NEXT(q) = position; + qCDebug(lcFocus) << q << "inserted before" << position; + break; + } + + Q_ASSERT(isFocusChainConsistent()); + return true; +} + +/*! + \internal + Convenience override to insert a QWidgetList \param toBeInserted into the focus chain + before or after \param position, depending on \param direction. + \return \c true, if the insertion has changed the focus chain, otherwise \c false. + \note + \param toBeInserted must be a consistent focus chain. + */ +bool QWidgetPrivate::insertIntoFocusChain(const QWidgetList &toBeInserted, + FocusDirection direction, QWidget *position) +{ + if (toBeInserted.isEmpty()) { + qCDebug(lcFocus) << "No-op insertion of an empty list"; + return false; + } + + Q_ASSERT_X(!toBeInserted.contains(position), + Q_FUNC_INFO, + "Coding error: toBeInserted contains position"); + + QWidget *first = toBeInserted.constFirst(); + QWidget *last = toBeInserted.constLast(); + + // Call QWidget override to log accordingly + if (toBeInserted.count() == 1) + return first->d_func()->insertIntoFocusChain(direction, position); + + Q_ASSERT(first != last); + switch (direction) { + case FocusDirection::Previous: + if (FOCUS_PREV(position) == last) { + qCDebug(lcFocus) << "No-op insertion." << toBeInserted << "is already before" + << position; + return false; + } + FOCUS_NEXT(FOCUS_PREV(position)) = first; + FOCUS_PREV(first) = FOCUS_PREV(position); + FOCUS_NEXT(last) = position; + FOCUS_PREV(position) = last; + qCDebug(lcFocus) << toBeInserted << "inserted before" << position; + break; + case FocusDirection::Next: + if (FOCUS_PREV(position) == last) { + qCDebug(lcFocus) << "No-op insertion." << toBeInserted << "is already after" + << position; + return false; + } + FOCUS_PREV(FOCUS_NEXT(position)) = last; + FOCUS_NEXT(last) = FOCUS_NEXT(position); + FOCUS_PREV(first) = position; + FOCUS_NEXT(position) = first; + qCDebug(lcFocus) << toBeInserted << "inserted after" << position; + break; + } + + Q_ASSERT(position->d_func()->isFocusChainConsistent()); + return true; +} + +/*! + \internal + \return a QWidgetList, representing the part of the focus chain, + starting with \param from and ending with \param to, in \param direction. + */ +QWidgetList focusPath(QWidget *from, QWidget *to, QWidgetPrivate::FocusDirection direction) +{ + QWidgetList path({from}); + if (from == to) + return path; + + QWidget *current = from; + do { + switch (direction) { + case QWidgetPrivate::FocusDirection::Previous: + current = current->previousInFocusChain(); + break; + case QWidgetPrivate::FocusDirection::Next: + current = current->nextInFocusChain(); + break; + } + if (path.contains(current)) + return QWidgetList(); + path << current; + } while (current != to); + + return path; +} + +/*! + \internal + Removes the part from the focus chain starting with \param from and ending with \param to, + in \param direction. + \return removed part as a QWidgetList. + */ +QWidgetList QWidgetPrivate::takeFromFocusChain(QWidget *from, + QWidget *to, + FocusDirection direction) +{ + // Check if there is a path from->to in direction + const QWidgetList path = focusPath(from, to , direction); + if (path.isEmpty()) { + qCDebug(lcFocus) << "No-op removal. Focus chain from" << from << "doesn't lead to " << to; + return QWidgetList(); + } + + QWidget *first = path.constFirst(); + QWidget *last = path.constLast(); + if (first == last) { + first->d_func()->removeFromFocusChain(); + return QWidgetList({first}); + } + + FOCUS_NEXT(FOCUS_PREV(first)) = FOCUS_NEXT(last); + FOCUS_PREV(FOCUS_NEXT(last)) = FOCUS_PREV(first); + FOCUS_PREV(first) = last; + FOCUS_NEXT(last) = first; + qCDebug(lcFocus) << path << "removed from focus chain"; + return path; +} + +/*! + \internal + \return The last focus child of the widget, traversing the focus chain no further than + \param noFurtherThan. + */ +QWidget *QWidgetPrivate::determineLastFocusChild(QWidget *noFurtherThan) +{ + Q_Q(QWidget); + // Since we need to repeat the same logic for both 'first' and 'second', we add a function + // that determines the last focus child for a widget, taking proxies and compound widgets into + // account. If the target is not a compound widget (it doesn't have a focus proxy that points + // to a child), 'lastFocusChild' will be set to the target itself. + QWidget *lastFocusChild = q; + + QWidget *focusProxy = deepestFocusProxy(); + if (!focusProxy) { + // QTBUG-81097: Another case is possible here. We can have a child + // widget, that sets its focusProxy() to the parent (target). + // An example of such widget is a QLineEdit, nested into + // a QAbstractSpinBox. In this case such widget should be considered + // the last focus child. + for (auto *object : std::as_const(q->children())) { + QWidget *w = qobject_cast<QWidget *>(object); + if (w && w->focusProxy() == q) { + lastFocusChild = w; + break; + } + } + } else if (q->isAncestorOf(focusProxy)) { + lastFocusChild = focusProxy; + for (QWidget *focusNext = lastFocusChild->nextInFocusChain(); + focusNext != focusProxy && q->isAncestorOf(focusNext) + && focusNext->window() == focusProxy->window(); + focusNext = focusNext->nextInFocusChain()) { + if (focusNext == noFurtherThan) + break; + if (focusNext->focusPolicy() != Qt::NoFocus) + lastFocusChild = focusNext; + } + } + return lastFocusChild; +}; + +/*! + \internal + \return \c true, if the widget is part of a focus chain and \c false otherwise. + A widget is considered to be part of a focus chain, neither FOCUS_NEXT, nor FOCUS_PREV + are pointing to the widget itself. + + \note + This method doesn't check the consistency of the focus chain. + If multiple widgets have been removed from the focus chain by takeFromFocusChain(), + isInFocusChain() will return \c true for all of those widgets, even if they represent + an inconsistent focus chain. + */ +bool QWidgetPrivate::isInFocusChain() const +{ + Q_Q(const QWidget); + return !(FOCUS_NEXT(q) == q && FOCUS_PREV(q) == q); +} + +/*! + \internal + A focus chain is consistent, when it is circular: Following the chain in either direction + has to return to the beginning. This is why a newly constructed widget points to itself, + when the focus chain has been initialized. A newly constructed widget is considered to have + a consistent focus chain, while not being part of a focus chain. + + This method returns \c true early, if a widget is pointing to itself. + It returns \c false, if one of the following is detected: + \list + \li nullptr found in a previous/next pointer. + \li broken chain: widget A is B's previous, but B isn't A's next. + \li chain isn't closed: starting at A doesn't lead back to A. + \endlist + It return \c true, if none of the above is observed. + + \note + The focus chain is checked only in forward direction. + This is sufficient, because the check for a broken chain asserts consistent paths + in both directions. + */ +bool QWidgetPrivate::isFocusChainConsistent() const +{ + Q_Q(const QWidget); + if (!isInFocusChain()) + return true; + + const QWidget *position = q; + + for (int i = 0; i < QApplication::allWidgets().count(); ++i) { + if (!FOCUS_PREV(position) || !FOCUS_NEXT(position)) { + qCDebug(lcFocus) << "Nullptr found at:" << position + << "Previous pointing to" << FOCUS_PREV(position) + << "Next pointing to" << FOCUS_NEXT(position); + return false; + } + if (!(FOCUS_PREV(FOCUS_NEXT(position)) == position + && FOCUS_NEXT(FOCUS_PREV(position)) == position)) { + qCDebug(lcFocus) << "Inconsistent focus chain at:" << position + << "Previous pointing to" << FOCUS_PREV(FOCUS_NEXT(position)) + << "Next pointing to" << FOCUS_NEXT(FOCUS_PREV(position)); + return false; + } + position = FOCUS_NEXT(position); + if (position == q) + return true; + + } + + qCDebug(lcFocus) << "Focus chain leading from" << q << "to" << position << "is not closed."; + return false; +} + +#undef FOCUS_NEXT +#undef FOCUS_PREV + + QT_END_NAMESPACE #include "moc_qwidget.cpp" diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index d16d0f438c..9fab9efa62 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -41,6 +41,7 @@ #include <private/qgesture_p.h> #include <qpa/qplatformbackingstore.h> #include <QtGui/private/qbackingstorerhisupport_p.h> +#include <private/qapplication_p.h> #include <QtCore/qpointer.h> @@ -733,6 +734,40 @@ public: uint childrenHiddenByWState : 1; uint childrenShownByExpose : 1; + // *************************** Focus abstraction ************************************ + enum class FocusDirection { + Previous, + Next, + }; + + enum class FocusChainRemovalRule { + EnsureFocusOut = 0x01, + AssertConsistency = 0x02, + }; + Q_DECLARE_FLAGS(FocusChainRemovalRules, FocusChainRemovalRule) + + // Getters + QWidget *nextPrevElementInFocusChain(FocusDirection direction) const; + + // manipulators + bool removeFromFocusChain(FocusChainRemovalRules rules = FocusChainRemovalRules(), + FocusDirection direction = FocusDirection::Next); + bool insertIntoFocusChain(FocusDirection direction, QWidget *position); + static bool insertIntoFocusChain(const QWidgetList &toBeInserted, FocusDirection direction, QWidget *position); + bool insertIntoFocusChainBefore(QWidget *position) + { return insertIntoFocusChain(FocusDirection::Previous, position); } + bool insertIntoFocusChainAfter(QWidget *position) + { return insertIntoFocusChain(FocusDirection::Next, position); } + static QWidgetList takeFromFocusChain(QWidget *from, QWidget *to, + FocusDirection direction = FocusDirection::Next); + void reparentFocusChildren(FocusDirection direction); + QWidget *determineLastFocusChild(QWidget *noFurtherThan); + + // Initialization and tests + void initFocusChain(); + bool isInFocusChain() const; + bool isFocusChainConsistent() const; + // *************************** Platform specific ************************************ #if defined(Q_OS_WIN) uint noPaintOnScreen : 1; // see qwidget.cpp ::paintEngine() |