KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
Position.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2020-2023 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
18#include "Position_p.h"
19#include "DockRegistry_p.h"
20#include "FloatingWindow_p.h"
21#include "LayoutSaver_p.h"
22#include "LayoutWidget_p.h"
23#include "multisplitter/Item_p.h"
24
25#include <algorithm>
26
27using namespace KDDockWidgets;
28
29Position::~Position()
30{
31 m_placeholders.clear();
32}
33
34void Position::addPlaceholderItem(Layouting::Item *placeholder)
35{
36 Q_ASSERT(placeholder);
37
38 // 1. Already exists, nothing to do
39 if (containsPlaceholder(placeholder))
40 return;
41
42 if (DockRegistry::self()->itemIsInMainWindow(placeholder)) {
43 // 2. If we have a MainWindow placeholder we don't need nothing else
44 removePlaceholders();
45 } else {
46 // 3. It's a placeholder to a FloatingWindow. Let's still keep any MainWindow placeholders we have
47 // as FloatingWindow are temporary so we might need the MainWindow placeholder later.
48 removeNonMainWindowPlaceholders();
49 }
50
51 // Make sure our list only contains valid placeholders. We save the result so we can disconnect from the lambda, since the Item might outlive Position
52 QMetaObject::Connection connection = QObject::connect(placeholder, &QObject::destroyed, placeholder, [this, placeholder] {
53 removePlaceholder(placeholder);
54 });
55
56 m_placeholders.push_back(std::unique_ptr<ItemRef>(new ItemRef(connection, placeholder)));
57
58 // NOTE: We use a list instead of simply two variables to keep the placeholders, because
59 // a placeholder from a FloatingWindow might become a MainWindow one without we knowing,
60 // like when dragging a floating window into a MainWindow. So, isInMainWindow() won't return
61 // the same value always, hence we just shove them into a list, instead of giving them meaningful names in separated variables
62}
63
64Layouting::Item *Position::layoutItem() const
65{
66 // Return the layout item that is in a MainWindow, that's where we restore the dock widget to.
67 // In the future we might want to restore it to FloatingWindows.
68
69 for (const auto &itemref : m_placeholders) {
70 if (itemref->isInMainWindow())
71 return itemref->item;
72 }
73
74 return nullptr;
75}
76
77bool Position::containsPlaceholder(Layouting::Item *item) const
78{
79 for (const auto &itemRef : m_placeholders)
80 if (itemRef->item == item)
81 return true;
82
83 return false;
84}
85
86void Position::removePlaceholders()
87{
88 QScopedValueRollback<bool> clearGuard(m_clearing, true);
89 m_placeholders.clear();
90}
91
92void Position::removePlaceholders(const LayoutWidget *ms)
93{
94 m_placeholders.erase(std::remove_if(m_placeholders.begin(), m_placeholders.end(), [ms](const std::unique_ptr<ItemRef> &itemref) {
95 return itemref->item->hostWidget() == *ms;
96 }),
97 m_placeholders.end());
98}
99
100void Position::removeNonMainWindowPlaceholders()
101{
102 auto it = m_placeholders.begin();
103 while (it != m_placeholders.end()) {
104 ItemRef *itemref = it->get();
105 if (!itemref->isInMainWindow())
106 it = m_placeholders.erase(it);
107 else
108 ++it;
109 }
110}
111
112void Position::removePlaceholder(Layouting::Item *placeholder)
113{
114 if (m_clearing) // reentrancy guard
115 return;
116
117 m_placeholders.erase(std::remove_if(m_placeholders.begin(), m_placeholders.end(), [placeholder](const std::unique_ptr<ItemRef> &itemref) {
118 return itemref->item == placeholder;
119 }),
120 m_placeholders.end());
121}
122
123void Position::deserialize(const LayoutSaver::Position &lp)
124{
125 m_lastFloatingGeometry = lp.lastFloatingGeometry;
126 m_lastOverlayedGeometries = lp.lastOverlayedGeometries;
127
128 for (const auto &placeholder : qAsConst(lp.placeholders)) {
129 LayoutWidget *layout;
130 int itemIndex = placeholder.itemIndex;
131 if (placeholder.isFloatingWindow) {
132 const int index = placeholder.indexOfFloatingWindow;
133 if (index == -1) {
134 continue; // Skip
135 } else {
136 auto serializedFw = LayoutSaver::Layout::s_currentLayoutBeingRestored->floatingWindowForIndex(index);
137 if (serializedFw.isValid()) {
138 if (FloatingWindow *fw = serializedFw.floatingWindowInstance) {
139 layout = fw->layoutWidget();
140 } else {
141 continue;
142 }
143 } else {
144 qWarning() << "Invalid floating window position to restore" << index;
145 continue;
146 }
147 }
148 } else {
149 MainWindowBase *mainWindow = DockRegistry::self()->mainWindowByName(placeholder.mainWindowUniqueName);
150 layout = mainWindow->layoutWidget();
151 }
152
153 const Layouting::Item::List &items = layout->items();
154 if (itemIndex >= 0 && itemIndex < items.size()) {
155 Layouting::Item *item = items.at(itemIndex);
156 addPlaceholderItem(item);
157 } else {
158 // Shouldn't happen, maybe even assert
159 qWarning() << Q_FUNC_INFO << "Couldn't find item index" << itemIndex << "in" << items;
160 }
161 }
162
163 m_tabIndex = lp.tabIndex;
164 m_wasFloating = lp.wasFloating;
165}
166
167LayoutSaver::Position Position::serialize() const
168{
169 LayoutSaver::Position l;
170
171 for (auto &itemRef : m_placeholders) {
172 LayoutSaver::Placeholder p;
173
174 Layouting::Item *item = itemRef->item;
175 LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
176 Q_ASSERT(layout);
177 const auto itemIndex = layout->items().indexOf(item);
178
179 auto fw = layout->floatingWindow();
180 auto mainWindow = layout->mainWindow(/*honourNesting=*/true);
181 Q_ASSERT(mainWindow || fw);
182 p.isFloatingWindow = fw;
183
184 if (p.isFloatingWindow) {
185 p.indexOfFloatingWindow = fw->beingDeleted() ? -1 : DockRegistry::self()->floatingWindows().indexOf(fw); // TODO: Remove once we stop using deleteLater with FloatingWindow. delete would be better
186 } else {
187 p.mainWindowUniqueName = mainWindow->uniqueName();
188 Q_ASSERT(!p.mainWindowUniqueName.isEmpty());
189 }
190
191 p.itemIndex = itemIndex;
192 l.placeholders.push_back(p);
193 }
194
195 l.tabIndex = m_tabIndex;
196 l.wasFloating = m_wasFloating;
197
198 l.lastFloatingGeometry = lastFloatingGeometry();
199 l.lastOverlayedGeometries = m_lastOverlayedGeometries;
200
201 return l;
202}
203
204ItemRef::ItemRef(const QMetaObject::Connection &conn, Layouting::Item *it)
205 : item(it)
206 , guard(it)
207 , connection(conn)
208{
209 item->ref();
210}
211
212ItemRef::~ItemRef()
213{
214 if (guard) {
215 QObject::disconnect(connection);
216 item->unref();
217 }
218}
219
220bool ItemRef::isInMainWindow() const
221{
222 return DockRegistry::self()->itemIsInMainWindow(item);
223}
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
LayoutWidget * layoutWidget() const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void destroyed(QObject *obj)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)

© 2019-2023 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated on Wed Nov 1 2023 00:02:31 for KDDockWidgets API Documentation by doxygen 1.9.8