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"
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);
514FloatingWindow *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;
546void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
548 if (q->isWindow() && q->isVisible())
549 morphIntoFloatingWindow();
552MDILayoutWidget *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())
582bool DockWidgetBase::Private::isMDIWrapper()
const
584 return mdiDropAreaWrapper() !=
nullptr;
587DropArea *DockWidgetBase::Private::mdiDropAreaWrapper()
const
589 if (
auto dropAreaGuest = qobject_cast<DropArea *>(q->widget())) {
590 if (dropAreaGuest->isMDIWrapper())
591 return dropAreaGuest;
597DockWidgetBase *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();
626DockWidgetBase::Private *DockWidgetBase::dptr()
const
631QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
636 if (!mw || !q->isFloating())
642bool DockWidgetBase::Private::eventFilter(
QObject *watched,
QEvent *event)
646 if ((isWindowActivate || isWindowDeactivate) && watched == q->window())
647 Q_EMIT q->windowActiveAboutToChange(isWindowActivate);
652void DockWidgetBase::Private::updateTitle()
655 q->window()->setWindowTitle(title);
657 toggleAction->setText(title);
660void DockWidgetBase::Private::toggle(
bool enabled)
662 if (SideBar *sb = sideBar()) {
664 sb->toggleOverlay(q);
675void 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);
686void 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"));
701void DockWidgetBase::Private::onDockWidgetShown()
703 updateToggleAction();
707void DockWidgetBase::Private::onDockWidgetHidden()
709 updateToggleAction();
713void 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();
755bool 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());
768void 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();
801int DockWidgetBase::Private::currentTabIndex()
const
803 Frame *frame = this->frame();
804 return frame ? frame->indexOfDockWidget(q) : 0;
807void DockWidgetBase::Private::saveTabIndex()
809 m_lastPosition->saveTabIndex(currentTabIndex(), q->isFloating());
812void 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);
883DockWidgetBase *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;
955LayoutSaver::DockWidget::Ptr DockWidgetBase::Private::serialize()
const
957 auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
958 ptr->affinities = q->affinities();
963void DockWidgetBase::Private::forceClose()
969DockWidgetBase::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);
1014void DockWidgetBase::Private::addPlaceholderItem(Layouting::Item *item)
1017 m_lastPosition->addPlaceholderItem(item);
1020Position::Ptr &DockWidgetBase::Private::lastPosition()
1022 return m_lastPosition;
1025Frame *DockWidgetBase::Private::frame()
const
1029 if (
auto frame = qobject_cast<Frame *>(p))
1036void DockWidgetBase::Private::saveLastFloatingGeometry()
1038 if (q->isFloating() && q->isVisible()) {
1040 lastPosition()->setLastFloatingGeometry(q->window()->geometry());
1046 if (floatingWindow()) {
1047 qWarning() << Q_FUNC_INFO <<
"Call this function only before having a floating window";
Application-wide config to tune certain behaviours of the framework.
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.
void toggled(bool checked)
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 boundedTo(const QSize &otherSize) const const
bool isEmpty() const const
const T & constFirst() const const
bool isEmpty() const const