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) || (!floats && !alreadyFloating))
198 auto frame = d->frame();
200 qWarning() <<
"DockWidget::setFloating: Tabbed but no frame exists"
206 frame->detachTab(
this);
208 d->frame()->titleBar()->makeWindow();
211 auto lastGeo = d->lastPositions().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;
245 if (
title != d->title) {
254 if (
Frame *f = d->frame())
255 return f->QWidgetAdapter::geometry();
258 return QWidgetAdapter::geometry();
268 return d->layoutSaverOptions;
274 qWarning() << Q_FUNC_INFO <<
"Option_NotDockable not allowed to change. Pass via ctor only.";
288 if (
Frame *frame = d->frame()) {
289 return frame->alwaysShowsTabs() || frame->dockWidgetCount() > 1;
292 qWarning() <<
"DockWidget::isTabbed() Couldn't find any tab widget.";
299 if (
Frame *frame = d->frame()) {
300 return frame->currentIndex() == frame->indexOfDockWidget(
const_cast<DockWidgetBase *
>(
this));
308 if (
Frame *frame = d->frame())
309 frame->setCurrentDockWidget(
this);
314 if (
Frame *frame = d->frame())
315 return frame->indexOfDockWidget(
this);
323 d->titleBarIcon =
icon;
326 d->tabBarIcon =
icon;
329 d->toggleAction->setIcon(
icon);
337 return d->titleBarIcon;
340 return d->tabBarIcon;
343 return d->toggleAction->icon();
355 if (
Frame *f = d->frame())
356 return f->actualTitleBar();
363 return d->toggleAction->isChecked();
368 return d->affinities;
373 if (isWindow() && (d->m_lastPositions.wasFloating() || !d->m_lastPositions.isValid())) {
376 d->morphIntoFloatingWindow();
389 if (
auto fw = floatingWindow()) {
391 fw->activateWindow();
392 }
else if (
Frame *frame = d->frame()) {
400 return qobject_cast<MainWindowBase *>(
widget());
405 return d->mainWindow() !=
nullptr;
410 return d->mainWindow();
432 if (!d->affinities.isEmpty()) {
433 qWarning() << Q_FUNC_INFO
434 <<
"Affinity is already set, refusing to change."
435 <<
"Submit a feature request with a good justification.";
445 m->moveToSideBar(
this);
451 return m->overlayedDockWidget() ==
this;
458 return DockRegistry::self()->sideBarLocationForDockWidget(
this);
468 return d->m_lastPositions.isValid();
473 return d->m_lastOverlayedSize;
478 return DockRegistry::self()->dockByName(
uniqueName);
489 window()->setGeometry(geometry);
491 d->m_lastPositions.setLastFloatingGeometry(geometry);
495 FloatingWindow *DockWidgetBase::Private::morphIntoFloatingWindow()
497 if (
auto fw = floatingWindow())
501 QRect geo = m_lastPositions.lastFloatingGeometry();
507 const QPoint center = defaultCenterPosForFloating();
508 if (!center.isNull())
516 FloatingWindow::ensureRectIsOnScreen(geo);
517 auto floatingWindow =
519 floatingWindow->show();
521 return floatingWindow;
527 void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
529 if (q->isWindow() && q->isVisible())
530 morphIntoFloatingWindow();
533 MDILayoutWidget *DockWidgetBase::Private::mdiLayout()
const
535 if (
auto mw = mainWindow())
536 return mw->mdiLayoutWidget();
541 DockWidgetBase::Private *DockWidgetBase::dptr()
const
546 QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
551 if (!mw || !q->isFloating())
557 bool DockWidgetBase::Private::eventFilter(
QObject *watched,
QEvent *event)
561 if ((isWindowActivate || isWindowDeactivate) && watched == q->window())
562 Q_EMIT q->windowActiveAboutToChange(isWindowActivate);
567 void DockWidgetBase::Private::updateTitle()
570 q->window()->setWindowTitle(title);
572 toggleAction->setText(title);
575 void DockWidgetBase::Private::toggle(
bool enabled)
577 if (SideBar *sb = sideBar()) {
579 sb->toggleOverlay(q);
590 void DockWidgetBase::Private::updateToggleAction()
593 m_updatingToggleAction =
true;
594 if ((q->isVisible() || frame()) && !toggleAction->isChecked()) {
595 toggleAction->setChecked(
true);
596 }
else if ((!q->isVisible() && !frame()) && toggleAction->isChecked()) {
597 toggleAction->setChecked(
false);
601 void DockWidgetBase::Private::updateFloatAction()
605 if (q->isFloating()) {
606 floatAction->setEnabled(m_lastPositions.isValid());
607 floatAction->setChecked(
true);
608 floatAction->setToolTip(tr(
"Dock"));
610 floatAction->setEnabled(
true);
611 floatAction->setChecked(
false);
612 floatAction->setToolTip(tr(
"Detach"));
616 void DockWidgetBase::Private::onDockWidgetShown()
618 updateToggleAction();
622 void DockWidgetBase::Private::onDockWidgetHidden()
624 updateToggleAction();
628 void DockWidgetBase::Private::close()
630 if (!m_processingToggleAction && !q->isOpen()) {
634 if (m_isPersistentCentralDockWidget)
638 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
639 auto mainWindow = sb->mainWindow();
640 if (mainWindow->overlayedDockWidget() == q) {
641 mainWindow->clearSideBarOverlay(
false);
645 if (!m_isForceClosing && q->isFloating()
649 m_lastPositions.setLastFloatingGeometry(q->window()->geometry());
655 if (Frame *frame = this->frame()) {
656 q->setParent(
nullptr);
657 frame->removeWidget(q);
659 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
660 sb->removeDockWidget(q);
665 Q_EMIT q->aboutToDeleteOnClose();
670 bool DockWidgetBase::Private::restoreToPreviousPosition()
672 if (!m_lastPositions.isValid())
675 Layouting::Item *item = m_lastPositions.lastItem();
677 LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
679 layout->restorePlaceholder(q, item, m_lastPositions.lastTabIndex());
683 void DockWidgetBase::Private::maybeRestoreToPreviousPosition()
687 if (!m_lastPositions.isValid())
690 Layouting::Item *layoutItem = m_lastPositions.lastItem();
694 if (m_lastPositions.wasFloating())
697 Frame *frame = this->frame();
699 if (frame && frame->QWidgetAdapter::parentWidget() == DockRegistry::self()->layoutForItem(layoutItem)) {
707 if (q->parentWidget()) {
713 restoreToPreviousPosition();
716 int DockWidgetBase::Private::currentTabIndex()
const
718 Frame *frame = this->frame();
719 return frame ? frame->indexOfDockWidget(q) : 0;
722 void DockWidgetBase::Private::saveTabIndex()
724 m_lastPositions.saveTabIndex(currentTabIndex(), q->isFloating());
727 void DockWidgetBase::Private::show()
735 #ifdef KDDOCKWIDGETS_QTWIDGETS
738 Q_EMIT QQuickItem::parentChanged(parentItem());
740 d->updateToggleAction();
741 d->updateFloatAction();
748 d->onDockWidgetShown();
751 if (
Frame *f = d->frame()) {
753 f->onDockWidgetShown(
this);
757 d->maybeRestoreToPreviousPosition();
765 d->onDockWidgetHidden();
768 if (
Frame *f = d->frame()) {
770 f->onDockWidgetHidden(
this);
778 if (
auto frame = d->frame()) {
779 d->m_lastOverlayedSize = frame->QWidgetAdapter::size();
781 qWarning() << Q_FUNC_INFO <<
"Overlayed dock widget without frame shouldn't happen";
785 return QWidgetAdapter::onResize(newSize);
792 qApp->sendEvent(d->widget, e);
798 DockWidgetBase *DockWidgetBase::deserialize(
const LayoutSaver::DockWidget::Ptr &saved)
800 auto dr = DockRegistry::self();
801 DockWidgetBase *dw = dr->dockByName(saved->uniqueName, DockRegistry::DockByNameFlag::CreateIfNotFound);
805 dw->setProperty(
"kddockwidget_was_restored",
true);
808 qWarning() << Q_FUNC_INFO <<
"Affinity name changed from" << dw->
affinities()
809 <<
"; to" << saved->affinities;
810 dw->d->affinities = saved->affinities;
824 return d->m_userType;
830 layout->moveDockWidget(
this, pos);
836 layout->resizeDockWidget(
this, size);
841 #ifdef KDDOCKWIDGETS_QTQUICK
842 if (
Frame *frame = d->frame()) {
849 qWarning() << Q_FUNC_INFO <<
"Not implemented for QtQuick";
855 return d->m_isPersistentCentralDockWidget;
858 LayoutSaver::DockWidget::Ptr DockWidgetBase::Private::serialize()
const
860 auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
861 ptr->affinities = q->affinities();
866 void DockWidgetBase::Private::forceClose()
872 DockWidgetBase::Private::Private(
const QString &dockName, DockWidgetBase::Options options_,
879 , layoutSaverOptions(layoutSaverOptions_)
884 if (!m_updatingToggleAction) {
888 m_processingToggleAction =
true;
891 m_processingToggleAction =
false;
896 if (!m_updatingFloatAction) {
897 q->setFloating(checked);
900 Q_EMIT q->isFloatingChanged(checked);
903 if (checked && q->isOpen()) {
904 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
905 sb->mainWindow()->clearSideBarOverlay(
false);
906 sb->removeDockWidget(q);
914 qApp->installEventFilter(
this);
917 void DockWidgetBase::Private::addPlaceholderItem(Layouting::Item *item)
920 m_lastPositions.addPosition(item);
923 LastPositions &DockWidgetBase::Private::lastPositions()
925 return m_lastPositions;
928 Frame *DockWidgetBase::Private::frame()
const
932 if (
auto frame = qobject_cast<Frame *>(p))
939 void DockWidgetBase::Private::saveLastFloatingGeometry()
941 if (q->isFloating() && q->isVisible()) {
943 lastPositions().setLastFloatingGeometry(q->window()->geometry());