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