nested mdi: Get rid of unneeded drop area mdi wrapper when floating

When floating, the FloatingWindow has its own DropArea for nesting.
We delete the redundant level of wrappers when floating.
This commit is contained in:
Sergio Martins
2022-01-14 17:55:43 +00:00
parent 95c12dbd4c
commit 18457d80aa
6 changed files with 77 additions and 8 deletions

View File

@@ -551,10 +551,17 @@ MDILayoutWidget *DockWidgetBase::Private::mdiLayout() const
bool DockWidgetBase::Private::isMDIWrapper() const
{
if (auto dropAreaGuest = qobject_cast<DropArea *>(q->widget()))
return dropAreaGuest->isMDIWrapper();
return mdiDropAreaWrapper() != nullptr;
}
return false;
DropArea *DockWidgetBase::Private::mdiDropAreaWrapper() const
{
if (auto dropAreaGuest = qobject_cast<DropArea *>(q->widget())) {
if (dropAreaGuest->isMDIWrapper())
return dropAreaGuest;
}
return nullptr;
}
DockWidgetBase::Private *DockWidgetBase::dptr() const

View File

@@ -140,6 +140,9 @@ public:
/// This is only used by the DockWidget::Option_MDINestable feature
bool isMDIWrapper() const;
/// @brief If this dock widget is an MDI wrapper (isMDIWrapper()), then returns the wrapper drop area
DropArea *mdiDropAreaWrapper() const;
const QString name;
QStringList affinities;
QString title;

View File

@@ -22,6 +22,7 @@
#include "FrameworkWidgetFactory.h"
#include "DragController_p.h"
#include "LayoutSaver_p.h"
#include "DockWidgetBase_p.h"
#include <QCloseEvent>
#include <QScopedValueRollback>
@@ -146,10 +147,26 @@ FloatingWindow::FloatingWindow(Frame *frame, QRect suggestedGeometry, MainWindow
{
QScopedValueRollback<bool> guard(m_disableSetVisible, true);
// Adding a widget will trigger onFrameCountChanged, which triggers a setVisible(true).
// The problem with setVisible(true) will forget about or requested geometry and place the window at 0,0
// So disable the setVisible(true) call while in the ctor.
m_dropArea->addWidget(frame, KDDockWidgets::Location_OnTop, {});
if (frame->hasNestedMDIDockWidgets()) {
// When using DockWidget::MDINestable, the docked MDI widget is wrapped by a drop area so we can drop things into it.
// When floating it, we can delete that helper drop area, as FloatingWindow already has one
if (frame->dockWidgetCount() == 0) {
// doesn't happen
qWarning() << Q_FUNC_INFO << "Unexpected empty frame";
return;
}
auto dwMDIWrapper = frame->dockWidgetAt(0);
auto dropAreaMDIWrapper = dwMDIWrapper->d->mdiDropAreaWrapper();
m_dropArea->addMultiSplitter(dropAreaMDIWrapper, Location_OnTop);
delete dwMDIWrapper;
} else {
// Adding a widget will trigger onFrameCountChanged, which triggers a setVisible(true).
// The problem with setVisible(true) will forget about or requested geometry and place the window at 0,0
// So disable the setVisible(true) call while in the ctor.
m_dropArea->addWidget(frame, KDDockWidgets::Location_OnTop, {});
}
}
FloatingWindow::~FloatingWindow()

View File

@@ -889,6 +889,19 @@ MDILayoutWidget *Frame::mdiLayoutWidget() const
return qobject_cast<MDILayoutWidget *>(m_layoutWidget);
}
bool Frame::hasNestedMDIDockWidgets() const
{
if (!isMDI() || dockWidgetCount() == 0)
return false;
if (dockWidgetCount() != 1) {
qWarning() << Q_FUNC_INFO << "Expected a single dock widget wrapper as frame child";
return false;
}
return dockWidgetAt(0)->d->isMDIWrapper();
}
int Frame::userType() const
{
return m_userType;

View File

@@ -302,6 +302,10 @@ public:
/// @brief Returns the MDI layout. Or nullptr if this frame isn't in a MDI layout
MDILayoutWidget *mdiLayoutWidget() const;
/// @brief If this frame is a MDI frame (isMDI() == true), returns whether it contains nested dock widgets (DockWidget::Option_MDINestable)
/// @sa isMDI()
bool hasNestedMDIDockWidgets() const;
/// @brief See DockWidgetBase::userType()
int userType() const;

View File

@@ -5153,7 +5153,32 @@ void TestDocks::tst_mdi_mixed_with_docking2()
QVERIFY(!mdiWidget3->isOpen());
QVERIFY(dropArea1.isNull());
// QTest::qWait(10000);
// Reopen everything again:
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
frame1 = mdiWidget1->d->frame();
mdiFrame1 = frame1->mdiFrame();
dropArea1 = frame1->mdiDropAreaWrapper();
dropArea1->addDockWidget(mdiWidget3, Location_OnLeft, nullptr);
// Test floating:
frame2 = mdiWidget2->d->frame();
QPointer<DockWidgetBase> dwWrapper2 = frame2->mdiDockWidgetWrapper();
dropArea2 = frame2->mdiDropAreaWrapper();
QVERIFY(mdiWidget2->isVisible());
QVERIFY(frame2->isMDIWrapper());
QVERIFY(dwWrapper2->d->isMDIWrapper());
mdiWidget2->setFloating(true);
QVERIFY(mdiWidget2->isFloating());
QVERIFY(!mdiWidget2->d->frame()->isMDI());
QVERIFY(!mdiWidget2->d->frame()->isMDIWrapper());
QTest::qWait(500); // remove
QVERIFY(dropArea2.isNull());
QVERIFY(dwWrapper2.isNull());
// QTest::qWait(100000);
}
// No need to port to QtQuick