diff --git a/src/multisplitter/Anchor.cpp b/src/multisplitter/Anchor.cpp index cca98daa..7058d744 100644 --- a/src/multisplitter/Anchor.cpp +++ b/src/multisplitter/Anchor.cpp @@ -281,6 +281,22 @@ int Anchor::smallestAvailableItemSqueeze(Anchor::Side side) const return smallest; } +void Anchor::ensureBounded() +{ + if (!isStatic()) { + const QPair bounds = m_layout->boundPositionsForAnchor(this); + if (position() < bounds.first) { + setPosition(bounds.first); + } else if (position() > bounds.second) { + setPosition(bounds.second); + } + } + + for (Item *item : items(Side2)) { + item->anchorAtSide(Side2, orientation())->ensureBounded(); + } +} + int Anchor::length() const { Q_ASSERT(m_to); diff --git a/src/multisplitter/Anchor_p.h b/src/multisplitter/Anchor_p.h index d3a3ea75..08c59487 100644 --- a/src/multisplitter/Anchor_p.h +++ b/src/multisplitter/Anchor_p.h @@ -143,6 +143,8 @@ public: void setVisible(bool); qreal positionPercentage() const { return m_positionPercentage; } + void ensureBounded(); + /** * @brief Sets the new layout. Called when we're dropping a source layout into a target one. * The target one will steal the separators of the source one. diff --git a/src/multisplitter/MultiSplitterLayout.cpp b/src/multisplitter/MultiSplitterLayout.cpp index a9575f81..100436b7 100644 --- a/src/multisplitter/MultiSplitterLayout.cpp +++ b/src/multisplitter/MultiSplitterLayout.cpp @@ -422,6 +422,13 @@ void MultiSplitterLayout::ensureEnoughContentsSize(const QWidgetOrQuick *widget, } } +void MultiSplitterLayout::ensureAnchorsBounded() +{ + // Recursive, goes all the way to right/bottom + m_leftAnchor->ensureBounded(); + m_topAnchor->ensureBounded(); +} + static Anchor::List removeSmallestPath(QVector &paths) { // Removes and returns the smallest list @@ -1576,6 +1583,7 @@ void MultiSplitterLayout::restorePlaceholder(Item *item) } item->endBlockPropagateGeo(); + ensureAnchorsBounded(); updateAnchorFollowing(); } diff --git a/src/multisplitter/MultiSplitterLayout_p.h b/src/multisplitter/MultiSplitterLayout_p.h index e1daca33..252e0687 100644 --- a/src/multisplitter/MultiSplitterLayout_p.h +++ b/src/multisplitter/MultiSplitterLayout_p.h @@ -473,6 +473,8 @@ private: const Item *relativeToItem); + void ensureAnchorsBounded(); + void insertAnchor(Anchor *); void removeAnchor(Anchor *); diff --git a/tests/tst_docks.cpp b/tests/tst_docks.cpp index f027f8e6..298f638f 100644 --- a/tests/tst_docks.cpp +++ b/tests/tst_docks.cpp @@ -306,6 +306,7 @@ private Q_SLOTS: void tst_rectForDropMath_data(); void tst_rectForDropMath(); void tst_crash(); // tests some crash I got + void tst_crash2(); void tst_setFloatingWhenWasTabbed(); void tst_setFloatingWhenSideBySide(); void tst_setFloatingAfterDraggedFromTabToSideBySide(); @@ -2492,6 +2493,41 @@ void TestDocks::tst_crash() } } +void TestDocks::tst_crash2() +{ + EnsureTopLevelsDeleted e; + auto m = new MainWindow("m1"); + auto layout = m->multiSplitterLayout(); + m->show(); + + DockWidget::List docks; + for (int i = 0; i < 3; ++i) + docks << new DockWidget(QString::number(i)); + + QVector locations = {Location_OnLeft, Location_OnLeft, + Location_OnRight}; + + QVector options = { AddingOption_None, AddingOption_None, + AddingOption_StartHidden}; + + QVector floatings = {true, false, false}; + + for (int i = 0; i < 3; ++i) { + + m->addDockWidget(docks[i], locations[i], nullptr, options[i]); + layout->checkSanity(); + + QCOMPARE(layout->m_leftAnchor->cumulativeMinLength(Anchor::Side2), layout->minimumSize().width()); + QCOMPARE(layout->m_topAnchor->cumulativeMinLength(Anchor::Side2), layout->minimumSize().height()); + + docks[i]->setFloating(floatings[i]); + } + + qDeleteAll(docks); + qDeleteAll(DockRegistry::self()->frames()); + delete m; +} + void TestDocks::tst_setFloatingWhenWasTabbed() { // Tests DockWidget::isTabbed() and DockWidget::setFloating(false|true) when tabbed (it should redock) @@ -3966,6 +4002,7 @@ void TestDocks::tst_addToHiddenMainWindow() QVERIFY(!m->isVisible()); d1->setFloating(true); + d2->setFloating(false); delete m; }