From 9f02de820063284d65510ec1f12b8acaae683148 Mon Sep 17 00:00:00 2001 From: Senthil Kandaswamy Date: Mon, 6 Nov 2023 15:32:20 -0500 Subject: [PATCH] MAYA-131102: Fixing Qt issues related to docking Change-Id: I769f5381c87c1cfed89c1b3cff9f35313c849dc9 --- src/widgets/widgets/qmainwindowlayout.cpp | 99 ++++++++--------------- src/widgets/widgets/qmainwindowlayout_p.h | 2 + 2 files changed, 34 insertions(+), 67 deletions(-) diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 5571b9e51cd..bf6193d3395 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #ifndef QT_NO_DEBUG_STREAM # include @@ -264,6 +266,20 @@ bool QDockWidgetGroupWindow::event(QEvent *e) if (QDockWidget *dw = activeTabbedDockWidget()) { dw->close(); adjustFlags(); + // when all child QDockWidgets' are closed, this QDockWidgetGroupWindow will be hidden + // after receiving the `LayoutRequest` event. This causes subsequent call to show + // on the current QDockWidget to fail. Hence, adding a connection to the + // QDockWidget's toggle action to re-show this QDockWidgetGroupWindow along with the + // current QDockWidget. + m_widgetConnections[dw] = connect(dw->toggleViewAction(), &QAction::toggled, [this, dw]() { + // show this QDockWidgetGroupWindow before showing the child QDockWidget. + show(); + dw->show(); + // once at least one child becomes visible, clear all listeners since we no longer need them.. + for (const auto& pair : m_widgetConnections) + disconnect(pair.second); + m_widgetConnections.clear(); + }); } #endif return true; @@ -288,6 +304,10 @@ bool QDockWidgetGroupWindow::event(QEvent *e) if (qobject_cast(static_cast(e)->child())) adjustFlags(); break; + case QEvent::ChildRemoved: + if (auto widget = qobject_cast(static_cast(e)->child())) + m_widgetConnections.erase(widget); + break; case QEvent::LayoutRequest: // We might need to show the widget again destroyOrHideIfEmpty(); @@ -2577,70 +2597,7 @@ QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, bool group) // unplug the widget first dockWidget->d_func()->unplug(widget->geometry()); - - // Create a floating tab, copy properties and generate layout info - QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow(); - const QInternal::DockPosition dockPos = groupWindow->layoutInfo()->dockPos; - QDockAreaLayoutInfo *info = floatingTabs->layoutInfo(); - - const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dockWidget); - - // Populate newly created DockAreaLayoutInfo of floating tabs - *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPos, - Qt::Horizontal, shape, - layoutState.mainWindow); - - // Create tab and hide it as group window contains only one widget - info->tabbed = true; - info->tabBar = getTabBar(); - info->tabBar->hide(); - updateGapIndicator(); - - // Reparent it to a QDockWidgetGroupLayout - floatingTabs->setGeometry(dockWidget->geometry()); - - // Append reference to floatingTabs to the dock's item_list - parentItem.widgetItem = new QDockWidgetGroupWindowItem(floatingTabs); - layoutState.dockAreaLayout.docks[dockPos].item_list.append(parentItem); - - // use populated parentItem to set reference to dockWidget as the first item in own list - parentItem.widgetItem = new QDockWidgetItem(dockWidget); - info->item_list = {parentItem}; - - // Add non-gap items of the dock to the tab bar - for (const auto &listItem : layoutState.dockAreaLayout.docks[dockPos].item_list) { - if (listItem.GapItem || !listItem.widgetItem) - continue; - info->tabBar->addTab(listItem.widgetItem->widget()->objectName()); - } - - // Re-parent and fit - floatingTabs->setParent(layoutState.mainWindow); - floatingTabs->layoutInfo()->fitItems(); - floatingTabs->layoutInfo()->apply(dockOptions & QMainWindow::AnimatedDocks); - groupWindow->layoutInfo()->fitItems(); - groupWindow->layoutInfo()->apply(dockOptions & QMainWindow::AnimatedDocks); - dockWidget->d_func()->tabPosition = layoutState.mainWindow->tabPosition(toDockWidgetArea(dockPos)); - info->reparentWidgets(floatingTabs); - dockWidget->setParent(floatingTabs); - info->updateTabBar(); - - // Show the new item - const QList path = layoutState.indexOf(floatingTabs); - QRect r = layoutState.itemRect(path); - savedState = layoutState; - savedState.fitLayout(); - - // Update gap, fix orientation, raise and show - currentGapPos = path; - currentGapRect = r; - updateGapIndicator(); - fixToolBarOrientation(parentItem.widgetItem, currentGapPos.at(1)); - floatingTabs->show(); - floatingTabs->raise(); - - qCDebug(lcQpaDockWidgets) << "Unplugged from floating dock:" << widget << "from" << parentItem.widgetItem; - return parentItem.widgetItem; + return item; } } #endif @@ -2837,10 +2794,18 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget, info->tabBar = getTabBar(); info->tabbed = true; QLayout *parentLayout = dropTo->parentWidget()->layout(); - info->item_list.append( - QDockAreaLayoutItem(parentLayout->takeAt(parentLayout->indexOf(dropTo)))); - + auto parentItem = QDockAreaLayoutItem(parentLayout->takeAt(parentLayout->indexOf(dropTo))); + if (!parentItem.widgetItem) + parentItem.widgetItem = new QDockWidgetItem(dropTo); + info->item_list.append(parentItem); + + auto oldGroupWindow = qobject_cast(dropTo->parent()); dropTo->setParent(floatingTabs); + // just an early cleanup to if there are no other children. + if (oldGroupWindow) { + oldGroupWindow->destroyOrHideIfEmpty(); + } + qCDebug(lcQpaDockWidgets) << "Wrapping" << widget << "into floating tabs" << floatingTabs; w = floatingTabs; } diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h index 4719210e30c..849a349d405 100644 --- a/src/widgets/widgets/qmainwindowlayout_p.h +++ b/src/widgets/widgets/qmainwindowlayout_p.h @@ -38,6 +38,7 @@ #include "qtoolbararealayout_p.h" #endif #include +#include QT_REQUIRE_CONFIG(mainwindow); @@ -335,6 +336,7 @@ class Q_AUTOTEST_EXPORT QDockWidgetGroupWindow : public QWidget private: QSize m_removedFrameSize; + std::unordered_map m_widgetConnections; }; // This item will be used in the layout for the gap item. We cannot use QWidgetItem directly