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"
30 #include <QCloseEvent>
32 #include <QScopedValueRollback>
44 LayoutSaverOptions layoutSaverOptions)
45 : QWidgetAdapter(nullptr,
Qt::Tool)
46 , d(new Private(name, options, layoutSaverOptions, this))
49 DockRegistry::self()->registerDockWidget(
this);
52 qWarning() << Q_FUNC_INFO <<
"Name can't be null";
59 DockRegistry::self()->unregisterDockWidget(
this);
66 qWarning() << Q_FUNC_INFO <<
"Refusing to add dock widget into itself" << other;
71 qWarning() << Q_FUNC_INFO <<
"dock widget is null";
75 if (!DockRegistry::self()->affinitiesMatch(other->
affinities(), d->affinities)) {
76 qWarning() << Q_FUNC_INFO <<
"Refusing to dock widget with incompatible affinity."
82 qWarning() << Q_FUNC_INFO <<
"Refusing to dock non-dockable widget" << other;
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.";
93 Frame *frame = d->frame();
96 if (frame->containsDockWidget(other)) {
97 qWarning() << Q_FUNC_INFO <<
"Already contains" << other;
103 d->morphIntoFloatingWindow();
107 qWarning() << Q_FUNC_INFO <<
"null frame";
112 other->setParent(
nullptr);
113 frame->addWidget(other, option);
121 if (
auto mainWindow = qobject_cast<MainWindowBase *>(window())) {
127 if (!DockRegistry::self()->affinitiesMatch(other->
affinities(), d->affinities)) {
128 qWarning() << Q_FUNC_INFO <<
"Refusing to dock widget with incompatible affinity."
134 qWarning() << Q_FUNC_INFO <<
"Refusing to dock non-dockable widget" << other;
139 d->morphIntoFloatingWindow();
141 if (
auto fw = floatingWindow()) {
142 fw->addDockWidget(other, location, relativeTo, initialOption);
144 qWarning() << Q_FUNC_INFO <<
"Couldn't find floating nested window";
155 d->widget->setParent(
nullptr);
175 auto fw = floatingWindow();
176 return fw && fw->hasSingleDockWidget();
183 if (floats == alreadyFloating)
198 auto frame = d->frame();
200 qWarning() <<
"DockWidget::setFloating: Tabbed but no frame exists"
206 frame->detachTab(
this);
211 auto lastGeo = d->lastPosition()->lastFloatingGeometry();
212 if (lastGeo.isValid()) {
213 if (
auto fw = floatingWindow())
218 d->saveLastFloatingGeometry();
219 return d->restoreToPreviousPosition();
225 return d->toggleAction;
230 return d->floatAction;
240 if (d->isMDIWrapper()) {
242 auto dropAreaGuest = qobject_cast<DropArea *>(
widget());
243 Q_ASSERT(dropAreaGuest);
244 if (dropAreaGuest->hasSingleFrame()) {
245 return dropAreaGuest->frames().constFirst()->title();
247 return qApp->applicationName();
256 if (
title != d->title) {
265 if (
Frame *f = d->frame())
266 return f->QWidgetAdapter::geometry();
269 return QWidgetAdapter::geometry();
279 return d->layoutSaverOptions;
285 qWarning() << Q_FUNC_INFO <<
"Option_NotDockable not allowed to change. Pass via ctor only.";
299 if (
Frame *frame = d->frame()) {
300 return frame->alwaysShowsTabs() || frame->dockWidgetCount() > 1;
303 qWarning() <<
"DockWidget::isTabbed() Couldn't find any tab widget.";
310 if (
Frame *frame = d->frame()) {
311 return frame->currentIndex() == frame->indexOfDockWidget(
const_cast<DockWidgetBase *
>(
this));
319 if (
Frame *frame = d->frame())
320 frame->setCurrentDockWidget(
this);
325 if (
Frame *frame = d->frame())
326 return frame->indexOfDockWidget(
this);
333 if (
Frame *frame = d->frame())
334 return frame->currentTabIndex();
342 d->titleBarIcon =
icon;
345 d->tabBarIcon =
icon;
348 d->toggleAction->setIcon(
icon);
356 return d->titleBarIcon;
359 return d->tabBarIcon;
362 return d->toggleAction->icon();
374 if (
Frame *f = d->frame())
375 return f->actualTitleBar();
382 return d->toggleAction->isChecked();
387 return d->affinities;
392 if (isWindow() && (d->m_lastPosition->wasFloating() || !d->m_lastPosition->isValid())) {
395 d->morphIntoFloatingWindow();
408 if (
auto fw = floatingWindow()) {
410 fw->activateWindow();
411 }
else if (
Frame *frame = d->frame()) {
419 return qobject_cast<MainWindowBase *>(
widget());
424 return d->mainWindow() !=
nullptr;
429 return d->mainWindow();
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.";
464 m->moveToSideBar(
this);
470 return m->overlayedDockWidget() ==
this;
477 return DockRegistry::self()->sideBarLocationForDockWidget(
this);
487 return d->m_lastPosition->isValid();
492 return d->m_lastOverlayedSize;
497 return DockRegistry::self()->dockByName(
uniqueName);
508 window()->setGeometry(geometry);
510 d->m_lastPosition->setLastFloatingGeometry(geometry);
514 FloatingWindow *DockWidgetBase::Private::morphIntoFloatingWindow()
516 if (
auto fw = floatingWindow())
520 QRect geo = m_lastPosition->lastFloatingGeometry();
526 const QPoint center = defaultCenterPosForFloating();
527 if (!center.isNull())
535 FloatingWindow::ensureRectIsOnScreen(geo);
536 auto floatingWindow =
538 floatingWindow->show();
540 return floatingWindow;
546 void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
548 if (q->isWindow() && q->isVisible())
549 morphIntoFloatingWindow();
552 MDILayoutWidget *DockWidgetBase::Private::mdiLayout()
const
554 auto p =
const_cast<QObject *
>(q->parent());
556 if (qobject_cast<const QWindow *>(p)) {
561 if (qobject_cast<LayoutWidget *>(p)) {
563 if (
auto mdiLayout = qobject_cast<MDILayoutWidget *>(p)) {
566 }
else if (
auto dropArea = qobject_cast<DropArea *>(p)) {
569 if (!dropArea->isMDIWrapper())
582 bool DockWidgetBase::Private::isMDIWrapper()
const
584 return mdiDropAreaWrapper() !=
nullptr;
587 DropArea *DockWidgetBase::Private::mdiDropAreaWrapper()
const
589 if (
auto dropAreaGuest = qobject_cast<DropArea *>(q->widget())) {
590 if (dropAreaGuest->isMDIWrapper())
591 return dropAreaGuest;
597 DockWidgetBase *DockWidgetBase::Private::mdiDockWidgetWrapper()
const
599 if (isMDIWrapper()) {
604 auto p =
const_cast<QObject *
>(q->parent());
606 if (qobject_cast<const QWindow *>(p)) {
611 if (qobject_cast<LayoutWidget *>(p)) {
612 if (
auto dropArea = qobject_cast<DropArea *>(p)) {
613 if (dropArea->isMDIWrapper())
614 return dropArea->mdiDockWidgetWrapper();
626 DockWidgetBase::Private *DockWidgetBase::dptr()
const
631 QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
636 if (!mw || !q->isFloating())
642 bool DockWidgetBase::Private::eventFilter(
QObject *watched,
QEvent *event)
646 if ((isWindowActivate || isWindowDeactivate) && watched == q->window())
647 Q_EMIT q->windowActiveAboutToChange(isWindowActivate);
652 void DockWidgetBase::Private::updateTitle()
655 q->window()->setWindowTitle(title);
657 toggleAction->setText(title);
660 void DockWidgetBase::Private::toggle(
bool enabled)
662 if (SideBar *sb = sideBar()) {
664 sb->toggleOverlay(q);
675 void DockWidgetBase::Private::updateToggleAction()
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);
686 void DockWidgetBase::Private::updateFloatAction()
690 if (q->isFloating()) {
691 floatAction->setEnabled(m_lastPosition->isValid());
692 floatAction->setChecked(
true);
693 floatAction->setToolTip(tr(
"Dock"));
695 floatAction->setEnabled(
true);
696 floatAction->setChecked(
false);
697 floatAction->setToolTip(tr(
"Detach"));
701 void DockWidgetBase::Private::onDockWidgetShown()
703 updateToggleAction();
707 void DockWidgetBase::Private::onDockWidgetHidden()
709 updateToggleAction();
713 void DockWidgetBase::Private::close()
715 if (!m_processingToggleAction && !q->isOpen()) {
719 if (m_isPersistentCentralDockWidget)
723 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
724 auto mainWindow = sb->mainWindow();
725 if (mainWindow->overlayedDockWidget() == q) {
726 mainWindow->clearSideBarOverlay(
false);
730 if (!m_isForceClosing && q->isFloating()
734 m_lastPosition->setLastFloatingGeometry(q->window()->geometry());
740 if (Frame *frame = this->frame()) {
741 q->setParent(
nullptr);
742 frame->removeWidget(q);
744 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
745 sb->removeDockWidget(q);
750 Q_EMIT q->aboutToDeleteOnClose();
755 bool DockWidgetBase::Private::restoreToPreviousPosition()
757 if (!m_lastPosition->isValid())
760 Layouting::Item *item = m_lastPosition->lastItem();
762 LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
764 layout->restorePlaceholder(q, item, m_lastPosition->lastTabIndex());
768 void DockWidgetBase::Private::maybeRestoreToPreviousPosition()
772 if (!m_lastPosition->isValid())
775 Layouting::Item *layoutItem = m_lastPosition->lastItem();
779 if (m_lastPosition->wasFloating())
782 Frame *frame = this->frame();
784 if (frame && frame->QWidgetAdapter::parentWidget() == DockRegistry::self()->layoutForItem(layoutItem)) {
792 if (q->parentWidget()) {
798 restoreToPreviousPosition();
801 int DockWidgetBase::Private::currentTabIndex()
const
803 Frame *frame = this->frame();
804 return frame ? frame->indexOfDockWidget(q) : 0;
807 void DockWidgetBase::Private::saveTabIndex()
809 m_lastPosition->saveTabIndex(currentTabIndex(), q->isFloating());
812 void DockWidgetBase::Private::show()
820 #ifdef KDDOCKWIDGETS_QTWIDGETS
823 Q_EMIT QQuickItem::parentChanged(parentItem());
825 d->updateToggleAction();
826 d->updateFloatAction();
833 d->onDockWidgetShown();
836 if (
Frame *f = d->frame()) {
838 f->onDockWidgetShown(
this);
842 d->maybeRestoreToPreviousPosition();
850 d->onDockWidgetHidden();
853 if (
Frame *f = d->frame()) {
855 f->onDockWidgetHidden(
this);
863 if (
auto frame = d->frame()) {
864 d->m_lastOverlayedSize = frame->QWidgetAdapter::size();
866 qWarning() << Q_FUNC_INFO <<
"Overlayed dock widget without frame shouldn't happen";
870 return QWidgetAdapter::onResize(newSize);
877 qApp->sendEvent(d->widget, e);
883 DockWidgetBase *DockWidgetBase::deserialize(
const LayoutSaver::DockWidget::Ptr &saved)
885 auto dr = DockRegistry::self();
886 DockWidgetBase *dw = dr->dockByName(saved->uniqueName, DockRegistry::DockByNameFlag::CreateIfNotFound);
890 dw->setProperty(
"kddockwidget_was_restored",
true);
893 qWarning() << Q_FUNC_INFO <<
"Affinity name changed from" << dw->
affinities()
894 <<
"; to" << saved->affinities;
895 dw->d->affinities = saved->affinities;
909 return d->m_userType;
915 if (
auto wrapperDW = d->mdiDockWidgetWrapper()) {
917 layout->moveDockWidget(wrapperDW, pos);
919 layout->moveDockWidget(
this, pos);
927 if (
auto wrapperDW = d->mdiDockWidgetWrapper()) {
929 layout->resizeDockWidget(wrapperDW, size);
931 layout->resizeDockWidget(
this, size);
938 #ifdef KDDOCKWIDGETS_QTQUICK
939 if (
Frame *frame = d->frame()) {
946 qWarning() << Q_FUNC_INFO <<
"Not implemented for QtQuick";
952 return d->m_isPersistentCentralDockWidget;
955 LayoutSaver::DockWidget::Ptr DockWidgetBase::Private::serialize()
const
957 auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
958 ptr->affinities = q->affinities();
963 void DockWidgetBase::Private::forceClose()
969 DockWidgetBase::Private::Private(
const QString &dockName, DockWidgetBase::Options options_,
976 , layoutSaverOptions(layoutSaverOptions_)
981 if (!m_updatingToggleAction) {
985 m_processingToggleAction =
true;
988 m_processingToggleAction =
false;
993 if (!m_updatingFloatAction) {
994 q->setFloating(checked);
997 Q_EMIT q->isFloatingChanged(checked);
1000 if (checked && q->isOpen()) {
1001 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
1002 sb->mainWindow()->clearSideBarOverlay(
false);
1003 sb->removeDockWidget(q);
1011 qApp->installEventFilter(
this);
1014 void DockWidgetBase::Private::addPlaceholderItem(Layouting::Item *item)
1017 m_lastPosition->addPlaceholderItem(item);
1020 Position::Ptr &DockWidgetBase::Private::lastPosition()
1022 return m_lastPosition;
1025 Frame *DockWidgetBase::Private::frame()
const
1029 if (
auto frame = qobject_cast<Frame *>(p))
1036 void DockWidgetBase::Private::saveLastFloatingGeometry()
1038 if (q->isFloating() && q->isVisible()) {
1040 lastPosition()->setLastFloatingGeometry(q->window()->geometry());