diff --git a/src/private/multisplitter/Item.cpp b/src/private/multisplitter/Item.cpp index eeee4e8d..07574fdf 100644 --- a/src/private/multisplitter/Item.cpp +++ b/src/private/multisplitter/Item.cpp @@ -882,6 +882,7 @@ struct ItemContainer::Private void updateSeparators_recursive(); QSize minSize(const Item::List &items) const; int excessLength() const; + void simplify(); mutable bool m_checkSanityScheduled = false; QVector m_separators; @@ -1695,7 +1696,12 @@ void ItemContainer::insertItem(Item *item, int index, DefaultSizeMode defaultSiz if (!d->m_convertingItemToContainer && item->isVisible()) restoreChild(item); - if (item->isVisible()) + const bool shouldEmitVisibleChanged = item->isVisible(); + + if (!d->m_convertingItemToContainer) + d->simplify(); + + if (shouldEmitVisibleChanged) Q_EMIT root()->numVisibleItemsChanged(root()->numVisibleChildren()); Q_EMIT root()->numItemsChanged(); } @@ -3117,6 +3123,42 @@ int ItemContainer::Private::excessLength() const return qMax(0, Layouting::length(q->size(), m_orientation) - q->maxLengthHint(m_orientation)); } +void ItemContainer::Private::simplify() +{ + // Removes unneeded nesting. For example, a vertical layout doesn't need to have vertical layouts + // inside. It can simply have the contents of said sub-layouts + + Item::List newChildren; + newChildren.reserve(m_children.size() + 20); // over-reserve a bit + + for (Item *child : qAsConst(m_children)) { + if (ItemContainer *childContainer = child->asContainer()) { + childContainer->d->simplify(); // recurse down the hierarchy + + if (childContainer->orientation() == m_orientation) { + // This sub-container is reduntant, as it has the same orientation as its parent + // Canibalize it. + for (Item *child2 : childContainer->childItems()) { + child2->setParentContainer(q); + newChildren.push_back(child2); + } + + delete childContainer; + } else { + newChildren.push_back(child); + } + } else { + newChildren.push_back(child); + } + } + + if (m_children != newChildren) { + m_children = newChildren; + q->positionItems(); + q->updateChildPercentages(); + } +} + Separator *ItemContainer::Private::separatorAt(int p) const { for (Separator *separator : m_separators) { diff --git a/src/private/multisplitter/tests/tst_multisplitter.cpp b/src/private/multisplitter/tests/tst_multisplitter.cpp index a696e1e3..b60b420e 100644 --- a/src/private/multisplitter/tests/tst_multisplitter.cpp +++ b/src/private/multisplitter/tests/tst_multisplitter.cpp @@ -931,7 +931,7 @@ void TestMultiSplitter::tst_suggestedRect2() Item *item = createItem(); root2->insertItem(item, Item::Location_OnRight); - root1->insertItem(root2.get(), Item::Location_OnRight); + root1->insertItem(root2.release(), Item::Location_OnRight); QVERIFY(item->parentContainer()->suggestedDropRect(&itemBeingDropped, item, Item::Location_OnRight).isValid()); } @@ -960,7 +960,7 @@ void TestMultiSplitter::tst_suggestedRect4() Item *item1 = createItem(); root1->insertItem(item1, Item::Location_OnLeft); - root->insertItem(root1.get(), Item::Location_OnLeft); + root->insertItem(root1.release(), Item::Location_OnLeft); auto root2 = createRoot(); Item *item2 = createItem(); @@ -970,13 +970,13 @@ void TestMultiSplitter::tst_suggestedRect4() Item *item3 = createItem(); root3->insertItem(item3, Item::Location_OnLeft); - root1->insertItem(root2.get(), Item::Location_OnRight); - root2->insertItem(root3.get(), Item::Location_OnBottom); + item1->insertItem(root2.release(), Item::Location_OnRight); + item2->insertItem(root3.release(), Item::Location_OnBottom); Item *itemToDrop = createItem(); QVERIFY(root->checkSanity()); - QVERIFY(!root3->suggestedDropRect(itemToDrop, item3, Item::Location_OnLeft).isEmpty()); + QVERIFY(!item3->parentContainer()->suggestedDropRect(itemToDrop, item3, Item::Location_OnLeft).isEmpty()); delete itemToDrop; } @@ -993,10 +993,10 @@ void TestMultiSplitter::tst_insertAnotherRoot() Item *item2 = createItem(); root2->insertItem(item2, Item::Location_OnRight); - root1->insertItem(root2.get(), Item::Location_OnBottom); + root1->insertItem(root2.release(), Item::Location_OnBottom); QCOMPARE(root1->hostWidget()->asQWidget(), host1); - QCOMPARE(root2->hostWidget()->asQWidget(), host1); + QCOMPARE(item2->hostWidget()->asQWidget(), host1); for (Item *item : root1->items_recursive()) { QCOMPARE(item->hostWidget()->asQWidget(), host1); QVERIFY(item->isVisible()); @@ -1017,10 +1017,10 @@ void TestMultiSplitter::tst_insertAnotherRoot() Item *item12 = createItem(); root2->insertItem(item12, Item::Location_OnRight); - root1->insertItem(root2.get(), Item::Location_OnTop); + root1->insertItem(root2.release(), Item::Location_OnTop); QCOMPARE(root1->hostWidget()->asQWidget(), host1); - QCOMPARE(root2->hostWidget()->asQWidget(), host1); + QCOMPARE(item2->hostWidget()->asQWidget(), host1); for (Item *item : root1->items_recursive()) { QCOMPARE(item->hostWidget()->asQWidget(), host1); QVERIFY(item->isVisible()); @@ -1058,25 +1058,27 @@ void TestMultiSplitter::tst_misc2() // | |3|4| auto root = createRoot(); - Item *item1 = createRootWithSingleItem(); - Item *item2 = createRootWithSingleItem(); - Item *item3 = createRootWithSingleItem(); - Item *item4 = createRootWithSingleItem(); - Item *item5 = createRootWithSingleItem(); + ItemContainer *root1 = createRootWithSingleItem(); + Item *item1 = root1->childItems().constFirst(); + ItemContainer *root2 = createRootWithSingleItem(); + ItemContainer *root3 = createRootWithSingleItem(); + Item *item3 = root3->childItems().constFirst(); + ItemContainer *root4 = createRootWithSingleItem(); + ItemContainer *root5 = createRootWithSingleItem(); - root->insertItem(item1, Item::Location_OnTop); + root->insertItem(root1, Item::Location_OnTop); QVERIFY(root->checkSanity()); - item1->insertItem(item2, Item::Location_OnRight); + item1->insertItem(root2, Item::Location_OnRight); QVERIFY(root->checkSanity()); root->insertItem(item3, Item::Location_OnBottom); QVERIFY(root->checkSanity()); - item3->insertItem(item4, Item::Location_OnRight); + item3->insertItem(root4, Item::Location_OnRight); QVERIFY(root->checkSanity()); - root->insertItem(item5, Item::Location_OnLeft); + root->insertItem(root5, Item::Location_OnLeft); QVERIFY(root->checkSanity()); - item5->parentContainer()->removeItem(item5); + root5->parentContainer()->removeItem(root5); QVERIFY(root->checkSanity()); QVERIFY(serializeDeserializeTest(root)); } @@ -1494,14 +1496,18 @@ void TestMultiSplitter::tst_resizeViaSeparator3() void TestMultiSplitter::tst_mapToRoot() { + // 1 + // ----- + // 21|22 + auto root = createRoot(); Item *item1 = createItem(); root->insertItem(item1, Item::Location_OnLeft); auto root2 = createRoot(); Item *item21 = createItem(); Item *item22 = createItem(); - root2->insertItem(item21, Item::Location_OnTop); - root2->insertItem(item22, Item::Location_OnBottom); + root2->insertItem(item21, Item::Location_OnLeft); + root2->insertItem(item22, Item::Location_OnRight); root->insertItem(root2.release(), Item::Location_OnBottom); QVERIFY(root->checkSanity()); @@ -1652,13 +1658,21 @@ void TestMultiSplitter::tst_maxSizeHonoured2() { // Tests that a container gets the max size of its children + // 2 + // ----- + // 1|3 + auto root1 = createRoot(); auto root2 = createRoot(); auto item1 = createItem(); auto item2 = createItem(); + auto item3 = createItem(); root1->insertItem(item1, Item::Location_OnTop); + root1->insertItem(item3, Item::Location_OnRight); root2->insertItem(item2, Item::Location_OnTop); + root2->insertItem(item3, Item::Location_OnLeft); + root2->removeItem(item3, /*hardRemove=*/false); item2->setMaxSizeHint(QSize(200, 200));