Refactor and fix QMainWindow::tabifiedDockWidgets()
The method traversed QDockAreaLayoutInfo::item_list, to identify dock widgets tabbed with the QDockWidget argument in a tab bar It relied on bool QDockAreLayoutInfo::tabbed, which is set to true, when a QMainWindowTabBar is to be added to a QDockAreaLayoutInfo. This flag isn't cleared, when the second last dock widget is removed from the tab bar. It can't be replaced by QMainWindowLayout::isDockWidgetTabbed, because the flag also represents intermediate states, where e.g. a dock widget is hovered over, prepares to become a floating tab and then rolls back, because hovering doesn't result in a drop. In that case, tabbed must become true, which the dock widget isn't actually tabbed. Furthermore, the way to traverse item_list didn't find dock widgets in a floating tab. In that case, tabifiedDockWidgets() wrongly returned an empty list. To fix both issues, refactor QMainWindow::tabifiedDockWidgets() to read the list of dock widgets directly from the QMainWindowTabBar. Add tests in tst_QDockWidget::floatingTabs() and updateTabBarOnVisibilityChanged() Fixes: QTBUG-122001 Pick-to: 6.5 Change-Id: Ia9eb3711be642101261f34ee447521cc6accc20c Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit cd2a3e970aaeb8f5f92d9c6e52ede7a82f953150) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 5e89966da1a2107324171a222f27e7c02340a449)
This commit is contained in:
parent
e5b3c0bb1d
commit
b8ed5def06
@ -1123,21 +1123,8 @@ void QMainWindow::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
|
|||||||
|
|
||||||
QList<QDockWidget*> QMainWindow::tabifiedDockWidgets(QDockWidget *dockwidget) const
|
QList<QDockWidget*> QMainWindow::tabifiedDockWidgets(QDockWidget *dockwidget) const
|
||||||
{
|
{
|
||||||
QList<QDockWidget*> ret;
|
Q_D(const QMainWindow);
|
||||||
const QDockAreaLayoutInfo *info = d_func()->layout->layoutState.dockAreaLayout.info(dockwidget);
|
return d->layout ? d->layout->tabifiedDockWidgets(dockwidget) : QList<QDockWidget *>();
|
||||||
if (info && info->tabbed && info->tabBar) {
|
|
||||||
for(int i = 0; i < info->item_list.size(); ++i) {
|
|
||||||
const QDockAreaLayoutItem &item = info->item_list.at(i);
|
|
||||||
if (item.widgetItem) {
|
|
||||||
if (QDockWidget *dock = qobject_cast<QDockWidget*>(item.widgetItem->widget())) {
|
|
||||||
if (dock != dockwidget) {
|
|
||||||
ret += dock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#endif // QT_CONFIG(tabbar)
|
#endif // QT_CONFIG(tabbar)
|
||||||
|
|
||||||
|
@ -1885,6 +1885,7 @@ public:
|
|||||||
~QMainWindowTabBar();
|
~QMainWindowTabBar();
|
||||||
QDockWidget *dockAt(int index) const;
|
QDockWidget *dockAt(int index) const;
|
||||||
QList<QDockWidget *> dockWidgets() const;
|
QList<QDockWidget *> dockWidgets() const;
|
||||||
|
bool contains(const QDockWidget *dockWidget) const;
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent *e) override;
|
bool event(QEvent *e) override;
|
||||||
void mouseReleaseEvent(QMouseEvent*) override;
|
void mouseReleaseEvent(QMouseEvent*) override;
|
||||||
@ -1892,6 +1893,17 @@ protected:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QMainWindowTabBar *QMainWindowLayout::findTabBar(const QDockWidget *dockWidget) const
|
||||||
|
{
|
||||||
|
for (auto *bar : usedTabBars) {
|
||||||
|
Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
|
||||||
|
auto *tabBar = static_cast<QMainWindowTabBar *>(bar);
|
||||||
|
if (tabBar->contains(dockWidget))
|
||||||
|
return tabBar;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
|
QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
|
||||||
: QTabBar(parent), mainWindow(parent)
|
: QTabBar(parent), mainWindow(parent)
|
||||||
{
|
{
|
||||||
@ -1908,6 +1920,15 @@ QList<QDockWidget *> QMainWindowTabBar::dockWidgets() const
|
|||||||
return docks;
|
return docks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QMainWindowTabBar::contains(const QDockWidget *dockWidget) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count(); ++i) {
|
||||||
|
if (dockAt(i) == dockWidget)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QDockWidget *QMainWindowTabBar::dockAt(int index) const
|
QDockWidget *QMainWindowTabBar::dockAt(int index) const
|
||||||
{
|
{
|
||||||
QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this);
|
QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this);
|
||||||
@ -2011,21 +2032,26 @@ bool QMainWindowTabBar::event(QEvent *e)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(const QDockWidget *dockWidget) const
|
||||||
|
{
|
||||||
|
const auto *bar = findTabBar(dockWidget);
|
||||||
|
if (!bar)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QList<QDockWidget *> buddies = bar->dockWidgets();
|
||||||
|
// Return only other dock widgets associated with dockWidget in a tab bar.
|
||||||
|
// If dockWidget is alone in a tab bar, return an empty list.
|
||||||
|
buddies.removeOne(dockWidget);
|
||||||
|
return buddies;
|
||||||
|
}
|
||||||
|
|
||||||
bool QMainWindowLayout::isDockWidgetTabbed(const QDockWidget *dockWidget) const
|
bool QMainWindowLayout::isDockWidgetTabbed(const QDockWidget *dockWidget) const
|
||||||
{
|
{
|
||||||
for (auto *bar : std::as_const(usedTabBars)) {
|
// A single dock widget in a tab bar is not considered to be tabbed.
|
||||||
// A single dock widget in a tab bar is not considered to be tabbed.
|
// This is to make sure, we don't drag an empty QDockWidgetGroupWindow around.
|
||||||
// This is to make sure, we don't drag an empty QDockWidgetGroupWindow around.
|
// => only consider tab bars with two or more tabs.
|
||||||
// => only consider tab bars with two or more tabs.
|
const auto *bar = findTabBar(dockWidget);
|
||||||
if (bar->count() <= 1)
|
return bar && bar->count() > 1;
|
||||||
continue;
|
|
||||||
auto *tabBar = qobject_cast<QMainWindowTabBar *>(bar);
|
|
||||||
Q_ASSERT(tabBar);
|
|
||||||
const auto dockWidgets = tabBar->dockWidgets();
|
|
||||||
if (std::find(dockWidgets.begin(), dockWidgets.end(), dockWidget) != dockWidgets.end())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTabBar *QMainWindowLayout::getTabBar()
|
QTabBar *QMainWindowLayout::getTabBar()
|
||||||
|
@ -448,6 +448,7 @@ public:
|
|||||||
bool restoreState(QDataStream &stream, const QMainWindowLayoutState &oldState);
|
bool restoreState(QDataStream &stream, const QMainWindowLayoutState &oldState);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class QMainWindowTabBar;
|
||||||
class Q_AUTOTEST_EXPORT QMainWindowLayout
|
class Q_AUTOTEST_EXPORT QMainWindowLayout
|
||||||
: public QLayout,
|
: public QLayout,
|
||||||
public QMainWindowLayoutSeparatorHelper<QMainWindowLayout>
|
public QMainWindowLayoutSeparatorHelper<QMainWindowLayout>
|
||||||
@ -575,7 +576,11 @@ public:
|
|||||||
#if QT_CONFIG(dockwidget)
|
#if QT_CONFIG(dockwidget)
|
||||||
QPointer<QDockWidgetGroupWindow> currentHoveredFloat; // set when dragging over a floating dock widget
|
QPointer<QDockWidgetGroupWindow> currentHoveredFloat; // set when dragging over a floating dock widget
|
||||||
void setCurrentHoveredFloat(QDockWidgetGroupWindow *w);
|
void setCurrentHoveredFloat(QDockWidgetGroupWindow *w);
|
||||||
|
#if QT_CONFIG(tabbar)
|
||||||
bool isDockWidgetTabbed(const QDockWidget *dockWidget) const;
|
bool isDockWidgetTabbed(const QDockWidget *dockWidget) const;
|
||||||
|
QList<QDockWidget *> tabifiedDockWidgets(const QDockWidget *dockWidget) const;
|
||||||
|
QMainWindowTabBar *findTabBar(const QDockWidget *dockWidget) const;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
bool isInApplyState = false;
|
bool isInApplyState = false;
|
||||||
|
|
||||||
|
@ -698,6 +698,9 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged()
|
|||||||
mw.tabifyDockWidget(dw1, dw2);
|
mw.tabifyDockWidget(dw1, dw2);
|
||||||
mw.tabifyDockWidget(dw2, dw3);
|
mw.tabifyDockWidget(dw2, dw3);
|
||||||
|
|
||||||
|
const auto list1 = QList<QDockWidget *>{dw1, dw2, dw3};
|
||||||
|
QCOMPARE(mw.tabifiedDockWidgets(dw0), list1);
|
||||||
|
|
||||||
QTabBar *tabBar = mw.findChild<QTabBar *>();
|
QTabBar *tabBar = mw.findChild<QTabBar *>();
|
||||||
QVERIFY(tabBar);
|
QVERIFY(tabBar);
|
||||||
tabBar->setCurrentIndex(2);
|
tabBar->setCurrentIndex(2);
|
||||||
@ -711,6 +714,8 @@ void tst_QDockWidget::updateTabBarOnVisibilityChanged()
|
|||||||
dw1->hide();
|
dw1->hide();
|
||||||
QTRY_COMPARE(tabBar->count(), 2);
|
QTRY_COMPARE(tabBar->count(), 2);
|
||||||
QCOMPARE(tabBar->currentIndex(), 0);
|
QCOMPARE(tabBar->currentIndex(), 0);
|
||||||
|
|
||||||
|
QCOMPARE(mw.tabifiedDockWidgets(dw2), {dw3});
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Qt::DockWidgetArea)
|
Q_DECLARE_METATYPE(Qt::DockWidgetArea)
|
||||||
@ -1438,6 +1443,9 @@ void tst_QDockWidget::floatingTabs()
|
|||||||
createFloatingTabs(mainWindow, cent, d1, d2, path1, path2);
|
createFloatingTabs(mainWindow, cent, d1, d2, path1, path2);
|
||||||
std::unique_ptr<QMainWindow> up_mainWindow(mainWindow);
|
std::unique_ptr<QMainWindow> up_mainWindow(mainWindow);
|
||||||
|
|
||||||
|
QCOMPARE(mainWindow->tabifiedDockWidgets(d1), {d2});
|
||||||
|
QCOMPARE(mainWindow->tabifiedDockWidgets(d2), {d1});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* unplug both dockwidgets, resize them and plug them into a joint floating tab
|
* unplug both dockwidgets, resize them and plug them into a joint floating tab
|
||||||
* expected behavior: QDOckWidgetGroupWindow with both widgets is created
|
* expected behavior: QDOckWidgetGroupWindow with both widgets is created
|
||||||
@ -1515,6 +1523,9 @@ void tst_QDockWidget::floatingTabs()
|
|||||||
// Paths must be identical
|
// Paths must be identical
|
||||||
QTRY_COMPARE(layout->layoutState.indexOf(d1), path1);
|
QTRY_COMPARE(layout->layoutState.indexOf(d1), path1);
|
||||||
QTRY_COMPARE(layout->layoutState.indexOf(d2), path2);
|
QTRY_COMPARE(layout->layoutState.indexOf(d2), path2);
|
||||||
|
|
||||||
|
QCOMPARE(mainWindow->tabifiedDockWidgets(d1), {});
|
||||||
|
QCOMPARE(mainWindow->tabifiedDockWidgets(d2), {});
|
||||||
#else
|
#else
|
||||||
QSKIP("test requires -developer-build option");
|
QSKIP("test requires -developer-build option");
|
||||||
#endif // QT_BUILD_INTERNAL
|
#endif // QT_BUILD_INTERNAL
|
||||||
|
Loading…
x
Reference in New Issue
Block a user