Skip to content

Commit c1952b4

Browse files
committed
Don't close "document" dock widgets when restoring non-document dock widgets
Finishes supporting MainWindow::setDocumentAffinity() feature
1 parent 947e7b6 commit c1952b4

6 files changed

Lines changed: 190 additions & 7 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,9 +592,11 @@ if(KDDockWidgets_EXAMPLES)
592592
add_subdirectory(examples/minimal)
593593
add_subdirectory(examples/mdi)
594594
add_subdirectory(examples/mdi_with_docking)
595+
add_subdirectory(examples/misc)
595596
set_compiler_flags(qtwidgets_dockwidgets)
596597
set_compiler_flags(qtwidgets_minimal)
597598
set_compiler_flags(qtwidgets_mdi_with_docking)
599+
set_compiler_flags(qtwidgets_documents)
598600

599601
# Standalone layouting example
600602
add_subdirectory(src/core/layouting/examples/qtwidgets/)

examples/misc/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# This file is part of KDDockWidgets.
2+
#
3+
# SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
4+
# Author: Sergio Martins <sergio.martins@kdab.com>
5+
#
6+
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
7+
#
8+
# Contact KDAB at <info@kdab.com> for commercial licensing options.
9+
#
10+
11+
add_subdirectory(documents)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# This file is part of KDDockWidgets.
2+
#
3+
# SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
4+
# Author: Sergio Martins <sergio.martins@kdab.com>
5+
#
6+
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
7+
#
8+
# Contact KDAB at <info@kdab.com> for commercial licensing options.
9+
#
10+
11+
cmake_minimum_required(VERSION 3.15)
12+
project(qtwidgets_documents)
13+
14+
set(CMAKE_AUTOMOC ON)
15+
set(CMAKE_AUTORCC ON)
16+
set(CMAKE_INCLUDE_CURRENT_DIRS ON)
17+
set(CMAKE_CXX_STANDARD 17)
18+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
19+
20+
if(NOT TARGET kddockwidgets)
21+
# For the purpose of our example, we're looking for Qt5 or Qt6 KDDW.
22+
# For your own purposes, just chose the one you need.
23+
find_package(KDDockWidgets QUIET)
24+
if(NOT KDDockWidgets_FOUND)
25+
find_package(KDDockWidgets-qt6 REQUIRED)
26+
endif()
27+
endif()
28+
29+
set(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../dockwidgets/resources_example.qrc)
30+
31+
add_executable(qtwidgets_documents main.cpp ../../dockwidgets/MyWidget.cpp ${RESOURCES_EXAMPLE_SRC})
32+
33+
target_include_directories(qtwidgets_documents PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../dockwidgets)
34+
35+
target_link_libraries(qtwidgets_documents PRIVATE KDAB::kddockwidgets)

