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;
86 Frame *frame = d->frame();
89 if (frame->containsDockWidget(other)) {
90 qWarning() << Q_FUNC_INFO <<
"Already contains" << other;
96 d->morphIntoFloatingWindow();
100 qWarning() << Q_FUNC_INFO <<
"null frame";
105 other->setParent(
nullptr);
106 frame->addWidget(other, option);
114 if (
auto mainWindow = qobject_cast<MainWindowBase *>(window())) {
120 if (!DockRegistry::self()->affinitiesMatch(other->
affinities(), d->affinities)) {
121 qWarning() << Q_FUNC_INFO <<
"Refusing to dock widget with incompatible affinity."
127 qWarning() << Q_FUNC_INFO <<
"Refusing to dock non-dockable widget" << other;
132 d->morphIntoFloatingWindow();
134 if (
auto fw = floatingWindow()) {
135 fw->addDockWidget(other, location, relativeTo, initialOption);
137 qWarning() << Q_FUNC_INFO <<
"Couldn't find floating nested window";
148 d->widget->setParent(
nullptr);
168 auto fw = floatingWindow();
169 return fw && fw->hasSingleDockWidget();
176 if ((floats && alreadyFloating) || (!floats && !alreadyFloating))
188 auto frame = d->frame();
190 qWarning() <<
"DockWidget::setFloating: Tabbed but no frame exists"
196 frame->detachTab(
this);
198 d->frame()->titleBar()->makeWindow();
201 auto lastGeo = d->lastPositions().lastFloatingGeometry();
202 if (lastGeo.isValid()) {
203 if (
auto fw = floatingWindow())
208 d->saveLastFloatingGeometry();
209 return d->restoreToPreviousPosition();
215 return d->toggleAction;
220 return d->floatAction;
235 if (
title != d->title) {
244 if (
Frame *f = d->frame())
245 return f->QWidgetAdapter::geometry();
248 return QWidgetAdapter::geometry();
258 return d->layoutSaverOptions;
264 qWarning() << Q_FUNC_INFO <<
"Option_NotDockable not allowed to change. Pass via ctor only.";
278 if (
Frame *frame = d->frame()) {
279 return frame->alwaysShowsTabs() || frame->dockWidgetCount() > 1;
282 qWarning() <<
"DockWidget::isTabbed() Couldn't find any tab widget.";
289 if (
Frame *frame = d->frame()) {
290 return frame->currentIndex() == frame->indexOfDockWidget(
const_cast<DockWidgetBase *
>(
this));
298 if (
Frame *frame = d->frame())
299 frame->setCurrentDockWidget(
this);
304 if (
Frame *frame = d->frame())
305 return frame->indexOfDockWidget(
this);
313 d->titleBarIcon =
icon;
316 d->tabBarIcon =
icon;
319 d->toggleAction->setIcon(
icon);
327 return d->titleBarIcon;
330 return d->tabBarIcon;
333 return d->toggleAction->icon();
345 if (
Frame *f = d->frame())
346 return f->actualTitleBar();
353 return d->toggleAction->isChecked();
358 return d->affinities;
363 if (isWindow() && (d->m_lastPositions.wasFloating() || !d->m_lastPositions.isValid())) {
366 d->morphIntoFloatingWindow();
379 if (
auto fw = floatingWindow()) {
381 fw->activateWindow();
382 }
else if (
Frame *frame = d->frame()) {
390 return qobject_cast<MainWindowBase *>(
widget());
395 return d->mainWindow() !=
nullptr;
400 return d->mainWindow();
422 if (!d->affinities.isEmpty()) {
423 qWarning() << Q_FUNC_INFO
424 <<
"Affinity is already set, refusing to change."
425 <<
"Submit a feature request with a good justification.";
435 m->moveToSideBar(
this);
441 return m->overlayedDockWidget() ==
this;
448 return DockRegistry::self()->sideBarLocationForDockWidget(
this);
458 return d->m_lastPositions.isValid();
463 return d->m_lastOverlayedSize;
468 return DockRegistry::self()->dockByName(
uniqueName);
479 window()->setGeometry(geometry);
481 d->m_lastPositions.setLastFloatingGeometry(geometry);
485 FloatingWindow *DockWidgetBase::Private::morphIntoFloatingWindow()
487 if (
auto fw = floatingWindow())
491 QRect geo = m_lastPositions.lastFloatingGeometry();
497 const QPoint center = defaultCenterPosForFloating();
498 if (!center.isNull())
506 auto floatingWindow =
508 floatingWindow->show();
510 return floatingWindow;
516 void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
518 if (q->isWindow() && q->isVisible())
519 morphIntoFloatingWindow();
522 MDILayoutWidget *DockWidgetBase::Private::mdiLayout()
const
524 if (
auto mw = mainWindow())
525 return mw->mdiLayoutWidget();
530 DockWidgetBase::Private *DockWidgetBase::dptr()
const
535 QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
540 if (!mw || !q->isFloating())
546 bool DockWidgetBase::Private::eventFilter(
QObject *watched,
QEvent *event)
550 if ((isWindowActivate || isWindowDeactivate) && watched == q->window())
551 Q_EMIT q->windowActiveAboutToChange(isWindowActivate);
556 void DockWidgetBase::Private::updateTitle()
559 q->window()->setWindowTitle(title);
561 toggleAction->setText(title);
564 void DockWidgetBase::Private::toggle(
bool enabled)
566 if (SideBar *sb = sideBar()) {
568 sb->toggleOverlay(q);
579 void DockWidgetBase::Private::updateToggleAction()
582 m_updatingToggleAction =
true;
583 if ((q->isVisible() || frame()) && !toggleAction->isChecked()) {
584 toggleAction->setChecked(
true);
585 }
else if ((!q->isVisible() && !frame()) && toggleAction->isChecked()) {
586 toggleAction->setChecked(
false);
590 void DockWidgetBase::Private::updateFloatAction()
594 if (q->isFloating()) {
595 floatAction->setEnabled(m_lastPositions.isValid());
596 floatAction->setChecked(
true);
597 floatAction->setToolTip(tr(
"Dock"));
599 floatAction->setEnabled(
true);
600 floatAction->setChecked(
false);
601 floatAction->setToolTip(tr(
"Detach"));
605 void DockWidgetBase::Private::onDockWidgetShown()
607 updateToggleAction();
611 void DockWidgetBase::Private::onDockWidgetHidden()
613 updateToggleAction();
617 void DockWidgetBase::Private::close()
619 if (!m_processingToggleAction && !q->isOpen()) {
624 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
625 auto mainWindow = sb->mainWindow();
626 if (mainWindow->overlayedDockWidget() == q) {
627 mainWindow->clearSideBarOverlay(
false);
631 if (!m_isForceClosing && q->isFloating()
635 m_lastPositions.setLastFloatingGeometry(q->window()->geometry());
641 if (Frame *frame = this->frame()) {
642 q->setParent(
nullptr);
643 frame->removeWidget(q);
645 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
646 sb->removeDockWidget(q);
651 Q_EMIT q->aboutToDeleteOnClose();
656 bool DockWidgetBase::Private::restoreToPreviousPosition()
658 if (!m_lastPositions.isValid())
661 Layouting::Item *item = m_lastPositions.lastItem();
663 LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
665 layout->restorePlaceholder(q, item, m_lastPositions.lastTabIndex());
669 void DockWidgetBase::Private::maybeRestoreToPreviousPosition()
673 if (!m_lastPositions.isValid())
676 Layouting::Item *layoutItem = m_lastPositions.lastItem();
680 if (m_lastPositions.wasFloating())
683 Frame *frame = this->frame();
685 if (frame && frame->QWidgetAdapter::parentWidget() == DockRegistry::self()->layoutForItem(layoutItem)) {
693 if (q->parentWidget()) {
699 restoreToPreviousPosition();
702 int DockWidgetBase::Private::currentTabIndex()
const
704 Frame *frame = this->frame();
705 return frame ? frame->indexOfDockWidget(q) : 0;
708 void DockWidgetBase::Private::saveTabIndex()
710 m_lastPositions.saveTabIndex(currentTabIndex(), q->isFloating());
713 void DockWidgetBase::Private::show()
721 #ifdef KDDOCKWIDGETS_QTWIDGETS
727 d->updateToggleAction();
728 d->updateFloatAction();
735 d->onDockWidgetShown();
738 if (
Frame *f = d->frame()) {
740 f->onDockWidgetShown(
this);
744 d->maybeRestoreToPreviousPosition();
752 d->onDockWidgetHidden();
755 if (
Frame *f = d->frame()) {
757 f->onDockWidgetHidden(
this);
765 if (
auto frame = d->frame()) {
766 d->m_lastOverlayedSize = frame->QWidgetAdapter::size();
768 qWarning() << Q_FUNC_INFO <<
"Overlayed dock widget without frame shouldn't happen";
772 return QWidgetAdapter::onResize(newSize);
779 qApp->sendEvent(d->widget, e);
785 DockWidgetBase *DockWidgetBase::deserialize(
const LayoutSaver::DockWidget::Ptr &saved)
787 auto dr = DockRegistry::self();
788 DockWidgetBase *dw = dr->dockByName(saved->uniqueName, DockRegistry::DockByNameFlag::CreateIfNotFound);
792 dw->setProperty(
"kddockwidget_was_restored",
true);
795 qWarning() << Q_FUNC_INFO <<
"Affinity name changed from" << dw->
affinities()
796 <<
"; to" << saved->affinities;
797 dw->d->affinities = saved->affinities;
811 return d->m_userType;
817 layout->moveDockWidget(
this, pos);
823 layout->resizeDockWidget(
this, size);
828 #ifdef KDDOCKWIDGETS_QTQUICK
829 if (
Frame *frame = d->frame()) {
836 qWarning() << Q_FUNC_INFO <<
"Not implemented for QtQuick";
840 LayoutSaver::DockWidget::Ptr DockWidgetBase::Private::serialize()
const
842 auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
843 ptr->affinities = q->affinities();
848 void DockWidgetBase::Private::forceClose()
854 DockWidgetBase::Private::Private(
const QString &dockName, DockWidgetBase::Options options_,
861 , layoutSaverOptions(layoutSaverOptions_)
866 if (!m_updatingToggleAction) {
870 m_processingToggleAction =
true;
873 m_processingToggleAction =
false;
878 if (!m_updatingFloatAction) {
879 q->setFloating(checked);
882 Q_EMIT q->isFloatingChanged(checked);
885 if (checked && q->isOpen()) {
886 if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
887 sb->mainWindow()->clearSideBarOverlay(
false);
888 sb->removeDockWidget(q);
896 qApp->installEventFilter(
this);
899 void DockWidgetBase::Private::addPlaceholderItem(Layouting::Item *item)
902 m_lastPositions.addPosition(item);
905 LastPositions &DockWidgetBase::Private::lastPositions()
907 return m_lastPositions;
910 Frame *DockWidgetBase::Private::frame()
const
914 if (
auto frame = qobject_cast<Frame *>(p))
921 void DockWidgetBase::Private::saveLastFloatingGeometry()
923 if (q->isFloating() && q->isVisible()) {
925 lastPositions().setLastFloatingGeometry(q->window()->geometry());