KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
TabWidget.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019-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
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"
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
37using namespace KDDockWidgets;
38
39TabBar::TabBar(QWidgetOrQuick *thisWidget, TabWidget *tabWidget)
40 : Draggable(thisWidget)
41 , m_tabWidget(tabWidget)
42 , m_thisWidget(thisWidget)
43{
44}
45
46DockWidgetBase *TabBar::dockWidgetAt(int index) const
47{
48 if (index < 0 || index >= numDockWidgets())
49 return nullptr;
50
51 return m_tabWidget->dockwidgetAt(index);
52}
53
54DockWidgetBase *TabBar::dockWidgetAt(QPoint localPos) const
55{
56 return dockWidgetAt(tabAt(localPos));
57}
58
59std::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
97bool TabBar::isWindow() const
98{
99 // Same semantics as tab widget, no need to duplicate logic
100 return m_tabWidget->isWindow();
101}
102
103void 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
114void TabBar::onMouseDoubleClick(QPoint localPos)
115{
116 if (DockWidgetBase *dw = dockWidgetAt(localPos))
117 dw->setFloating(true);
118}
119
120bool TabBar::hasSingleDockWidget() const
121{
122 return numDockWidgets() == 1;
123}
124
125int TabBar::numDockWidgets() const
126{
127 return m_tabWidget->numDockWidgets();
128}
129
130QWidgetOrQuick *TabBar::asWidget() const
131{
132 return m_thisWidget;
133}
134
135DockWidgetBase *TabBar::singleDockWidget() const
136{
137 return m_tabWidget->singleDockWidget();
138}
139
140bool TabBar::isMDI() const
141{
142 Frame *f = frame();
143 return f && f->isMDI();
144}
145
146Frame *TabBar::frame() const
147{
148 return m_tabWidget->frame();
149}
150
151TabWidget::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
158void TabWidget::setCurrentDockWidget(DockWidgetBase *dw)
159{
160 setCurrentDockWidget(indexOfDockWidget(dw));
161}
162
163DockWidgetBase *TabWidget::currentDockWidget() const
164{
165 return dockwidgetAt(currentIndex());
166}
167
168void TabWidget::addDockWidget(DockWidgetBase *dock)
169{
170 insertDockWidget(dock, numDockWidgets());
171}
172
173bool 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
207bool TabWidget::contains(DockWidgetBase *dw) const
208{
209 return indexOfDockWidget(dw) != -1;
210}
211
212QWidgetOrQuick *TabWidget::asWidget() const
213{
214 return m_thisWidget;
215}
216
217Frame *TabWidget::frame() const
218{
219 return m_frame;
220}
221
222std::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
246bool 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
256DockWidgetBase *TabWidget::singleDockWidget() const
257{
258 if (m_frame->hasSingleDockWidget())
259 return m_frame->dockWidgets().first();
260
261 return nullptr;
262}
263
264bool TabWidget::isMDI() const
265{
266 return m_frame && m_frame->isMDI();
267}
268
269void TabWidget::onTabInserted()
270{
271 m_frame->onDockWidgetCountChanged();
272}
273
274void TabWidget::onTabRemoved()
275{
276 m_frame->onDockWidgetCountChanged();
277}
278
279void TabWidget::onCurrentTabChanged(int index)
280{
281 Q_UNUSED(index);
282}
283
284bool 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}
Application-wide config to tune certain behaviours of the framework.
A factory class for allowing the user to customize some internal widgets.
Singleton to allow to choose certain behaviours of the framework.
Definition Config.h:75
FrameworkWidgetFactory * frameworkWidgetFactory() const
getter for the framework widget factory
Definition Config.cpp:145
static Config & self()
returns the singleton Config instance
Definition Config.cpp:84
Flags flags() const
returns the chosen flags
Definition Config.cpp:95
@ Flag_HideTitleBarWhenTabsVisible
Hides the title bar if there's tabs visible. The empty space in the tab bar becomes draggable.
Definition Config.h:92
@ Flag_AlwaysShowTabs
Always show tabs, even if there's only one,.
Definition Config.h:93
@ Flag_TitleBarIsFocusable
You can click the title bar and it will focus the last focused widget in the focus scope....
Definition Config.h:98
The DockWidget base-class. DockWidget and DockWidgetBase are only split in two so we can share some c...
QIcon icon(IconPlace place=IconPlace::TitleBar) const
Returns the dock widget's titlebar, tabbar, or toggle action icon (depending on the passed place)
virtual FloatingWindow * createFloatingWindow(MainWindowBase *parent=nullptr, FloatingWindowFlags=FloatingWindowFlag::FromGlobalConfig) const =0
Called internally by the framework to create a FloatingWindow Override to provide your own FloatingWi...
@ SuggestedGeometryHint_GeometryIsFromDocked
void moveTopLeft(const QPoint &position)
MouseFocusReason

© 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