examples/misc/documents/main.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
This file is part of KDDockWidgets.
3+
4+
SPDX-FileCopyrightText: 2026 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5+
Author: Sérgio Martins <sergio.martins@kdab.com>
6+
7+
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8+
9+
Contact KDAB at <info@kdab.com> for commercial licensing options.
10+
*/
11+
12+
#include "MyWidget.h"
13+
14+
#include <kddockwidgets/MainWindow.h>
15+
#include <kddockwidgets/DockWidget.h>
16+
#include <kddockwidgets/LayoutSaver.h>
17+
#include <kddockwidgets/core/MainWindow.h>
18+
#include <kddockwidgets/core/DockRegistry.h>
19+
20+
#include <QStyleFactory>
21+
#include <QApplication>
22+
#include <QMenuBar>
23+
24+
// clazy:excludeall=qstring-allocations
25+
26+
using namespace KDDockWidgets;
27+
28+
int main(int argc, char **argv)
29+
{
30+
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
31+
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
32+
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
33+
#endif
34+
QApplication app(argc, argv);
35+
QCoreApplication::setOrganizationName(QStringLiteral("KDAB"));
36+
QCoreApplication::setApplicationName(QStringLiteral("Documents Example"));
37+
38+
KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtWidgets);
39+
40+
qApp->setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
41+
42+
// 1. Create a main window with a persistent central group
43+
KDDockWidgets::QtWidgets::MainWindow mainWindow(QStringLiteral("MyMainWindow"),
44+
MainWindowOption_HasCentralGroup);
45+
mainWindow.setWindowTitle("Documents Example");
46+
mainWindow.resize(1200, 800);
47+
mainWindow.show();
48+
49+
// 2. Set up affinities: the main window supports both scopes
50+
mainWindow.setAffinities({ "global", "projects" });
51+
mainWindow.mainWindow()->setDocumentAffinity("projects");
52+
53+
// 3. Create project dock widgets (tabbed in the central group)
54+
auto projectDock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("project1"));
55+
projectDock1->setWidget(new MyWidget1());
56+
projectDock1->setAffinities({ "projects" });
57+
mainWindow.addDockWidgetAsTab(projectDock1);
58+
59+
auto projectDock2 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("project2"));
60+
projectDock2->setWidget(new MyWidget2());
61+
projectDock2->setAffinities({ "projects" });
62+
mainWindow.addDockWidgetAsTab(projectDock2);
63+
64+
// 4. Create global dock widgets (docked to the sides)
65+
auto dockedGlobal = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("dockedGlobal"));
66+
dockedGlobal->setWidget(new MyWidget3());
67+
dockedGlobal->setAffinities({ "global" });
68+
mainWindow.mainWindow()->addDockWidgetToSide(dockedGlobal->asDockWidgetController(), KDDockWidgets::Location_OnLeft);
69+
70+
auto dockedGlobal2 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("dockedGlobal2"));
71+
dockedGlobal2->setWidget(new MyWidget1());
72+
dockedGlobal2->setAffinities({ "global" });
73+
mainWindow.mainWindow()->addDockWidgetToSide(dockedGlobal2->asDockWidgetController(), KDDockWidgets::Location_OnRight);
74+
75+
// 5. Create floating dock widgets
76+
auto floatingGlobal = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("floatingGlobal"));
77+
floatingGlobal->setWidget(new MyWidget2());
78+
floatingGlobal->setAffinities({ "global" });
79+
floatingGlobal->open();
80+
81+
auto floatingProjects = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("floatingProjects"));
82+
floatingProjects->setWidget(new MyWidget3());
83+
floatingProjects->setAffinities({ "projects" });
84+
floatingProjects->open();
85+
86+
// 6. Create menu bar with save/load actions for each affinity scope
87+
QMenuBar *menuBar = mainWindow.menuBar();
88+
QMenu *layoutMenu = menuBar->addMenu(QStringLiteral("Layout"));
89+
90+
layoutMenu->addAction(QStringLiteral("Save Project"), [&] {
91+
KDDockWidgets::LayoutSaver saver;
92+
saver.setAffinityNames({ "projects" });
93+
saver.saveToFile(QStringLiteral("projects_layout.json"));
94+
});
95+
96+
layoutMenu->addAction(QStringLiteral("Load Project"), [&] {
97+
KDDockWidgets::LayoutSaver saver;
98+
saver.setAffinityNames({ "projects" });
99+
saver.restoreFromFile(QStringLiteral("projects_layout.json"));
100+
});
101+
102+
layoutMenu->addSeparator();
103+
104+
layoutMenu->addAction(QStringLiteral("Save Global"), [&] {
105+
KDDockWidgets::LayoutSaver saver;
106+
saver.setAffinityNames({ "global" });
107+
saver.saveToFile(QStringLiteral("global_layout.json"));
108+
});
109+
110+
layoutMenu->addAction(QStringLiteral("Load Global"), [&] {
111+
KDDockWidgets::LayoutSaver saver;
112+
saver.setAffinityNames({ "global" });
113+
saver.restoreFromFile(QStringLiteral("global_layout.json"));
114+
});
115+
116+
layoutMenu->addSeparator();
117+
118+
layoutMenu->addAction(QStringLiteral("Close all"), [&] {
119+
KDDockWidgets::DockRegistry::self()->clear();
120+
});
121+
122+
return app.exec();
123+
}

src/LayoutSaver.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "LayoutSaver.h"
2020
#include "Config.h"
21+
#include "core/DropArea.h"
2122
#include "core/ViewFactory.h"
2223
#include "core/LayoutSaver_p.h"
2324
#include "core/Logging_p.h"
@@ -39,6 +40,7 @@
3940
#include <iostream>
4041
#include <fstream>
4142
#include <cmath>
43+
#include <qtestsupport_core.h>
4244
#include <utility>
4345

