KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
DockWidgetBase.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 "DockWidgetBase.h"
13#include "private/DockWidgetBase_p.h"
14#include "private/DockRegistry_p.h"
15#include "private/FloatingWindow_p.h"
16#include "private/Frame_p.h"
17#include "private/LayoutSaver_p.h"
18#include "private/Logging_p.h"
19#include "private/MDILayoutWidget_p.h"
20#include "private/SideBar_p.h"
21#include "private/TitleBar_p.h"
22#include "private/Utils_p.h"
23#include "private/WindowBeingDragged_p.h"
24#include "private/Position_p.h"
25
26#include "Config.h"
28
29#include <QEvent>
30#include <QCloseEvent>
31#include <QTimer>
32#include <QScopedValueRollback>
33
41using namespace KDDockWidgets;
42
43DockWidgetBase::DockWidgetBase(const QString &name, Options options,
44 LayoutSaverOptions layoutSaverOptions)
45 : QWidgetAdapter(nullptr, Qt::Tool)
46 , d(new Private(name, options, layoutSaverOptions, this))
47{
48 d->init();
49 DockRegistry::self()->registerDockWidget(this);
50
51 if (name.isEmpty())
52 qWarning() << Q_FUNC_INFO << "Name can't be null";
53
54 setAttribute(Qt::WA_PendingMoveEvent, false);
55}
56
58{
59 DockRegistry::self()->unregisterDockWidget(this);
60 delete d;
61}
62
64{
65 if (other == this) {
66 qWarning() << Q_FUNC_INFO << "Refusing to add dock widget into itself" << other;
67 return;
68 }
69
70 if (!other) {
71 qWarning() << Q_FUNC_INFO << "dock widget is null";
72 return;
73 }
74
75 if (!DockRegistry::self()->affinitiesMatch(other->affinities(), d->affinities)) {
76 qWarning() << Q_FUNC_INFO << "Refusing to dock widget with incompatible affinity."
77 << other->affinities() << affinities();
78 return;
79 }
80
82 qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << other;
83 return;
84 }
85
87 qWarning() << Q_FUNC_INFO << "Not supported with MainWindowOption_HasCentralWidget."
88 << "MainWindowOption_HasCentralWidget can only have 1 widget in the center."
89 << "Use MainWindowOption_HasCentralFrame instead, which is similar but supports tabbing.";
90 return;
91 }
92
93 Frame *frame = d->frame();
94
95 if (frame) {
96 if (frame->containsDockWidget(other)) {
97 qWarning() << Q_FUNC_INFO << "Already contains" << other;
98 return;
99 }
100 } else {
101 if (isWindow()) {
102 // Doesn't have a frame yet
103 d->morphIntoFloatingWindow();
104 frame = d->frame();
105 } else {
106 // Doesn't happen
107 qWarning() << Q_FUNC_INFO << "null frame";
108 return;
109 }
110 }
111
112 other->setParent(nullptr);
113 frame->addWidget(other, option);
114}
115
117 Location location,
118 DockWidgetBase *relativeTo,
119 InitialOption initialOption)
120{
121 if (auto mainWindow = qobject_cast<MainWindowBase *>(window())) {
122 // It's inside a main window. Simply use the main window API.
123 mainWindow->addDockWidget(other, location, relativeTo, initialOption);
124 return;
125 }
126
127 if (!DockRegistry::self()->affinitiesMatch(other->affinities(), d->affinities)) {
128 qWarning() << Q_FUNC_INFO << "Refusing to dock widget with incompatible affinity."
129 << other->affinities() << affinities();
130 return;
131 }
132
134 qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << other;
135 return;
136 }
137
138 if (isWindow())
139 d->morphIntoFloatingWindow();
140
141 if (auto fw = floatingWindow()) {
142 fw->addDockWidget(other, location, relativeTo, initialOption);
143 } else {
144 qWarning() << Q_FUNC_INFO << "Couldn't find floating nested window";
145 }
146}
147
149{
150 if (w == d->widget)
151 return;
152
153 if (d->widget) {
154 // Unparent the old widget, we're giving back ownership
155 d->widget->setParent(nullptr);
156 }
157
158 d->widget = w;
159 if (w)
160 setSizePolicy(w->sizePolicy());
161
162 Q_EMIT widgetChanged(w);
163}
164
166{
167 return d->widget;
168}
169
171{
172 if (isWindow())
173 return true;
174
175 auto fw = floatingWindow();
176 return fw && fw->hasSingleDockWidget();
177}
178
180{
181 const bool alreadyFloating = isFloating();
182
183 if (floats == alreadyFloating)
184 return true; // Nothing to do
185
186 if (!floats && (Config::self().internalFlags() & Config::InternalFlag_DontShowWhenUnfloatingHiddenWindow) && !isVisible()) {
187 // Mimics behaviour of QDockWidget, which you might need during porting.
188 // Not something we suggest though. For KDDW, setFloating(false) means dock, and that implies showing.
189 return false;
190 }
191
192 if (floats && isPersistentCentralDockWidget())
193 return false;
194
195 if (floats) {
196 d->saveTabIndex();
197 if (isTabbed()) {
198 auto frame = d->frame();
199 if (!frame) {
200 qWarning() << "DockWidget::setFloating: Tabbed but no frame exists"
201 << this;
202 Q_ASSERT(false);
203 return false;
204 }
205
206 frame->detachTab(this);
207 } else {
208 titleBar()->makeWindow();
209 }
210
211 auto lastGeo = d->lastPosition()->lastFloatingGeometry();
212 if (lastGeo.isValid()) {
213 if (auto fw = floatingWindow())
214 fw->setSuggestedGeometry(lastGeo, SuggestedGeometryHint_PreserveCenter);
215 }
216 return true;
217 } else {
218 d->saveLastFloatingGeometry();
219 return d->restoreToPreviousPosition();
220 }
221}
222
224{
225 return d->toggleAction;
226}
227
229{
230 return d->floatAction;
231}
232
234{
235 return d->name;
236}
237
239{
240 if (d->isMDIWrapper()) {
241 // It's just a wrapper to help implementing Option_MDINestable. Return the title of the real dock widget we're hosting.
242 auto dropAreaGuest = qobject_cast<DropArea *>(widget());
243 Q_ASSERT(dropAreaGuest);
244 if (dropAreaGuest->hasSingleFrame()) {
245 return dropAreaGuest->frames().constFirst()->title();
246 } else {
247 return qApp->applicationName();
248 }
249 }
250
251 return d->title;
252}
253
255{
256 if (title != d->title) {
257 d->title = title;
258 d->updateTitle();
259 Q_EMIT titleChanged(title);
260 }
261}
262
264{
265 if (Frame *f = d->frame())
266 return f->QWidgetAdapter::geometry();
267
268 // Means the dock widget isn't visible. Just fallback to its own geometry
269 return QWidgetAdapter::geometry();
270}
271
272DockWidgetBase::Options DockWidgetBase::options() const
273{
274 return d->options;
275}
276
277DockWidgetBase::LayoutSaverOptions DockWidgetBase::layoutSaverOptions() const
278{
279 return d->layoutSaverOptions;
280}
281
282void DockWidgetBase::setOptions(Options options)
283{
284 if ((d->options & Option_NotDockable) != (options & Option_NotDockable)) {
285 qWarning() << Q_FUNC_INFO << "Option_NotDockable not allowed to change. Pass via ctor only.";
286 return;
287 }
288
289 if (options != d->options) {
290 d->options = options;
291 Q_EMIT optionsChanged(options);
292 if (auto tb = titleBar())
293 tb->updateButtons();
294 }
295}
296
298{
299 if (Frame *frame = d->frame()) {
300 return frame->alwaysShowsTabs() || frame->dockWidgetCount() > 1;
301 } else {
302 if (!isFloating())
303 qWarning() << "DockWidget::isTabbed() Couldn't find any tab widget.";
304 return false;
305 }
306}
307
309{
310 if (Frame *frame = d->frame()) {
311 return frame->currentIndex() == frame->indexOfDockWidget(const_cast<DockWidgetBase *>(this));
312 } else {
313 return true;
314 }
315}
316
318{
319 if (Frame *frame = d->frame())
320 frame->setCurrentDockWidget(this);
321}
322
324{
325 if (Frame *frame = d->frame())
326 return frame->indexOfDockWidget(this);
327
328 return 0;
329}
330
332{
333 if (Frame *frame = d->frame())
334 return frame->currentTabIndex();
335
336 return 0;
337}
338
339void DockWidgetBase::setIcon(const QIcon &icon, IconPlaces places)
340{
341 if (places & IconPlace::TitleBar)
342 d->titleBarIcon = icon;
343
344 if (places & IconPlace::TabBar)
345 d->tabBarIcon = icon;
346
347 if (places & IconPlace::ToggleAction)
348 d->toggleAction->setIcon(icon);
349
350 Q_EMIT iconChanged();
351}
352
354{
355 if (place == IconPlace::TitleBar)
356 return d->titleBarIcon;
357
358 if (place == IconPlace::TabBar)
359 return d->tabBarIcon;
360
361 if (place == IconPlace::ToggleAction)
362 return d->toggleAction->icon();
363
364 return {};
365}
366
368{
369 d->forceClose();
370}
371
373{
374 if (Frame *f = d->frame())
375 return f->actualTitleBar();
376
377 return nullptr;
378}
379
381{
382 return d->toggleAction->isChecked();
383}
384
386{
387 return d->affinities;
388}
389
391{
392 if (isWindow() && (d->m_lastPosition->wasFloating() || !d->m_lastPosition->isValid())) {
393 // Create the FloatingWindow already, instead of waiting for the show event.
394 // This reduces flickering on some platforms
395 d->morphIntoFloatingWindow();
396 } else {
398 }
399}
400
402{
403 if (!isOpen())
404 return;
405
407
408 if (auto fw = floatingWindow()) {
409 fw->raise();
410 fw->activateWindow();
411 } else if (Frame *frame = d->frame()) {
412 if (frame->isMDI())
413 frame->raise();
414 }
415}
416
418{
419 return qobject_cast<MainWindowBase *>(widget());
420}
421
423{
424 return d->mainWindow() != nullptr;
425}
426
428{
429 return d->mainWindow();
430}
431
433{
434 auto f = d->frame();
435 return f && f->isFocused() && isCurrentTab();
436}
437
439{
440 setAffinities({ affinity });
441}
442
444{
445 QStringList affinities = affinityNames;
447
448 if (d->affinities == affinities)
449 return;
450
451 if (!d->affinities.isEmpty()) {
452 qWarning() << Q_FUNC_INFO
453 << "Affinity is already set, refusing to change."
454 << "Submit a feature request with a good justification.";
455 return;
456 }
457
458 d->affinities = affinities;
459}
460
462{
463 if (MainWindowBase *m = mainWindow())
464 m->moveToSideBar(this);
465}
466
468{
469 if (MainWindowBase *m = mainWindow())
470 return m->overlayedDockWidget() == this;
471
472 return false;
473}
474
476{
477 return DockRegistry::self()->sideBarLocationForDockWidget(this);
478}
479
484
486{
487 return d->m_lastPosition->isValid();
488}
489
491{
492 return d->m_lastOverlayedSize;
493}
494
496{
497 return DockRegistry::self()->dockByName(uniqueName);
498}
499
501{
502 return d->layoutSaverOptions & LayoutSaverOption::Skip;
503}
504
506{
507 if (isOpen() && isFloating()) {
508 window()->setGeometry(geometry);
509 } else {
510 d->m_lastPosition->setLastFloatingGeometry(geometry);
511 }
512}
513
514FloatingWindow *DockWidgetBase::Private::morphIntoFloatingWindow()
515{
516 if (auto fw = floatingWindow())
517 return fw; // Nothing to do
518
519 if (q->isWindow()) {
520 QRect geo = m_lastPosition->lastFloatingGeometry();
521 if (geo.isNull()) {
522 geo = q->geometry();
523
524 if (!q->testAttribute(Qt::WA_PendingMoveEvent)) { // If user already moved it, we don't
525 // interfere
526 const QPoint center = defaultCenterPosForFloating();
527 if (!center.isNull())
528 geo.moveCenter(center);
529 }
530 }
531
533 frame->addWidget(q);
534 geo.setSize(geo.size().boundedTo(frame->maxSizeHint()));
535 FloatingWindow::ensureRectIsOnScreen(geo);
536 auto floatingWindow =
538 floatingWindow->show();
539
540 return floatingWindow;
541 } else {
542 return nullptr;
543 }
544}
545
546void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
547{
548 if (q->isWindow() && q->isVisible())
549 morphIntoFloatingWindow();
550}
551
552MDILayoutWidget *DockWidgetBase::Private::mdiLayout() const
553{
554 auto p = const_cast<QObject *>(q->parent());
555 while (p) {
556 if (qobject_cast<const QWindow *>(p)) {
557 // Ignore QObject hierarchies spanning though multiple windows
558 return nullptr;
559 }
560
561 if (qobject_cast<LayoutWidget *>(p)) {
562 // We found a layout
563 if (auto mdiLayout = qobject_cast<MDILayoutWidget *>(p)) {
564 // And it's MDI
565 return mdiLayout;
566 } else if (auto dropArea = qobject_cast<DropArea *>(p)) {
567 // It's a DropArea. But maybe it's a drop area that's just helping
568 // making the MDI windows accept drops (Option_MDINestable)
569 if (!dropArea->isMDIWrapper())
570 return nullptr;
571
572 // It's a MDI wrapper, keep looking up.
573 }
574 }
575
576 p = p->parent();
577 }
578
579 return nullptr;
580}
581
582bool DockWidgetBase::Private::isMDIWrapper() const
583{
584 return mdiDropAreaWrapper() != nullptr;
585}
586
587DropArea *DockWidgetBase::Private::mdiDropAreaWrapper() const
588{
589 if (auto dropAreaGuest = qobject_cast<DropArea *>(q->widget())) {
590 if (dropAreaGuest->isMDIWrapper())
591 return dropAreaGuest;
592 }
593
594 return nullptr;
595}
596
597DockWidgetBase *DockWidgetBase::Private::mdiDockWidgetWrapper() const
598{
599 if (isMDIWrapper()) {
600 // We are the wrapper
601 return q;
602 }
603
604 auto p = const_cast<QObject *>(q->parent());
605 while (p) {
606 if (qobject_cast<const QWindow *>(p)) {
607 // Ignore QObject hierarchies spanning though multiple windows
608 return nullptr;
609 }
610
611 if (qobject_cast<LayoutWidget *>(p)) {
612 if (auto dropArea = qobject_cast<DropArea *>(p)) {
613 if (dropArea->isMDIWrapper())
614 return dropArea->mdiDockWidgetWrapper();
615 }
616
617 return nullptr;
618 }
619
620 p = p->parent();
621 }
622
623 return nullptr;
624}
625
626DockWidgetBase::Private *DockWidgetBase::dptr() const
627{
628 return d;
629}
630
631QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
632{
633 MainWindowBase::List mainWindows = DockRegistry::self()->mainwindows();
634 // We don't care about multiple mainwindows yet. Or, let's just say that the first one is more main than the others
635 MainWindowBase *mw = mainWindows.isEmpty() ? nullptr : mainWindows.constFirst();
636 if (!mw || !q->isFloating())
637 return {};
638
639 return mw->geometry().center();
640}
641
642bool DockWidgetBase::Private::eventFilter(QObject *watched, QEvent *event)
643{
644 const bool isWindowActivate = event->type() == QEvent::WindowActivate;
645 const bool isWindowDeactivate = event->type() == QEvent::WindowDeactivate;
646 if ((isWindowActivate || isWindowDeactivate) && watched == q->window())
647 Q_EMIT q->windowActiveAboutToChange(isWindowActivate);
648
649 return QObject::eventFilter(watched, event);
650}
651
652void DockWidgetBase::Private::updateTitle()
653{
654 if (q->isFloating())
655 q->window()->setWindowTitle(title);
656
657 toggleAction->setText(title);
658}
659
660void DockWidgetBase::Private::toggle(bool enabled)
661{
662 if (SideBar *sb = sideBar()) {
663 // The widget is in the sidebar, let's toggle its overlayed state
664 sb->toggleOverlay(q);
665 } else {
666 // The most common case. The dock widget is not in the sidebar. just close or open it.
667 if (enabled) {
668 show();
669 } else {
670 q->close();
671 }
672 }
673}
674
675void DockWidgetBase::Private::updateToggleAction()
676{
677 QScopedValueRollback<bool> recursionGuard(m_updatingToggleAction, true); // Guard against recursiveness
678 m_updatingToggleAction = true;
679 if ((q->isVisible() || frame()) && !toggleAction->isChecked()) {
680 toggleAction->setChecked(true);
681 } else if ((!q->isVisible() && !frame()) && toggleAction->isChecked()) {
682 toggleAction->setChecked(false);
683 }
684}
685
686void DockWidgetBase::Private::updateFloatAction()
687{
688 QScopedValueRollback<bool> recursionGuard(m_updatingFloatAction, true); // Guard against recursiveness
689
690 if (q->isFloating()) {
691 floatAction->setEnabled(m_lastPosition->isValid());
692 floatAction->setChecked(true);
693 floatAction->setToolTip(tr("Dock"));
694 } else {
695 floatAction->setEnabled(true);
696 floatAction->setChecked(false);
697 floatAction->setToolTip(tr("Detach"));
698 }
699}
700
701void DockWidgetBase::Private::onDockWidgetShown()
702{
703 updateToggleAction();
704 updateFloatAction();
705}
706
707void DockWidgetBase::Private::onDockWidgetHidden()
708{
709 updateToggleAction();
710 updateFloatAction();
711}
712
713void DockWidgetBase::Private::close()
714{
715 if (!m_processingToggleAction && !q->isOpen()) {
716 return;
717 }
718
719 if (m_isPersistentCentralDockWidget)
720 return;
721
722 // If it's overlayed and we're closing, we need to close the overlay
723 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
724 auto mainWindow = sb->mainWindow();
725 if (mainWindow->overlayedDockWidget() == q) {
726 mainWindow->clearSideBarOverlay(/* deleteFrame=*/false);
727 }
728 }
729
730 if (!m_isForceClosing && q->isFloating()
731 && q->isVisible()) { // only user-closing is interesting to save the geometry
732 // We check for isVisible so we don't save geometry if you call close() on an already closed
733 // dock widget
734 m_lastPosition->setLastFloatingGeometry(q->window()->geometry());
735 }
736
737 saveTabIndex();
738
739 // Do some cleaning. Widget is hidden, but we must hide the tab containing it.
740 if (Frame *frame = this->frame()) {
741 q->setParent(nullptr);
742 frame->removeWidget(q);
743
744 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
745 sb->removeDockWidget(q);
746 }
747 }
748
749 if (!m_isMovingToSideBar && (options & DockWidgetBase::Option_DeleteOnClose)) {
750 Q_EMIT q->aboutToDeleteOnClose();
751 q->deleteLater();
752 }
753}
754
755bool DockWidgetBase::Private::restoreToPreviousPosition()
756{
757 if (!m_lastPosition->isValid())
758 return false;
759
760 Layouting::Item *item = m_lastPosition->lastItem();
761
762 LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
763 Q_ASSERT(layout);
764 layout->restorePlaceholder(q, item, m_lastPosition->lastTabIndex());
765 return true;
766}
767
768void DockWidgetBase::Private::maybeRestoreToPreviousPosition()
769{
770 // This is called when we get a QEvent::Show. Let's see if we have to restore it to a previous position.
771
772 if (!m_lastPosition->isValid())
773 return;
774
775 Layouting::Item *layoutItem = m_lastPosition->lastItem();
776 if (!layoutItem)
777 return; // nothing to do, no last position
778
779 if (m_lastPosition->wasFloating())
780 return; // Nothing to do, it was floating before, now it'll just get visible
781
782 Frame *frame = this->frame();
783
784 if (frame && frame->QWidgetAdapter::parentWidget() == DockRegistry::self()->layoutForItem(layoutItem)) {
785 // There's a frame already. Means the DockWidget was hidden instead of closed.
786 // Nothing to do, the dock widget will simply be shown
787 return;
788 }
789
790 // Now we deal with the case where the DockWidget was close()ed. In this case it doesn't have a parent.
791
792 if (q->parentWidget()) {
793 // The QEvent::Show is due to it being made floating. Nothing to restore.
794 return;
795 }
796
797 // Finally, restore it
798 restoreToPreviousPosition();
799}
800
801int DockWidgetBase::Private::currentTabIndex() const
802{
803 Frame *frame = this->frame();
804 return frame ? frame->indexOfDockWidget(q) : 0;
805}
806
807void DockWidgetBase::Private::saveTabIndex()
808{
809 m_lastPosition->saveTabIndex(currentTabIndex(), q->isFloating());
810}
811
812void DockWidgetBase::Private::show()
813{
814 // Only show for now
815 q->show();
816}
817
819{
820#ifdef KDDOCKWIDGETS_QTWIDGETS
821 Q_EMIT parentChanged();
822#else
823 Q_EMIT QQuickItem::parentChanged(parentItem());
824#endif
825 d->updateToggleAction();
826 d->updateFloatAction();
827
828 Q_EMIT actualTitleBarChanged();
829}
830
831void DockWidgetBase::onShown(bool spontaneous)
832{
833 d->onDockWidgetShown();
834 Q_EMIT shown();
835
836 if (Frame *f = d->frame()) {
837 if (!spontaneous) {
838 f->onDockWidgetShown(this);
839 }
840 }
841
842 d->maybeRestoreToPreviousPosition();
843
844 // Transform into a FloatingWindow if this will be a regular floating dock widget.
845 QTimer::singleShot(0, d, &DockWidgetBase::Private::maybeMorphIntoFloatingWindow);
846}
847
848void DockWidgetBase::onHidden(bool spontaneous)
849{
850 d->onDockWidgetHidden();
851 Q_EMIT hidden();
852
853 if (Frame *f = d->frame()) {
854 if (!spontaneous) {
855 f->onDockWidgetHidden(this);
856 }
857 }
858}
859
861{
862 if (isOverlayed()) {
863 if (auto frame = d->frame()) {
864 d->m_lastOverlayedSize = frame->QWidgetAdapter::size();
865 } else {
866 qWarning() << Q_FUNC_INFO << "Overlayed dock widget without frame shouldn't happen";
867 }
868 }
869
870 return QWidgetAdapter::onResize(newSize);
871}
872
874{
875 e->accept(); // By default we accept, means DockWidget closes
876 if (d->widget)
877 qApp->sendEvent(d->widget, e); // Give a chance for the widget to ignore
878
879 if (e->isAccepted())
880 d->close();
881}
882
883DockWidgetBase *DockWidgetBase::deserialize(const LayoutSaver::DockWidget::Ptr &saved)
884{
885 auto dr = DockRegistry::self();
886 DockWidgetBase *dw = dr->dockByName(saved->uniqueName, DockRegistry::DockByNameFlag::CreateIfNotFound);
887 if (dw) {
888 if (QWidgetOrQuick *w = dw->widget())
889 w->setVisible(true);
890 dw->setProperty("kddockwidget_was_restored", true);
891
892 if (dw->affinities() != saved->affinities) {
893 qWarning() << Q_FUNC_INFO << "Affinity name changed from" << dw->affinities()
894 << "; to" << saved->affinities;
895 dw->d->affinities = saved->affinities;
896 }
897 }
898
899 return dw;
900}
901
903{
904 d->m_userType = userType;
905}
906
908{
909 return d->m_userType;
910}
911
913{
914 if (MDILayoutWidget *layout = d->mdiLayout()) {
915 if (auto wrapperDW = d->mdiDockWidgetWrapper()) {
916 // Case of using Option_MDINestable. We need to layout the actual top level DW
917 layout->moveDockWidget(wrapperDW, pos);
918 } else {
919 layout->moveDockWidget(this, pos);
920 }
921 }
922}
923
925{
926 if (MDILayoutWidget *layout = d->mdiLayout()) {
927 if (auto wrapperDW = d->mdiDockWidgetWrapper()) {
928 // Case of using Option_MDINestable. We need to layout the actual top level DW
929 layout->resizeDockWidget(wrapperDW, size);
930 } else {
931 layout->resizeDockWidget(this, size);
932 }
933 }
934}
935
937{
938#ifdef KDDOCKWIDGETS_QTQUICK
939 if (Frame *frame = d->frame()) {
940 if (!frame->isMDI())
941 return;
942 frame->setZ(z);
943 }
944#else
945 Q_UNUSED(z);
946 qWarning() << Q_FUNC_INFO << "Not implemented for QtQuick";
947#endif
948}
949
951{
952 return d->m_isPersistentCentralDockWidget;
953}
954
955LayoutSaver::DockWidget::Ptr DockWidgetBase::Private::serialize() const
956{
957 auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
958 ptr->affinities = q->affinities();
959
960 return ptr;
961}
962
963void DockWidgetBase::Private::forceClose()
964{
965 QScopedValueRollback<bool> rollback(m_isForceClosing, true);
966 close();
967}
968
969DockWidgetBase::Private::Private(const QString &dockName, DockWidgetBase::Options options_,
970 LayoutSaverOptions layoutSaverOptions_, DockWidgetBase *qq)
971
972 : name(dockName)
973 , title(dockName)
974 , q(qq)
975 , options(options_)
976 , layoutSaverOptions(layoutSaverOptions_)
977 , toggleAction(new QAction(q))
978 , floatAction(new QAction(q))
979{
980 q->connect(toggleAction, &QAction::toggled, q, [this](bool enabled) {
981 if (!m_updatingToggleAction) { // guard against recursiveness
982 toggleAction->blockSignals(true); // and don't emit spurious toggle. Like when a dock
983 // widget is inserted into a tab widget it might get
984 // hide events, ignore those. The Dock Widget is open.
985 m_processingToggleAction = true;
986 toggle(enabled);
988 m_processingToggleAction = false;
989 }
990 });
991
992 q->connect(floatAction, &QAction::toggled, q, [this](bool checked) {
993 if (!m_updatingFloatAction) { // guard against recursiveness
994 q->setFloating(checked);
995 }
996
997 Q_EMIT q->isFloatingChanged(checked);
998
999 // When floating, we remove from the sidebar
1000 if (checked && q->isOpen()) {
1001 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
1002 sb->mainWindow()->clearSideBarOverlay(/* deleteFrame=*/false);
1003 sb->removeDockWidget(q);
1004 }
1005 }
1006 });
1007
1010
1011 qApp->installEventFilter(this);
1012}
1013
1014void DockWidgetBase::Private::addPlaceholderItem(Layouting::Item *item)
1015{
1016 Q_ASSERT(item);
1017 m_lastPosition->addPlaceholderItem(item);
1018}
1019
1020Position::Ptr &DockWidgetBase::Private::lastPosition()
1021{
1022 return m_lastPosition;
1023}
1024
1025Frame *DockWidgetBase::Private::frame() const
1026{
1027 QWidgetOrQuick *p = q->parentWidget();
1028 while (p) {
1029 if (auto frame = qobject_cast<Frame *>(p))
1030 return frame;
1031 p = p->parentWidget();
1032 }
1033 return nullptr;
1034}
1035
1036void DockWidgetBase::Private::saveLastFloatingGeometry()
1037{
1038 if (q->isFloating() && q->isVisible()) {
1039 // It's getting docked, save last floating position
1040 lastPosition()->setLastFloatingGeometry(q->window()->geometry());
1041 }
1042}
1043
1044void DockWidgetBase::setFloatingWindowFlags(FloatingWindowFlags flags)
1045{
1046 if (floatingWindow()) {
1047 qWarning() << Q_FUNC_INFO << "Call this function only before having a floating window";
1048 } else {
1049 d->m_flags = flags;
1050 }
1051}
1052
1053KDDockWidgets::FloatingWindowFlags DockWidgetBase::floatingWindowFlags() const
1054{
1055 return d->m_flags;
1056}
Application-wide config to tune certain behaviours of the framework.
The DockWidget base-class that's shared between QtWidgets and QtQuick stack.
A factory class for allowing the user to customize some internal widgets.
@ InternalFlag_DontShowWhenUnfloatingHiddenWindow
DockWidget::setFloating(false) won't do anything if the window is hidden.
Definition Config.h:135
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
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.
virtual void setWidget(QWidgetOrQuick *widget)
sets the widget which this dock widget hosts.
Q_INVOKABLE void addDockWidgetAsTab(KDDockWidgets::DockWidgetBase *other, KDDockWidgets::InitialOption initialOption={})
docks other widget into this one. Tabs will be shown if not already.
void onHidden(bool spontaneous)
void setOptions(Options)
Setter for the options. Only Option_NotClosable is allowed to change after construction....
Q_INVOKABLE void setAsCurrentTab()
Makes this dock widget current in its tab group.
bool isInSideBar() const
Returns where this dockwidget is in a sidebar Similar to sideBarLocation(), but returns a bool.
void setMDIZ(int z)
like setMDIPosition(), but for the Z only implemented for QtQuick
QSize lastOverlayedSize() const
returns the last size the widget has when overlayed Empty otherwise
~DockWidgetBase() override
destructor
void widgetChanged(KDDockWidgets::QWidgetOrQuick *)
emitted when the hosted widget changed
void optionsChanged(KDDockWidgets::DockWidgetBase::Options)
emitted when the options change
KDDockWidgets::DockWidgetBase::LayoutSaverOptions layoutSaverOptions() const
returns the per-dockwidget options which will affect LayoutSaver These are the options which were pas...
QIcon icon(IconPlace place=IconPlace::TitleBar) const
Returns the dock widget's titlebar, tabbar, or toggle action icon (depending on the passed place)
int tabIndex() const
Returns the tab index this dock widget occupies Note that dock widgets are almost always tabbed,...
void parentChanged()
signal emitted when the parent changed QtQuick already has QQuickItem::parentChanged(),...
KDDockWidgets::DockWidgetBase::Options options
KDDockWidgets::FloatingWindowFlags floatingWindowFlags() const
bool isMainWindow() const
Returns whether widget() is a KDDockWidget::MainWindow.
void setUserType(int userType)
Allows the user to set a type on this dock widget The type is opaque and will not be interpreted by K...
QRect frameGeometry() const
Returns the size of the dock widget's parent frame.
bool onResize(QSize newSize) override
Q_INVOKABLE QAction * toggleAction() const
Returns the QAction that allows to hide/show the dock widget Useful to put in menus.
bool hasPreviousDockedLocation() const
Returns whether this floating dock widget knows its previous docked location Result only makes sense ...
void setMDISize(QSize size)
like setMDIPosition(), but for the size.
void setFloatingWindowFlags(FloatingWindowFlags)
Sets the desired floating window flags, in case the defaults aren't desired. By default KDDW will use...
Q_INVOKABLE QAction * floatAction() const
Returns the QAction that allows to dock/undock the dock widget Useful to put in menus.
bool setFloating(bool floats)
setter to make the dock widget float or dock.
void setIcon(const QIcon &icon, IconPlaces places=IconPlace::All)
Sets an icon to show on title bars and tab bars.
Q_INVOKABLE void moveToSideBar()
Minimizes this dock widget to the MainWindow's side-bar.
void setTitle(const QString &title)
setter for the dock widget's title
void setAffinityName(const QString &name)
bool isInMainWindow() const
Returns whether this dock widget is docked into a main window (as opposed to floating)
Q_INVOKABLE void addDockWidgetToContainingWindow(KDDockWidgets::DockWidgetBase *other, KDDockWidgets::Location location, KDDockWidgets::DockWidgetBase *relativeTo=nullptr, KDDockWidgets::InitialOption initialOption={})
docks other widget into the window that contains this one. Equivalent to MainWindow::addDockWidget() ...
Q_INVOKABLE void raise()
Brings the dock widget to the front.
bool isCurrentTab() const
Returns true if this dock widget is the current one in the tab widget that contains it....
bool isTabbed() const
returns if this dock widget is tabbed into another
MainWindowBase * mainWindow() const
Returns the main window this dock widget is in. nullptr if it's not inside a main window Also returns...
void shown()
signal emitted when the DockWidget is shown. As in QEvent::Show.
void onCloseEvent(QCloseEvent *e) override
SideBarLocation sideBarLocation() const
Returns whether this dock widget is in a side bar, and which. SideBarLocation::None is returned if it...
bool skipsRestore() const
Returns whether this widget has the LayoutSaverOption::Skip flag.
Q_INVOKABLE void show()
Equivalent to QWidget::show(), but it's optimized to reduce flickering on some platforms.
static DockWidgetBase * byName(const QString &uniqueName)
Returns a dock widget by its name This is the same name you passed to DockWidget CTOR....
Q_INVOKABLE bool isOpen() const
Returns whether this dock widget is open. Equivalent to calling toggleAction().isChecked() or isVisib...
QStringList affinities() const
Returns the affinity name. Empty by default.
TitleBar * titleBar() const
Returns this dock widget's title bar.
@ Skip
The dock widget won't participate in save/restore. Currently only available for floating windows.
bool isPersistentCentralDockWidget() const
Returns whether this dock widget is the main window persistent central widget This only applies when ...
void onShown(bool spontaneous)
void hidden()
signal emitted when the DockWidget is hidden. As in QEvent::Hide.
bool isOverlayed() const
Returns whether this dock widget is overlayed from the side-bar.
void setFloatingGeometry(QRect geo)
If this dock widget is floating, then sets its geometry to geo.
void actualTitleBarChanged()
Emitted when the title bar that serves this dock widget changes.
@ Option_NotDockable
The DockWidget can't be docked, it's always floating.
@ Option_DeleteOnClose
Deletes the DockWidget when closed.
int currentTabIndex() const
Returns the index of the current tab of the tab group this dock widget is in.
void setAffinities(const QStringList &)
Sets the affinity names. Dock widgets can only dock into dock widgets of the same affinity.
void setMDIPosition(QPoint pos)
Sets this dock widgets position to pos within the MDI layout This only applies if the main window is ...
DockWidgetBase(const QString &uniqueName, Options options=KDDockWidgets::DockWidgetBase::Options(), LayoutSaverOptions layoutSaverOptions=KDDockWidgets::DockWidgetBase::LayoutSaverOptions())
constructs a new DockWidget
void titleChanged(const QString &title)
signal emitted when the title changed
void iconChanged()
signal emitted when the icon changed
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...
virtual Frame * createFrame(QWidgetOrQuick *parent=nullptr, FrameOptions options=FrameOption_None) const =0
Called internally by the framework to create a Frame class Override to provide your own Frame sub-cla...
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
Q_INVOKABLE void addDockWidget(KDDockWidgets::DockWidgetBase *dockWidget, KDDockWidgets::Location location, KDDockWidgets::DockWidgetBase *relativeTo=nullptr, KDDockWidgets::InitialOption initialOption={})
Docks a DockWidget into this main window.
@ SuggestedGeometryHint_PreserveCenter
SideBarLocation
Each main window supports 4 sidebars.
void setCheckable(bool)
void toggled(bool checked)
void accept()
bool isAccepted() const const
int removeAll(const T &value)
bool blockSignals(bool block)
virtual bool eventFilter(QObject *watched, QEvent *event)
QObject * parent() const const
bool isNull() const const
void moveCenter(const QPoint &position)
void setSize(const QSize &size)
QSize size() const const
QSize boundedTo(const QSize &otherSize) const const
bool isEmpty() const const
WA_PendingMoveEvent
const T & constFirst() const const
bool isEmpty() const const
QWidget * parentWidget() const const
void show()
Struct describing the preferred dock widget size and visibility when adding it to a layout.

© 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