KDDockWidgets API Documentation  1.5
TabWidget.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-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 
20 #include "TabWidget_p.h"
21 #include "Config.h"
22 #include "DockWidgetBase_p.h"
23 #include "DragController_p.h"
24 #include "FloatingWindow_p.h"
25 #include "Frame_p.h"
26 #include "FrameworkWidgetFactory.h"
27 #include "Logging_p.h"
28 #include "Utils_p.h"
29 #include "WindowBeingDragged_p.h"
30 
31 #ifdef QT_WIDGETS_LIB
32 #include <QTabWidget>
33 #endif
34 
35 #include <memory>
36 
37 using namespace KDDockWidgets;
38 
39 TabBar::TabBar(QWidgetOrQuick *thisWidget, TabWidget *tabWidget)
40  : Draggable(thisWidget)
41  , m_tabWidget(tabWidget)
42  , m_thisWidget(thisWidget)
43 {
44 }
45 
46 DockWidgetBase *TabBar::dockWidgetAt(int index) const
47 {
48  if (index < 0 || index >= numDockWidgets())
49  return nullptr;
50 
51  return m_tabWidget->dockwidgetAt(index);
52 }
53 
54 DockWidgetBase *TabBar::dockWidgetAt(QPoint localPos) const
55 {
56  return dockWidgetAt(tabAt(localPos));
57 }
58 
59 std::unique_ptr<WindowBeingDragged> TabBar::makeWindow()
60 {
61  auto dock = m_lastPressedDockWidget;
62  m_lastPressedDockWidget = nullptr; // TODO check if we still have this dock, it might have been deleted
63 
64  const bool hideTitleBarWhenTabsVisible = Config::self().flags() & Config::Flag_HideTitleBarWhenTabsVisible;
65  const bool alwaysShowTabs = Config::self().flags() & Config::Flag_AlwaysShowTabs;
66 
67  if (hideTitleBarWhenTabsVisible) {
68  if (dock) {
69  if (alwaysShowTabs && hasSingleDockWidget()) {
70  // Case #1. User is dragging a tab but there's only 1 tab (and tabs are always visible), so drag everything instead, no detaching happens
71  return m_tabWidget->makeWindow();
72  }
73  } else {
74  // Case #2. User is dragging on the QTabBar background, not on an actual tab.
75  // As Flag_HideTitleBarWhenTabsVisible is set, we let the user drag through the tab widget background.
76  return m_tabWidget->makeWindow();
77  }
78  } else {
79  if (dock && hasSingleDockWidget() && alwaysShowTabs) {
80  // Case #3. window with title bar and single tab, no detaching should happen, just use the title bar.
81  return {};
82  }
83  }
84 
85  if (!dock)
86  return {};
87 
88  FloatingWindow *floatingWindow = frame()->detachTab(dock);
89  if (!floatingWindow)
90  return {};
91 
92  auto draggable = KDDockWidgets::usesNativeTitleBar() ? static_cast<Draggable *>(floatingWindow)
93  : static_cast<Draggable *>(this);
94  return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(floatingWindow, draggable));
95 }
96 
97 bool TabBar::isWindow() const
98 {
99  // Same semantics as tab widget, no need to duplicate logic
100  return m_tabWidget->isWindow();
101 }
102 
103 void TabBar::onMousePress(QPoint localPos)
104 {
105  m_lastPressedDockWidget = dockWidgetAt(localPos);
106  Frame *frame = this->frame();
107  if ((Config::self().flags() & Config::Flag_TitleBarIsFocusable) && !frame->isFocused()) {
108  // User clicked on a tab which was already focused
109  // A tab changing also counts as a change of scope
110  frame->FocusScope::focus(Qt::MouseFocusReason);
111  }
112 }
113 
114 void TabBar::onMouseDoubleClick(QPoint localPos)
115 {
116  if (DockWidgetBase *dw = dockWidgetAt(localPos))
117  dw->setFloating(true);
118 }
119 
120 bool TabBar::hasSingleDockWidget() const
121 {
122  return numDockWidgets() == 1;
123 }
124 
125 int TabBar::numDockWidgets() const
126 {
127  return m_tabWidget->numDockWidgets();
128 }
129 
130 QWidgetOrQuick *TabBar::asWidget() const
131 {
132  return m_thisWidget;
133 }
134 
135 DockWidgetBase *TabBar::singleDockWidget() const
136 {
137  return m_tabWidget->singleDockWidget();
138 }
139 
140 bool TabBar::isMDI() const
141 {
142  Frame *f = frame();
143  return f && f->isMDI();
144 }
145 
146 Frame *TabBar::frame() const
147 {
148  return m_tabWidget->frame();
149 }
150 
151 TabWidget::TabWidget(QWidgetOrQuick *thisWidget, Frame *frame)
152  : Draggable(thisWidget, Config::self().flags() & (Config::Flag_HideTitleBarWhenTabsVisible | Config::Flag_AlwaysShowTabs))
153  , m_frame(frame)
154  , m_thisWidget(thisWidget)
155 {
156 }
157 
158 void TabWidget::setCurrentDockWidget(DockWidgetBase *dw)
159 {
160  setCurrentDockWidget(indexOfDockWidget(dw));
161 }
162 
163 DockWidgetBase *TabWidget::currentDockWidget() const
164 {
165  return dockwidgetAt(currentIndex());
166 }
167 
168 void TabWidget::addDockWidget(DockWidgetBase *dock)
169 {
170  insertDockWidget(dock, numDockWidgets());
171 }
172 
173 bool TabWidget::insertDockWidget(DockWidgetBase *dock, int index)
174 {
175  Q_ASSERT(dock);
176  qCDebug(addwidget) << Q_FUNC_INFO << dock << "; count before=" << numDockWidgets();
177 
178  if (index < 0)
179  index = 0;
180  if (index > numDockWidgets())
181  index = numDockWidgets();
182 
183  if (contains(dock)) {
184  qWarning() << Q_FUNC_INFO << "Refusing to add already existing widget";
185  return false;
186  }
187 
188  QPointer<Frame> oldFrame = dock->d->frame();
189  insertDockWidget(index, dock, dock->icon(DockWidgetBase::IconPlace::TabBar), dock->title());
190  setCurrentDockWidget(index);
191 
192  if (oldFrame && oldFrame->beingDeletedLater()) {
193  // give it a push and delete it immediately.
194  // Having too many deleteLater() puts us in an inconsistent state. For example if LayoutSaver::saveState()
195  // would to be called while the Frame hadn't been deleted yet it would count with that frame unless hacks.
196  // Also the unit-tests are full of waitForDeleted() due to deleteLater.
197 
198  // Ideally we would just remove the deleteLater from frame.cpp, but QTabWidget::insertTab()
199  // would crash, as it accesses the old tab-widget we're stealing from
200 
201  delete oldFrame;
202  }
203 
204  return true;
205 }
206 
207 bool TabWidget::contains(DockWidgetBase *dw) const
208 {
209  return indexOfDockWidget(dw) != -1;
210 }
211 
212 QWidgetOrQuick *TabWidget::asWidget() const
213 {
214  return m_thisWidget;
215 }
216 
217 Frame *TabWidget::frame() const
218 {
219  return m_frame;
220 }
221 
222 std::unique_ptr<WindowBeingDragged> TabWidget::makeWindow()
223 {
224  // This is called when using Flag_HideTitleBarWhenTabsVisible
225  // For detaching individual tabs, TabBar::makeWindow() is called.
226  if (auto floatingWindow = qobject_cast<FloatingWindow *>(asWidget()->window())) {
227  if (floatingWindow->hasSingleFrame()) {
228  // We're already in a floating window, and it only has 1 dock widget.
229  // So there's no detachment to be made, we just move the window.
230  return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(floatingWindow, this));
231  }
232  }
233 
234  QRect r = m_frame->QWidgetAdapter::geometry();
235 
236  const QPoint globalPoint = m_thisWidget->mapToGlobal(QPoint(0, 0));
237 
238  auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(m_frame);
239  r.moveTopLeft(globalPoint);
240  floatingWindow->setSuggestedGeometry(r, SuggestedGeometryHint_GeometryIsFromDocked);
241  floatingWindow->show();
242 
243  return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(floatingWindow, this));
244 }
245 
246 bool TabWidget::isWindow() const
247 {
248  if (auto floatingWindow = qobject_cast<FloatingWindow *>(asWidget()->window())) {
249  // Case of dragging via the tab widget when the title bar is hidden
250  return floatingWindow->hasSingleFrame();
251  }
252 
253  return false;
254 }
255 
256 DockWidgetBase *TabWidget::singleDockWidget() const
257 {
258  if (m_frame->hasSingleDockWidget())
259  return m_frame->dockWidgets().first();
260 
261  return nullptr;
262 }
263 
264 bool TabWidget::isMDI() const
265 {
266  return m_frame && m_frame->isMDI();
267 }
268 
269 void TabWidget::onTabInserted()
270 {
271  m_frame->onDockWidgetCountChanged();
272 }
273 
274 void TabWidget::onTabRemoved()
275 {
276  m_frame->onDockWidgetCountChanged();
277 }
278 
279 void TabWidget::onCurrentTabChanged(int index)
280 {
281  Q_UNUSED(index);
282 }
283 
284 bool TabWidget::onMouseDoubleClick(QPoint localPos)
285 {
286  // User clicked the empty space of the tab widget and we don't have title bar
287  // We float the entire frame.
288 
289  if (!(Config::self().flags() & Config::Flag_HideTitleBarWhenTabsVisible) || tabBar()->dockWidgetAt(localPos))
290  return false;
291 
292  Frame *frame = this->frame();
293 
294  // When using MainWindowOption_HasCentralFrame. The central frame is never detachable.
295  if (frame->isCentralFrame())
296  return false;
297 
298  if (FloatingWindow *fw = frame->floatingWindow()) {
299  if (!fw->hasSingleFrame()) {
300  makeWindow();
301  return true;
302  }
303  } else if (frame->isInMainWindow()) {
304  makeWindow();
305  return true;
306  }
307 
308  return false;
309 }
QPointer
QRect::moveTopLeft
void moveTopLeft(const QPoint &position)
QRect
QWidget
KDDockWidgets::DockWidgetBase::title
QString title
Definition: DockWidgetBase.h:66
Qt::MouseFocusReason
MouseFocusReason
KDDockWidgets::Config
Singleton to allow to choose certain behaviours of the framework.
Definition: Config.h:55
Config.h
Application-wide config to tune certain behaviours of the framework.
KDDockWidgets::DockWidgetBase::icon
QIcon icon(IconPlace place=IconPlace::TitleBar) const
Returns the dock widget's titlebar, tabbar, or toggle action icon (depending on the passed place)
Definition: DockWidgetBase.cpp:334
KDDockWidgets::DockWidgetBase
The DockWidget base-class. DockWidget and DockWidgetBase are only split in two so we can share some c...
Definition: DockWidgetBase.h:61
KDDockWidgets
Definition: Config.cpp:36
Draggable
KDDockWidgets::SuggestedGeometryHint_GeometryIsFromDocked
@ SuggestedGeometryHint_GeometryIsFromDocked
Definition: KDDockWidgets.h:204
QPoint
FrameworkWidgetFactory.h
A factory class for allowing the user to customize some internal widgets.

© 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:21 for KDDockWidgets API Documentation by doxygen 1.8.20