KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
DockRegistry.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
12#include "DockRegistry_p.h"
13#include "Config.h"
14#include "DockWidgetBase.h"
15#include "DockWidgetBase_p.h"
16#include "FloatingWindow_p.h"
17#include "LayoutWidget_p.h"
18#include "Logging_p.h"
19#include "MainWindowMDI.h"
20#include "Position_p.h"
21#include "QWidgetAdapter.h"
22#include "SideBar_p.h"
23#include "Utils_p.h"
24#include "WidgetResizeHandler_p.h"
25#include "WindowBeingDragged_p.h"
26#include "multisplitter/Item_p.h"
27
28#include <QPointer>
29#include <QDebug>
30#include <QGuiApplication>
31#include <QWindow>
32
33#ifdef KDDOCKWIDGETS_QTWIDGETS
34#include "DebugWindow_p.h"
35#else
36#include "quick/QmlTypes.h"
37#endif
38
39using namespace KDDockWidgets;
40
42{
43#if defined(KDDOCKWIDGETS_STATICLIB) || defined(QT_STATIC)
44 Q_INIT_RESOURCE(kddockwidgets_resources);
45#if defined(KDDOCKWIDGETS_QTQUICK)
46 Q_INIT_RESOURCE(kddockwidgets_qtquick);
47#endif
48#endif
49}
50
51namespace KDDockWidgets {
52
53// Helper class to help implement Config::Flag_AutoHideAsTabGroups
54class SideBarGroupings
55{
56public:
57 void addGrouping(const DockWidgetBase::List &);
58 void removeGrouping(const DockWidgetBase::List &);
59 DockWidgetBase::List groupingFor(DockWidgetBase *) const;
60 void removeFromGroupings(DockWidgetBase *);
61
62private:
63 DockWidgetBase::List &groupingByRef(DockWidgetBase *);
65};
66
67}
68
69DockRegistry::DockRegistry(QObject *parent)
70 : QObject(parent)
71 , m_sideBarGroupings(new SideBarGroupings())
72{
73 qApp->installEventFilter(this);
74
75#ifdef KDDOCKWIDGETS_QTWIDGETS
76
77#ifdef DOCKS_DEVELOPER_MODE
78 if (qEnvironmentVariableIntValue("KDDOCKWIDGETS_SHOW_DEBUG_WINDOW") == 1) {
79 auto dv = new Debug::DebugWindow();
80 dv->show();
81 }
82#endif
83
84#else
86 QQuickWindow::setDefaultAlphaBuffer(true);
87#endif
88
90 this, &DockRegistry::onFocusObjectChanged);
91
93}
94
95DockRegistry::~DockRegistry()
96{
97 delete m_sideBarGroupings;
98}
99
100void DockRegistry::maybeDelete()
101{
102 if (isEmpty())
103 delete this;
104}
105
106void DockRegistry::onFocusObjectChanged(QObject *obj)
107{
108 auto p = qobject_cast<WidgetType *>(obj);
109 while (p) {
110 if (auto frame = qobject_cast<Frame *>(p)) {
111 // Special case: The focused widget is inside the frame but not inside the dockwidget.
112 // For example, it's a line edit in the QTabBar. We still need to send the signal for
113 // the current dw in the tab group
114 if (auto dw = frame->currentDockWidget()) {
115 setFocusedDockWidget(dw);
116 }
117
118 return;
119 }
120
121 if (auto dw = qobject_cast<DockWidgetBase *>(p)) {
122 DockRegistry::self()->setFocusedDockWidget(dw);
123 return;
124 }
125 p = KDDockWidgets::Private::parentWidget(p);
126 }
127
128 setFocusedDockWidget(nullptr);
129}
130
131void DockRegistry::setFocusedDockWidget(DockWidgetBase *dw)
132{
133 if (m_focusedDockWidget.data() == dw)
134 return;
135
136 if (m_focusedDockWidget)
137 Q_EMIT m_focusedDockWidget->isFocusedChanged(false);
138
139 m_focusedDockWidget = dw;
140
141 if (m_focusedDockWidget)
142 Q_EMIT m_focusedDockWidget->isFocusedChanged(true);
143}
144
145bool DockRegistry::isEmpty(bool excludeBeingDeleted) const
146{
147 if (!m_dockWidgets.isEmpty() || !m_mainWindows.isEmpty())
148 return false;
149
150 return excludeBeingDeleted ? !hasFloatingWindows()
151 : m_floatingWindows.isEmpty();
152}
153
154void DockRegistry::checkSanityAll(bool dumpLayout)
155{
156 for (auto layout : qAsConst(m_layouts)) {
157 layout->checkSanity();
158 if (dumpLayout)
159 layout->dumpLayout();
160 }
161}
162
163bool DockRegistry::isProcessingAppQuitEvent() const
164{
165 return m_isProcessingAppQuitEvent;
166}
167
168bool DockRegistry::affinitiesMatch(const QStringList &affinities1, const QStringList &affinities2) const
169{
170 if (affinities1.isEmpty() && affinities2.isEmpty())
171 return true;
172
173 for (const QString &a1 : affinities1) {
174 for (const QString &a2 : affinities2) {
175 if (a1 == a2)
176 return true;
177 }
178 }
179
180 return false;
181}
182
183QStringList DockRegistry::mainWindowsNames() const
184{
185 QStringList names;
186 names.reserve(m_mainWindows.size());
187 for (auto mw : m_mainWindows)
188 names.push_back(mw->uniqueName());
189
190 return names;
191}
192
193QStringList DockRegistry::dockWidgetNames() const
194{
195 QStringList names;
196 names.reserve(m_dockWidgets.size());
197 for (auto dw : m_dockWidgets)
198 names.push_back(dw->uniqueName());
199
200 return names;
201}
202
203bool DockRegistry::isProbablyObscured(QWindow *window, FloatingWindow *exclude) const
204{
205 if (!window)
206 return false;
207
208 const QRect geo = window->geometry();
209 for (FloatingWindow *fw : m_floatingWindows) {
210 QWindow *fwWindow = fw->QWidgetAdapter::windowHandle();
211 if (fw == exclude || fwWindow == window)
212 continue;
213
214 if (fwWindow->geometry().intersects(geo)) {
215 // fw might be below, but we don't have a way to check. So be conservative and return true.
216 return true;
217 }
218 }
219
220 // Floating windows are Tool (keep above), unless we disabled it in Config
221 auto fw = floatingWindowForHandle(window);
222 const bool targetIsToolWindow = fw && fw->isUtilityWindow();
223
224 for (MainWindowBase *mw : m_mainWindows) {
225 QWindow *mwWindow = mw->window()->windowHandle();
226
227 if (mwWindow && mwWindow != window && !targetIsToolWindow && mwWindow->geometry().intersects(geo)) {
228 // Two main windows that intersect. Return true. If the target is a tool window it will be above, so we don't care.
229 return true;
230 }
231 }
232
233 return false;
234}
235
236bool DockRegistry::isProbablyObscured(QWindow *target, WindowBeingDragged *exclude) const
237{
238 FloatingWindow *fw = exclude ? exclude->floatingWindow()
239 : nullptr; // It's null on Wayland. On wayland obscuring never happens anyway, so not a problem.
240
241 return isProbablyObscured(target, fw);
242}
243
244SideBarLocation DockRegistry::sideBarLocationForDockWidget(const DockWidgetBase *dw) const
245{
246 if (SideBar *sb = sideBarForDockWidget(dw))
247 return sb->location();
248
249 return SideBarLocation::None;
250}
251
252SideBar *DockRegistry::sideBarForDockWidget(const DockWidgetBase *dw) const
253{
254 for (auto mw : m_mainWindows) {
255 if (SideBar *sb = mw->sideBarForDockWidget(dw))
256 return sb;
257 }
258
259 return nullptr;
260}
261
262Frame *DockRegistry::frameInMDIResize() const
263{
264 for (auto mw : m_mainWindows) {
265 if (!mw->isMDI())
266 continue;
267
268 LayoutWidget *layout = mw->layoutWidget();
269 const QList<Frame *> frames = layout->frames();
270 for (Frame *frame : frames) {
271 if (WidgetResizeHandler *wrh = frame->resizeHandler()) {
272 if (wrh->isResizing())
273 return frame;
274 }
275 }
276 }
277
278 return nullptr;
279}
280
281MainWindowBase::List DockRegistry::mainWindowsWithAffinity(const QStringList &affinities) const
282{
284 result.reserve(m_mainWindows.size());
285
286 for (auto mw : m_mainWindows) {
287 const QStringList mwAffinities = mw->affinities();
288 if (affinitiesMatch(mwAffinities, affinities))
289 result << mw;
290 }
291
292 return result;
293}
294
295LayoutWidget *DockRegistry::layoutForItem(const Layouting::Item *item) const
296{
297 if (!item->hostWidget())
298 return nullptr;
299
300 if (auto ms = qobject_cast<LayoutWidget *>(item->hostWidget()->asQObject()))
301 return ms;
302
303 return nullptr;
304}
305
306bool DockRegistry::itemIsInMainWindow(const Layouting::Item *item) const
307{
308 if (LayoutWidget *layout = layoutForItem(item)) {
309 return layout->isInMainWindow(/*honoursNesting=*/true);
310 }
311
312 return false;
313}
314
315DockRegistry *DockRegistry::self()
316{
317 static QPointer<DockRegistry> s_dockRegistry;
318
319 if (!s_dockRegistry) {
320 s_dockRegistry = new DockRegistry();
321 }
322
323 return s_dockRegistry;
324}
325
326void DockRegistry::registerDockWidget(DockWidgetBase *dock)
327{
328 if (dock->uniqueName().isEmpty()) {
329 qWarning() << Q_FUNC_INFO << "DockWidget" << dock << " doesn't have an ID";
330 } else if (auto other = dockByName(dock->uniqueName())) {
331 qWarning() << Q_FUNC_INFO << "Another DockWidget" << other << "with name" << dock->uniqueName() << " already exists." << dock;
332 }
333
334 m_dockWidgets << dock;
335}
336
337void DockRegistry::unregisterDockWidget(DockWidgetBase *dock)
338{
339 if (m_focusedDockWidget == dock)
340 m_focusedDockWidget = nullptr;
341
342 m_dockWidgets.removeOne(dock);
343 m_sideBarGroupings->removeFromGroupings(dock);
344
345 maybeDelete();
346}
347
348void DockRegistry::registerMainWindow(MainWindowBase *mainWindow)
349{
350 if (mainWindow->uniqueName().isEmpty()) {
351 qWarning() << Q_FUNC_INFO << "MainWindow" << mainWindow << " doesn't have an ID";
352 } else if (auto other = mainWindowByName(mainWindow->uniqueName())) {
353 qWarning() << Q_FUNC_INFO << "Another MainWindow" << other << "with name" << mainWindow->uniqueName() << " already exists." << mainWindow;
354 }
355
356 m_mainWindows << mainWindow;
357}
358
359void DockRegistry::unregisterMainWindow(MainWindowBase *mainWindow)
360{
361 m_mainWindows.removeOne(mainWindow);
362 maybeDelete();
363}
364
365void DockRegistry::registerFloatingWindow(FloatingWindow *window)
366{
367 m_floatingWindows << window;
368}
369
370void DockRegistry::unregisterFloatingWindow(FloatingWindow *window)
371{
372 m_floatingWindows.removeOne(window);
373 maybeDelete();
374}
375
376void DockRegistry::registerLayout(LayoutWidget *layout)
377{
378 m_layouts << layout;
379}
380
381void DockRegistry::unregisterLayout(LayoutWidget *layout)
382{
383 m_layouts.removeOne(layout);
384}
385
386void DockRegistry::registerFrame(Frame *frame)
387{
388 m_frames << frame;
389}
390
391void DockRegistry::unregisterFrame(Frame *frame)
392{
393 m_frames.removeOne(frame);
394}
395
396DockWidgetBase *DockRegistry::focusedDockWidget() const
397{
398 return m_focusedDockWidget;
399}
400
401bool DockRegistry::containsDockWidget(const QString &uniqueName) const
402{
403 return dockByName(uniqueName) != nullptr;
404}
405
406bool DockRegistry::containsMainWindow(const QString &uniqueName) const
407{
408 return mainWindowByName(uniqueName) != nullptr;
409}
410
411DockWidgetBase *DockRegistry::dockByName(const QString &name, DockByNameFlags flags) const
412{
413 for (auto dock : qAsConst(m_dockWidgets)) {
414 if (dock->uniqueName() == name)
415 return dock;
416 }
417
418 if (flags.testFlag(DockByNameFlag::ConsultRemapping)) {
419 // Name doesn't exist, let's check if it was remapped during a layout restore.
420 const QString newName = m_dockWidgetIdRemapping.value(name);
421 if (!newName.isEmpty())
422 return dockByName(newName);
423 }
424
425 if (flags.testFlag(DockByNameFlag::CreateIfNotFound)) {
426 // DockWidget doesn't exist, ask to create it
427 if (auto factoryFunc = Config::self().dockWidgetFactoryFunc()) {
428 auto dw = factoryFunc(name);
429 if (dw && dw->uniqueName() != name) {
430 // Very special case
431 // The user's factory function returned a dock widget with a different ID.
432 // We support it. Save the mapping though.
433 m_dockWidgetIdRemapping.insert(name, dw->uniqueName());
434 }
435 return dw;
436 } else {
437 qWarning() << Q_FUNC_INFO << "Couldn't find dock widget" << name;
438 }
439 }
440
441 return nullptr;
442}
443
444MainWindowBase *DockRegistry::mainWindowByName(const QString &name) const
445{
446 for (auto mainWindow : qAsConst(m_mainWindows)) {
447 if (mainWindow->uniqueName() == name)
448 return mainWindow;
449 }
450
451 return nullptr;
452}
453
454MainWindowMDI *DockRegistry::mdiMainWindowByName(const QString &name) const
455{
456 return qobject_cast<MainWindowMDI *>(mainWindowByName(name));
457}
458
459DockWidgetBase *DockRegistry::dockWidgetForGuest(QWidgetOrQuick *guest) const
460{
461 if (!guest)
462 return nullptr;
463
464 for (DockWidgetBase *dw : m_dockWidgets) {
465 if (dw->widget() == guest)
466 return dw;
467 }
468
469 return nullptr;
470}
471
472bool DockRegistry::isSane() const
473{
474 QSet<QString> names;
475 for (auto dock : qAsConst(m_dockWidgets)) {
476 const QString name = dock->uniqueName();
477 if (name.isEmpty()) {
478 qWarning() << "DockRegistry::isSane: DockWidget" << dock << "is missing a name";
479 return false;
480 } else if (names.contains(name)) {
481 qWarning() << "DockRegistry::isSane: dockWidgets with duplicate names:" << name;
482 return false;
483 } else {
484 names.insert(name);
485 }
486 }
487
488 names.clear();
489 for (auto mainwindow : qAsConst(m_mainWindows)) {
490 const QString name = mainwindow->uniqueName();
491 if (name.isEmpty()) {
492 qWarning() << "DockRegistry::isSane: MainWindow" << mainwindow << "is missing a name";
493 return false;
494 } else if (names.contains(name)) {
495 qWarning() << "DockRegistry::isSane: mainWindow with duplicate names:" << name;
496 return false;
497 } else {
498 names.insert(name);
499 }
500
501 if (!mainwindow->layoutWidget()->checkSanity())
502 return false;
503 }
504
505 return true;
506}
507
508const DockWidgetBase::List DockRegistry::dockwidgets() const
509{
510 return m_dockWidgets;
511}
512
513const DockWidgetBase::List DockRegistry::dockWidgets(const QStringList &names)
514{
516 result.reserve(names.size());
517
518 for (auto dw : qAsConst(m_dockWidgets)) {
519 if (names.contains(dw->uniqueName()))
520 result.push_back(dw);
521 }
522
523 return result;
524}
525
526const MainWindowBase::List DockRegistry::mainWindows(const QStringList &names)
527{
529 result.reserve(names.size());
530
531 for (auto mw : qAsConst(m_mainWindows)) {
532 if (names.contains(mw->uniqueName()))
533 result.push_back(mw);
534 }
535
536 return result;
537}
538
539const DockWidgetBase::List DockRegistry::closedDockwidgets(bool honourSkipped) const
540{
542 result.reserve(m_dockWidgets.size());
543
544 for (DockWidgetBase *dw : m_dockWidgets) {
545 const bool shouldSkip = honourSkipped && (dw->layoutSaverOptions() & DockWidgetBase::LayoutSaverOption::Skip);
546 if (!shouldSkip && dw->parent() == nullptr && !dw->isVisible())
547 result.push_back(dw);
548 }
549
550 return result;
551}
552
553const MainWindowBase::List DockRegistry::mainwindows() const
554{
555 return m_mainWindows;
556}
557
558const QVector<LayoutWidget *> DockRegistry::layouts() const
559{
560 return m_layouts;
561}
562
563const Frame::List DockRegistry::frames() const
564{
565 return m_frames;
566}
567
568const QVector<FloatingWindow *> DockRegistry::floatingWindows(bool includeBeingDeleted, bool honourSkipped) const
569{
570 // Returns all the FloatingWindow which aren't being deleted
572 result.reserve(m_floatingWindows.size());
573 for (FloatingWindow *fw : m_floatingWindows) {
574 if (!includeBeingDeleted && fw->beingDeleted())
575 continue;
576
577 if (honourSkipped && fw->allDockWidgetsHave(DockWidgetBase::LayoutSaverOption::Skip))
578 continue;
579
580 result.push_back(fw);
581 }
582
583 return result;
584}
585
586const QVector<QWindow *> DockRegistry::floatingQWindows() const
587{
588 QVector<QWindow *> windows;
589 windows.reserve(m_floatingWindows.size());
590 for (FloatingWindow *fw : m_floatingWindows) {
591 if (!fw->beingDeleted()) {
592 if (QWindow *window = fw->windowHandle()) {
593 window->setProperty("kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick *>(fw)); // Since QWidgetWindow is private API
594 windows.push_back(window);
595 } else {
596 qWarning() << Q_FUNC_INFO << "FloatingWindow doesn't have QWindow";
597 }
598 }
599 }
600
601 return windows;
602}
603
604bool DockRegistry::hasFloatingWindows() const
605{
606 return std::any_of(m_floatingWindows.begin(), m_floatingWindows.end(), [](FloatingWindow *fw) {
607 return !fw->beingDeleted();
608 });
609}
610
611QWindow *DockRegistry::windowForHandle(WId id) const
612{
613 const QWindowList windows = qApp->topLevelWindows();
614 for (QWindow *w : windows) {
615 if (w->isVisible() && w->handle()) {
616 if (w->winId() == id)
617 return w;
618 }
619 }
620 return nullptr;
621}
622
623FloatingWindow *DockRegistry::floatingWindowForHandle(QWindow *windowHandle) const
624{
625 for (FloatingWindow *fw : m_floatingWindows) {
626 if (fw->windowHandle() == windowHandle)
627 return fw;
628 }
629
630 return nullptr;
631}
632
633FloatingWindow *DockRegistry::floatingWindowForHandle(WId hwnd) const
634{
635 for (FloatingWindow *fw : m_floatingWindows) {
636 if (fw->windowHandle() && fw->windowHandle()->winId() == hwnd)
637 return fw;
638 }
639
640 return nullptr;
641}
642
643MainWindowBase *DockRegistry::mainWindowForHandle(QWindow *windowHandle) const
644{
645 for (MainWindowBase *mw : m_mainWindows) {
646 if (mw->windowHandle() == windowHandle)
647 return mw;
648 }
649
650 return nullptr;
651}
652
653QWidgetOrQuick *DockRegistry::topLevelForHandle(QWindow *windowHandle) const
654{
655 if (auto fw = floatingWindowForHandle(windowHandle))
656 return fw;
657
658 if (auto mw = mainWindowForHandle(windowHandle))
659 return mw;
660
661 return nullptr;
662}
663
664QVector<QWindow *> DockRegistry::topLevels(bool excludeFloatingDocks) const
665{
666 QVector<QWindow *> windows;
667 windows.reserve(m_floatingWindows.size() + m_mainWindows.size());
668
669 if (!excludeFloatingDocks) {
670 for (FloatingWindow *fw : m_floatingWindows) {
671 if (fw->isVisible()) {
672 if (QWindow *window = fw->windowHandle()) {
673 window->setProperty("kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick *>(fw)); // Since QWidgetWindow is private API
674 windows << window;
675 } else {
676 qWarning() << Q_FUNC_INFO << "FloatingWindow doesn't have QWindow";
677 }
678 }
679 }
680 }
681
682 for (MainWindowBase *m : m_mainWindows) {
683 if (m->isVisible()) {
684 if (QWindow *window = m->window()->windowHandle()) {
685 window->setProperty("kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick *>(m));
686 windows << window;
687 } else {
688 qWarning() << Q_FUNC_INFO << "MainWindow doesn't have QWindow";
689 }
690 }
691 }
692
693 return windows;
694}
695
696void DockRegistry::clear(const QStringList &affinities)
697{
698 // Clears everything
699 clear(m_dockWidgets, m_mainWindows, affinities);
700}
701
702void DockRegistry::clear(const DockWidgetBase::List &dockWidgets,
703 const MainWindowBase::List &mainWindows,
704 const QStringList &affinities)
705{
706 for (auto dw : qAsConst(dockWidgets)) {
707 if (affinities.isEmpty() || affinitiesMatch(affinities, dw->affinities())) {
708 dw->forceClose();
709 dw->d->lastPosition()->removePlaceholders();
710 }
711 }
712
713 for (auto mw : qAsConst(mainWindows)) {
714 if (affinities.isEmpty() || affinitiesMatch(affinities, mw->affinities())) {
715 mw->layoutWidget()->clearLayout();
716 }
717 }
718}
719
720void DockRegistry::ensureAllFloatingWidgetsAreMorphed()
721{
722 for (DockWidgetBase *dw : qAsConst(m_dockWidgets)) {
723 if (dw->window() == dw && dw->isVisible())
724 dw->d->morphIntoFloatingWindow();
725 }
726}
727
728bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
729{
730 if (event->type() == QEvent::Quit && !m_isProcessingAppQuitEvent) {
731 m_isProcessingAppQuitEvent = true;
732 qApp->sendEvent(qApp, event);
733 m_isProcessingAppQuitEvent = false;
734 return true;
735 } else if (event->type() == QEvent::Expose) {
736 if (auto windowHandle = qobject_cast<QWindow *>(watched)) {
737 if (FloatingWindow *fw = floatingWindowForHandle(windowHandle)) {
738 // This floating window was exposed
739 m_floatingWindows.removeOne(fw);
740 m_floatingWindows.append(fw);
741 }
742 }
743 } else if (event->type() == QEvent::MouseButtonPress) {
744 // When clicking on a MDI Frame we raise the window
745 if (Frame *f = firstParentOfType<Frame>(watched)) {
746 if (f->isMDI())
747 f->raise();
748 }
749
750 // The following code is for hididng the overlay
752 return false;
753
754 if (qobject_cast<Frame *>(watched)) {
755 // break recursion
756 return false;
757 }
758
759 auto p = watched;
760 while (p) {
761 if (auto dw = qobject_cast<DockWidgetBase *>(p))
762 return onDockWidgetPressed(dw, static_cast<QMouseEvent *>(event));
763
764 if (auto layoutWidget = qobject_cast<LayoutWidget *>(p)) {
765 if (auto mw = layoutWidget->mainWindow()) {
766 // The user clicked somewhere in the main window's drop area, but outside of the
767 // overlayed dock widget
768 mw->clearSideBarOverlay();
769 return false;
770 }
771 }
772
773 p = p->parent();
774 }
775 }
776
777 return false;
778}
779
780bool DockRegistry::onDockWidgetPressed(DockWidgetBase *dw, QMouseEvent *ev)
781{
782 // Here we implement "auto-hide". If there's a overlayed dock widget, we hide it if some other
783 // dock widget is clicked.
784
785#ifdef KDDOCKWIDGETS_QTWIDGETS
786 // Don't be sending mouse events around if a popup is open, they are sensitive
787 if (qApp->activePopupWidget())
788 return false;
789#endif
790
791 MainWindowBase *mainWindow = dw->mainWindow();
792 if (!mainWindow) // Only docked widgets are interesting
793 return false;
794
795 if (DockWidgetBase *overlayedDockWidget = mainWindow->overlayedDockWidget()) {
796 ev->ignore();
797 qApp->sendEvent(overlayedDockWidget->d->frame(), ev);
798
799 if (ev->isAccepted()) {
800 // The Frame accepted it. It means the user is resizing it. We allow for 4px outside for better resize.
801 return true; // don't propagate the event further
802 }
803 if (dw != overlayedDockWidget) {
804 // User clicked outside if the overlay, then we close the overlay.
805 mainWindow->clearSideBarOverlay();
806 return false;
807 }
808 }
809
810 return false;
811}
812
813void DockRegistry::addSideBarGrouping(const DockWidgetBase::List &dws)
814{
815 m_sideBarGroupings->addGrouping(dws);
816}
817
818void DockRegistry::removeSideBarGrouping(const DockWidgetBase::List &dws)
819{
820 m_sideBarGroupings->removeGrouping(dws);
821}
822
823DockWidgetBase::List DockRegistry::sideBarGroupingFor(DockWidgetBase *dw) const
824{
825 return m_sideBarGroupings->groupingFor(dw);
826}
827
828void SideBarGroupings::addGrouping(const DockWidgetBase::List &dws)
829{
830 if (dws.size() < 2) {
831 // Simplification: A single dock widget is not considered to be grouped.
832 return;
833 }
834
835 m_groupings.push_back(dws);
836}
837
838void SideBarGroupings::removeGrouping(const DockWidgetBase::List &dws)
839{
840 m_groupings.removeAll(dws);
841}
842
843DockWidgetBase::List SideBarGroupings::groupingFor(DockWidgetBase *dw) const
844{
845 return const_cast<SideBarGroupings *>(this)->groupingByRef(dw);
846}
847
848void SideBarGroupings::removeFromGroupings(DockWidgetBase *dw)
849{
850 while (true) {
851 auto &grouping = groupingByRef(dw);
852 if (grouping.isEmpty())
853 return;
854 grouping.removeAll(dw);
855 }
856}
857
858DockWidgetBase::List &SideBarGroupings::groupingByRef(DockWidgetBase *dw)
859{
860 static DockWidgetBase::List empty;
861
862 for (auto &grouping : m_groupings) {
863 if (grouping.contains(dw))
864 return grouping;
865 }
866
867 return empty;
868}
Application-wide config to tune certain behaviours of the framework.
static void initKDDockWidgetResources()
The DockWidget base-class that's shared between QtWidgets and QtQuick stack.
MainWindow sub-class which uses MDI as a layout.
Abstraction for supporting both QtWidgets and QtQuick.
Namespace-level methods related to registering QML types.
static Config & self()
returns the singleton Config instance
Definition Config.cpp:84
The DockWidget base-class. DockWidget and DockWidgetBase are only split in two so we can share some c...
Q_INVOKABLE void forceClose()
Like QWidget::close() but the hosted widget won't be asked if we should close.
KDDockWidgets::DockWidgetBase::LayoutSaverOptions layoutSaverOptions() const
returns the per-dockwidget options which will affect LayoutSaver These are the options which were pas...
MainWindowBase * mainWindow() const
Returns the main window this dock widget is in. nullptr if it's not inside a main window Also returns...
void isFocusedChanged(bool)
emitted when isFocused changes
QStringList affinities() const
Returns the affinity name. Empty by default.
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
DockWidgetBase * overlayedDockWidget() const
returns the dock widget which is currently overlayed. nullptr if none. This is only relevant when usi...
Q_INVOKABLE void clearSideBarOverlay(bool deleteFrame=true)
closes any overlayed dock widget. The sidebar still displays them as button.
MainWindow sub-class which uses MDI as a layout.
SideBarLocation
Each main window supports 4 sidebars.
void registerQmlTypes()
Definition QmlTypes.cpp:26
bool isAccepted() const const
void ignore()
QEvent::Type type() const const
void focusObjectChanged(QObject *focusObject)
bool isEmpty() const const
void reserve(int alloc)
int size() const const
void installEventFilter(QObject *filterObj)
bool intersects(const QRect &rectangle) const const
void clear()
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
bool isEmpty() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void push_back(const T &value)
void reserve(int size)
int size() const const
QRect geometry() const const

© 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