diff --git a/src/LayoutSaver.cpp b/src/LayoutSaver.cpp index 4a06e6fc..0cb9e925 100644 --- a/src/LayoutSaver.cpp +++ b/src/LayoutSaver.cpp @@ -652,7 +652,7 @@ QVariantMap LayoutSaver::Frame::toVariantMap() const map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry)); map.insert(QStringLiteral("options"), options); map.insert(QStringLiteral("currentTabIndex"), currentTabIndex); - + map.insert(QStringLiteral("mainWindowUniqueName"), mainWindowUniqueName); map.insert(QStringLiteral("dockWidgets"), dockWidgetNames(dockWidgets)); return map; @@ -669,6 +669,7 @@ void LayoutSaver::Frame::fromVariantMap(const QVariantMap &map) id = map.value(QStringLiteral("id")).toString(); isNull = map.value(QStringLiteral("isNull")).toBool(); objectName = map.value(QStringLiteral("objectName")).toString(); + mainWindowUniqueName = map.value(QStringLiteral("mainWindowUniqueName")).toString(); geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap()); options = static_cast::Int>(map.value(QStringLiteral("options")).toUInt()); currentTabIndex = map.value(QStringLiteral("currentTabIndex")).toInt(); diff --git a/src/private/DropAreaWithCentralFrame_p.h b/src/private/DropAreaWithCentralFrame_p.h index 7cb925a5..12c50e6b 100644 --- a/src/private/DropAreaWithCentralFrame_p.h +++ b/src/private/DropAreaWithCentralFrame_p.h @@ -28,6 +28,7 @@ public: private: friend class MainWindowBase; + friend class Frame; Frame *const m_centralFrame = nullptr; }; diff --git a/src/private/Frame.cpp b/src/private/Frame.cpp index 5a7e43b4..71234034 100644 --- a/src/private/Frame.cpp +++ b/src/private/Frame.cpp @@ -31,6 +31,7 @@ #include "Utils_p.h" #include "WidgetResizeHandler_p.h" #include "MDILayoutWidget_p.h" +#include "DropAreaWithCentralFrame_p.h" #include #include @@ -147,7 +148,8 @@ void Frame::insertWidget(DockWidgetBase *dockWidget, int index, InitialOption ad { Q_ASSERT(dockWidget); if (containsDockWidget(dockWidget)) { - qWarning() << "Frame::addWidget dockWidget already exists. this=" << this << "; dockWidget=" << dockWidget; + if (!dockWidget->isPersistentCentralDockWidget()) + qWarning() << "Frame::addWidget dockWidget already exists. this=" << this << "; dockWidget=" << dockWidget; return; } if (m_layoutItem) @@ -652,7 +654,37 @@ Frame *Frame::deserialize(const LayoutSaver::Frame &f) if (!f.isValid()) return nullptr; - auto frame = Config::self().frameworkWidgetFactory()->createFrame(/*parent=*/nullptr, FrameOptions(f.options)); + const FrameOptions options = FrameOptions(f.options); + Frame *frame = nullptr; + const bool isPersistentCentralFrame = options & FrameOption::FrameOption_IsCentralFrame; + auto widgetFactory = Config::self().frameworkWidgetFactory(); + + if (isPersistentCentralFrame) { + // Don't create a new Frame if we're restoring the Persistent Central frame (the one created + // by MainWindowOption_HasCentralFrame). It already exists. + + if (f.mainWindowUniqueName.isEmpty()) { + // Can happen with older serialization formats + qWarning() << Q_FUNC_INFO << "Frame is the persistent central frame but doesn't have" + << "an associated window name"; + } else { + if (MainWindowBase *mw = DockRegistry::self()->mainWindowByName(f.mainWindowUniqueName)) { + frame = mw->dropArea()->m_centralFrame; + if (!frame) { + // Doesn't happen... + qWarning() << "Main window" << f.mainWindowUniqueName << "doesn't have central frame"; + } + } else { + // Doesn't happen... + qWarning() << Q_FUNC_INFO << "Couldn't find main window" + << f.mainWindowUniqueName; + } + } + } + + if (!frame) + frame = widgetFactory->createFrame(/*parent=*/nullptr, options); + frame->setObjectName(f.objectName); for (const auto &savedDock : qAsConst(f.dockWidgets)) { @@ -680,6 +712,9 @@ LayoutSaver::Frame Frame::serialize() const frame.currentTabIndex = currentTabIndex(); frame.id = id(); // for coorelation purposes + if (MainWindowBase *mw = mainWindow()) + frame.mainWindowUniqueName = mw->uniqueName(); + for (DockWidgetBase *dock : docks) frame.dockWidgets.push_back(dock->d->serialize()); diff --git a/src/private/LayoutSaver_p.h b/src/private/LayoutSaver_p.h index 36921ce2..15520cab 100644 --- a/src/private/LayoutSaver_p.h +++ b/src/private/LayoutSaver_p.h @@ -212,6 +212,10 @@ struct LayoutSaver::Frame int currentTabIndex; QString id; // for coorelation purposes + /// Might be empty if not in a main window. Used so we don't create a frame when restoring + /// the persistent central frame, that's never deleted when restoring + QString mainWindowUniqueName; + LayoutSaver::DockWidget::List dockWidgets; }; diff --git a/tests/tst_docks.cpp b/tests/tst_docks.cpp index 7bd7afae..8856a700 100644 --- a/tests/tst_docks.cpp +++ b/tests/tst_docks.cpp @@ -3746,6 +3746,23 @@ void TestDocks::tst_restoreSideBySide() } } +void TestDocks::tst_restoreWithCentralFrameWithTabs() +{ + auto m = createMainWindow(QSize(500, 500), MainWindowOption_HasCentralFrame, "tst_restoreTwice"); + auto dock1 = createDockWidget("1", new QPushButton("1")); + auto dock2 = createDockWidget("2", new QPushButton("2")); + m->addDockWidgetAsTab(dock1); + m->addDockWidgetAsTab(dock2); + + QCOMPARE(DockRegistry::self()->frames().size(), 1); + + LayoutSaver saver; + const QByteArray saved = saver.serializeLayout(); + QVERIFY(saver.restoreLayout(saved)); + + QCOMPARE(DockRegistry::self()->frames().size(), 1); +} + void TestDocks::tst_restoreWithPlaceholder() { // Float dock1, save and restore, then unfloat and see if dock2 goes back to where it was diff --git a/tests/tst_docks.h b/tests/tst_docks.h index c01fdcbb..156fab65 100644 --- a/tests/tst_docks.h +++ b/tests/tst_docks.h @@ -106,6 +106,7 @@ private Q_SLOTS: void tst_restoreNestedAndTabbed(); void tst_restoreCrash(); void tst_restoreSideBySide(); + void tst_restoreWithCentralFrameWithTabs(); void tst_restoreWithPlaceholder(); void tst_restoreWithAffinity(); void tst_marginsAfterRestore();