4446
/**
@@ -556,7 +558,6 @@ bool LayoutSaver::restoreLayout(const QByteArray &data)
556558
layout.scaleSizes(d->m_restoreOptions);
557559

558560
d->floatWidgetsWhichSkipRestore(layout.mainWindowNames());
559-
d->floatUnknownWidgets(layout);
560561

561562
Private::RAIIIsRestoring isRestoring;
562563

@@ -566,11 +567,16 @@ bool LayoutSaver::restoreLayout(const QByteArray &data)
566567
auto dockWidgetsToClose = d->m_dockRegistry->dockWidgets(layout.dockWidgetsToClose());
567568
auto mainWindowsToConsider = d->m_dockRegistry->mainWindows(layout.mainWindowNames());
568569
const bool isRestoringDocuments = ::isRestoringDocuments(mainWindowsToConsider, d->m_affinityNames);
570+
571+
if (!isDocumentMode(mainWindowsToConsider, d->m_affinityNames))
572+
d->floatUnknownWidgets(layout);
573+
569574
d->m_dockRegistry->clear(dockWidgetsToClose,
570575
mainWindowsToConsider,
571576
d->m_affinityNames, isRestoringDocuments);
572577

573578
// 1. Restore main windows
579+
574580
for (const LayoutSaver::MainWindow &mw : std::as_const(layout.mainWindows)) {
575581
auto mainWindow = d->m_dockRegistry->mainWindowByName(mw.uniqueName);
576582
if (!mainWindow) {
@@ -591,7 +597,6 @@ bool LayoutSaver::restoreLayout(const QByteArray &data)
591597
for (const auto &savedDock : centralGroup.dockWidgets) {
592598
Core::DockWidget *dw = d->m_dockRegistry->dockByName(
593599
savedDock->uniqueName, DockRegistry::DockByNameFlag::CreateIfNotFound);
594-
qDebug() << "is open?" << dw->uniqueName() << " ; " << dw->isOpen();
595600
if (dw)
596601
mainWindow->addDockWidgetAsTab(dw);
597602
}

tests/qtwidgets/tst_qtwidgets.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3178,29 +3178,36 @@ void TestQtWidgets::tst_affinityWithPersistentCentralGroup()
31783178

31793179
const auto &projectLayout = projectSaver.serializeLayout();
31803180
const auto &globalLayout = globalSaver.serializeLayout();
3181-
QVERIFY(globalSaver.saveToFile("/pub_data/a.json"));
31823181

31833182
// Make changes to the global state and to the project state
31843183
projectDock2->close();
31853184
dockedGlobal2->close();
31863185
floatingGlobal->close();
31873186
floatingProjects->close();
31883187

3188+
QVERIFY(dockedGlobal->isOpen());
3189+
QVERIFY(!dockedGlobal->isFloating());
3190+
31893191
QVERIFY(projectSaver.restoreLayout(projectLayout));
31903192

31913193
// Verify that only the project layout was restored, and the global layout is unaffected
31923194
QVERIFY(projectDock2->isOpen());
31933195
QVERIFY(!dockedGlobal2->isOpen());
3196+
QVERIFY(dockedGlobal->isOpen());
3197+
QVERIFY(!dockedGlobal->isFloating());
31943198
QVERIFY(!floatingGlobal->isOpen());
31953199

31963200
projectDock2->close(); // close it again
3201+
31973202
QVERIFY(globalSaver.restoreLayout(globalLayout));
31983203

31993204
// verify that the global layout was restored, and the project layout is unaffected
3200-
// QVERIFY(dockedGlobal->isOpen());
3201-
// QVERIFY(dockedGlobal2->isOpen());
3202-
// QVERIFY(floatingGlobal->isOpen());
3203-
// QVERIFY(!projectDock2->isOpen());
3205+
QVERIFY(dockedGlobal->isOpen());
3206+
QVERIFY(dockedGlobal2->isOpen());
3207+
QVERIFY(floatingGlobal->isOpen());
3208+
QVERIFY(projectDock1->isOpen());
3209+
QVERIFY(!projectDock1->isFloating());
3210+
QVERIFY(!projectDock2->isOpen());
32043211
}
32053212

32063213
void TestQtWidgets::tst_affinityFloatingWindowIndexMismatch()

0 commit comments

Comments
 (0)