Make DockWidgetBase::setMDIPosition|setMDISize support nesting
They now honour Option_MDINestable. Before they would bail out assuming they weren't in a MDI area. Now they look further up the hierarchy to find our MDIArea, if any.
This commit is contained in:
@@ -543,8 +543,30 @@ void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
|
||||
|
||||
MDILayoutWidget *DockWidgetBase::Private::mdiLayout() const
|
||||
{
|
||||
if (auto mw = mainWindow())
|
||||
return mw->mdiLayoutWidget();
|
||||
auto p = const_cast<QObject *>(q->parent());
|
||||
while (p) {
|
||||
if (qobject_cast<const QWindow*>(p)) {
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto layout = qobject_cast<LayoutWidget*>(p)) {
|
||||
// We found a layout
|
||||
if (auto mdiLayout = qobject_cast<MDILayoutWidget*>(p)) {
|
||||
// And it's MDI
|
||||
return mdiLayout;
|
||||
} else if (auto dropArea = qobject_cast<DropArea*>(p)) {
|
||||
// It's a DropArea. But maybe it's a drop area that's just helping
|
||||
// making the MDI windows accept drops (Option_MDINestable)
|
||||
if (!dropArea->isMDIWrapper())
|
||||
return nullptr;
|
||||
|
||||
// It's a MDI wrapper, keep looking up.
|
||||
}
|
||||
}
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -564,6 +586,36 @@ DropArea *DockWidgetBase::Private::mdiDropAreaWrapper() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DockWidgetBase *DockWidgetBase::Private::mdiDockWidgetWrapper() const
|
||||
{
|
||||
if (isMDIWrapper()) {
|
||||
// We are the wrapper
|
||||
return q;
|
||||
}
|
||||
|
||||
auto p = const_cast<QObject *>(q->parent());
|
||||
while (p) {
|
||||
if (qobject_cast<const QWindow*>(p)) {
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto layout = qobject_cast<LayoutWidget*>(p)) {
|
||||
if (auto dropArea = qobject_cast<DropArea*>(p)) {
|
||||
if (dropArea->isMDIWrapper())
|
||||
return dropArea->mdiDockWidgetWrapper();
|
||||
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DockWidgetBase::Private *DockWidgetBase::dptr() const
|
||||
{
|
||||
return d;
|
||||
@@ -852,14 +904,26 @@ int DockWidgetBase::userType() const
|
||||
|
||||
void DockWidgetBase::setMDIPosition(QPoint pos)
|
||||
{
|
||||
if (MDILayoutWidget *layout = d->mdiLayout())
|
||||
layout->moveDockWidget(this, pos);
|
||||
if (MDILayoutWidget *layout = d->mdiLayout()) {
|
||||
if (auto wrapperDW = d->mdiDockWidgetWrapper()) {
|
||||
// Case of using Option_MDINestable. We need to layout the actual top level DW
|
||||
layout->moveDockWidget(wrapperDW, pos);
|
||||
} else {
|
||||
layout->moveDockWidget(this, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::setMDISize(QSize size)
|
||||
{
|
||||
if (MDILayoutWidget *layout = d->mdiLayout())
|
||||
layout->resizeDockWidget(this, size);
|
||||
if (MDILayoutWidget *layout = d->mdiLayout()) {
|
||||
if (auto wrapperDW = d->mdiDockWidgetWrapper()) {
|
||||
// Case of using Option_MDINestable. We need to layout the actual top level DW
|
||||
layout->resizeDockWidget(wrapperDW, size);
|
||||
} else {
|
||||
layout->resizeDockWidget(this, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::setMDIZ(int z)
|
||||
|
||||
@@ -143,6 +143,10 @@ public:
|
||||
/// @brief If this dock widget is an MDI wrapper (isMDIWrapper()), then returns the wrapper drop area
|
||||
DropArea *mdiDropAreaWrapper() const;
|
||||
|
||||
/// @brief If this dock widget is inside a drop area nested in MDI then returns the wrapper dock widget
|
||||
/// This goes up the hierarchy, while mdiDropAreaWrapper goes down.
|
||||
DockWidgetBase *mdiDockWidgetWrapper() const;
|
||||
|
||||
const QString name;
|
||||
QStringList affinities;
|
||||
QString title;
|
||||
|
||||
@@ -74,6 +74,9 @@ public:
|
||||
/// When DockWidget::Option_MDINestable is used, docked MDI dock widgets will be wrapped inside a DropArea, so they accept drops
|
||||
/// This DropArea is created implicitly while docking, and this function will return true
|
||||
bool isMDIWrapper() const;
|
||||
|
||||
/// Returns the helper dock widget for implementing DockWidget::Option_MDINestable.
|
||||
DockWidgetBase *mdiDockWidgetWrapper() const;
|
||||
private:
|
||||
Q_DISABLE_COPY(DropArea)
|
||||
friend class Frame;
|
||||
@@ -88,7 +91,6 @@ private:
|
||||
bool drop(QWidgetOrQuick *droppedwindow, KDDockWidgets::Location location, Frame *relativeTo);
|
||||
Frame *frameContainingPos(QPoint globalPos) const;
|
||||
void updateFloatingActions();
|
||||
DockWidgetBase *mdiDockWidgetWrapper() const;
|
||||
|
||||
bool m_inDestructor = false;
|
||||
const bool m_isMDIWrapper;
|
||||
|
||||
@@ -107,7 +107,8 @@ void MDILayoutWidget::resizeDockWidget(Frame *frame, QSize size)
|
||||
|
||||
Layouting::Item *item = itemForFrame(frame);
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "Frame not found in the layout" << frame;
|
||||
qWarning() << Q_FUNC_INFO << "Frame not found in the layout" << frame << frame->isMDI()
|
||||
<< frame->isMDIWrapper();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5213,6 +5213,42 @@ void TestDocks::tst_mdi_mixed_with_docking2()
|
||||
mdiTitleBar->onFloatClicked();
|
||||
}
|
||||
|
||||
void TestDocks::tst_mdi_mixed_with_docking_setMDISize()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
||||
|
||||
m->addDockWidget(dock1, Location_OnBottom);
|
||||
|
||||
auto mdiArea = new MDIArea();
|
||||
m->setPersistentCentralWidget(mdiArea);
|
||||
|
||||
auto createSheet = [](int id) -> DockWidgetBase* {
|
||||
auto dock = new DockWidget(QStringLiteral("dw-sheet-%1").arg(id), DockWidgetBase::Option_MDINestable);
|
||||
dock->setWidget(new QPushButton(QStringLiteral("Sheet %1").arg(id)));
|
||||
dock->setTitle(QStringLiteral("Sheet %1").arg(id));
|
||||
|
||||
return dock;
|
||||
};
|
||||
|
||||
auto mdiWidget1 = createSheet(1);
|
||||
auto mdiWidget2 = createSheet(2);
|
||||
|
||||
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
||||
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
||||
|
||||
Frame *frame1 = mdiArea->frames().at(0);
|
||||
|
||||
const QSize sz1 = frame1->QWidgetAdapter::size();
|
||||
const QSize increment(200, 200);
|
||||
|
||||
QVERIFY(mdiWidget1->d->mdiLayout());
|
||||
mdiWidget1->setMDISize(sz1 + increment);
|
||||
|
||||
QCOMPARE(frame1->QWidgetAdapter::size(), sz1 + increment);
|
||||
}
|
||||
|
||||
// No need to port to QtQuick
|
||||
void TestDocks::tst_floatingWindowDeleted()
|
||||
{
|
||||
|
||||
@@ -252,6 +252,7 @@ private Q_SLOTS:
|
||||
void tst_mainWindowAlwaysHasCentralWidget();
|
||||
void tst_dockableMainWindows();
|
||||
void tst_mdi_mixed_with_docking2();
|
||||
void tst_mdi_mixed_with_docking_setMDISize();
|
||||
|
||||
// But these are fine to be widget only:
|
||||
void tst_tabsNotClickable();
|
||||
|
||||
Reference in New Issue
Block a user