KDDockWidgets API Documentation  1.6
Position.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2020-2022 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 
27 using namespace KDDockWidgets;
28 
29 Position::~Position()
30 {
31  m_placeholders.clear();
32 }
33 
34 void 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 
64 Layouting::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 
77 bool 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 
86 void Position::removePlaceholders()
87 {
88  QScopedValueRollback<bool> clearGuard(m_clearing, true);
89  m_placeholders.clear();
90 }
91 
92 void 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 
100 void 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 
112 void 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 
123 void 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 
167 LayoutSaver::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  const auto itemIndex = layout->items().indexOf(item);
177 
178  auto fw = layout->floatingWindow();
179  auto mainWindow = layout->mainWindow();
180  Q_ASSERT(mainWindow || fw);
181  p.isFloatingWindow = fw;
182 
183  if (p.isFloatingWindow) {
184  p.indexOfFloatingWindow = fw->beingDeleted() ? -1 : DockRegistry::self()->floatingWindows().indexOf(fw); // TODO: Remove once we stop using deleteLater with FloatingWindow. delete would be better
185  } else {
186  p.mainWindowUniqueName = mainWindow->uniqueName();
187  Q_ASSERT(!p.mainWindowUniqueName.isEmpty());
188  }
189 
190  p.itemIndex = itemIndex;
191  l.placeholders.push_back(p);
192  }
193 
194  l.tabIndex = m_tabIndex;
195  l.wasFloating = m_wasFloating;
196 
197  l.lastFloatingGeometry = lastFloatingGeometry();
198  l.lastOverlayedGeometries = m_lastOverlayedGeometries;
199 
200  return l;
201 }
202 
203 ItemRef::ItemRef(const QMetaObject::Connection &conn, Layouting::Item *it)
204  : item(it)
205  , guard(it)
206  , connection(conn)
207 {
208  item->ref();
209 }
210 
211 ItemRef::~ItemRef()
212 {
213  if (guard) {
214  QObject::disconnect(connection);
215  item->unref();
216  }
217 }
218 
219 bool ItemRef::isInMainWindow() const
220 {
221  return DockRegistry::self()->itemIsInMainWindow(item);
222 }
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
KDDockWidgets::MainWindowBase::layoutWidget
LayoutWidget * layoutWidget() const
Definition: MainWindowBase.cpp:205
QMetaObject::Connection
QObject::connect
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::destroyed
void destroyed(QObject *obj)
KDDockWidgets::MainWindowBase::uniqueName
QString uniqueName
Definition: MainWindowBase.h:59
KDDockWidgets
Definition: Config.cpp:37
QScopedValueRollback
KDDockWidgets::MainWindowBase
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
Definition: MainWindowBase.h:56

© 2019-2022 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 Thu Sep 15 2022 00:16:29 for KDDockWidgets API Documentation by doxygen 1.8.20