13#include "DockWidget_p.h"
15#include "core/LayoutSaver_p.h"
16#include "core/Logging_p.h"
25#include "core/TabBar_p.h"
27#include "core/Utils_p.h"
28#include "core/WindowBeingDragged_p.h"
29#include "core/Position_p.h"
30#include "core/Platform_p.h"
31#include "core/Action_p.h"
32#include "core/DelayedCall_p.h"
33#include "core/DragController_p.h"
35#include "core/layouting/Item_p.h"
39#include "core/ScopedValueRollback_p.h"
41#ifdef KDDW_FRONTEND_QT
56 LayoutSaverOptions layoutSaverOptions)
58 , d(new Private(name, options, layoutSaverOptions, this))
63 KDDW_ERROR(
"Name can't be null");
66 &DockWidget::Private::onWindowActivated,
d);
68 &DockWidget::Private::onWindowDeactivated,
d);
74 d->m_windowActivatedConnection->disconnect();
75 d->m_windowDeactivatedConnection->disconnect();
77 d->aboutToDelete.emit(
this);
91 KDDW_ERROR(
"Refusing to add dock widget into itself {}", (
void * )other);
96 KDDW_ERROR(
"dock widget is null");
101 KDDW_ERROR(
"Refusing to dock widget with incompatible affinity. {} {}", other->
affinities(),
affinities());
107 KDDW_ERROR(
"Refusing to dock non-dockable widget {}", (
void * )other);
112 KDDW_ERROR(
"Not supported with MainWindowOption_HasCentralWidget."
113 "MainWindowOption_HasCentralWidget can only have 1 widget in the center."
114 "Use MainWindowOption_HasCentralFrame instead, which is similar but supports "
123 KDDW_ERROR(
"Already contains {}", (
void * )other);
127 if (
view()->isRootView()) {
129 d->morphIntoFloatingWindow();
134 KDDW_ERROR(
"null group");
140 group->
addTab(other, option);
150 if (
auto mainWindow =
view()->rootView()->asMainWindowController()) {
157 KDDW_ERROR(
"Refusing to dock widget with incompatible affinity. {} {}", other->
affinities(),
affinities());
163 KDDW_ERROR(
"Refusing to dock non-dockable widget {}", (
void * )other);
167 if (
view()->isRootView())
168 d->morphIntoFloatingWindow();
171 fw->addDockWidget(other, location, relativeTo, initialOption);
173 KDDW_ERROR(
"Couldn't find floating nested window");
184 if ((guest && guest->equals(
d->guest)) || (!guest && !
d->guest))
189 d->guest->setParent(
nullptr);
194 guest->setParent(
view());
196 d->guestViewChanged.emit();
201 if (
view()->isRootView())
205 return fw && fw->hasSingleDockWidget();
212 if (floats == alreadyFloating)
231 auto group =
d->group();
233 KDDW_ERROR(
"DockWidget::setFloating: Tabbed but no group exists", (
void * )
this);
238 group->detachTab(
this);
243 auto lastGeo =
d->lastPosition()->lastFloatingGeometry();
244 if (lastGeo.isValid()) {
250 d->saveLastFloatingGeometry();
251 return d->restoreToPreviousPosition();
257 return d->toggleAction;
262 return d->floatAction;
272 if (
d->isMDIWrapper()) {
275 auto dropAreaGuest =
d->guest ?
guestView()->asDropAreaController() :
nullptr;
276 assert(dropAreaGuest);
277 if (dropAreaGuest->hasSingleFrame()) {
278 return dropAreaGuest->groups().constFirst()->title();
292 d->titleChanged.emit(
title);
299 return f->view()->geometry();
312 return d->layoutSaverOptions;
319 "DockWidget::setOptions: Option_NotDockable not allowed to change. Pass via ctor only.");
334 return group->alwaysShowsTabs() || group->dockWidgetCount() > 1;
337 KDDW_ERROR(
"DockWidget::isTabbed() Couldn't find any tab widget.");
345 return group->currentIndex() == group->indexOfDockWidget(
const_cast<DockWidget *
>(
this));
354 group->setCurrentDockWidget(
this);
360 return group->indexOfDockWidget(
this);
367 if (
Group *group =
d->group())
368 return group->currentTabIndex();
376 d->titleBarIcon =
icon;
379 d->tabBarIcon =
icon;
382 d->toggleAction->setIcon(
icon);
384 d->iconChanged.emit();
390 return d->titleBarIcon;
393 return d->tabBarIcon;
396 return d->toggleAction->icon();
409 return f->actualTitleBar();
421 return d->affinities;
431 if (
view()->isRootView()
432 && (
d->m_lastPosition->wasFloating() || !
d->m_lastPosition->isValid())) {
435 d->morphIntoFloatingWindow();
450 fw->view()->activateWindow();
453 group->view()->raise();
466 return d->mainWindow() !=
nullptr;
471 return d->mainWindow();
476 auto group =
d->group();
493 if (!
d->affinities.isEmpty()) {
494 KDDW_ERROR(
"Affinity is already set, refusing to change."
495 "Submit a feature request with a good justification.");
505 m->moveToSideBar(
this);
511 return m->overlayedDockWidget() ==
this;
528 return d->m_lastPosition->isValid();
533 return d->m_lastOverlayedSize;
544 group->tabBar()->removeDockWidget(
this);
548 d->onParentChanged();
561 d->m_lastPosition->setLastFloatingGeometry(
geometry);
567 if (
auto fw =
view()->rootView()->asFloatingWindowController())
575 if (
auto fw = floatingWindow())
578 if (q->view()->isRootView()) {
579 Rect geo = m_lastPosition->lastFloatingGeometry();
586 const Point center = defaultCenterPosForFloating();
587 if (!center.isNull())
588 geo.moveCenter(center);
594 geo.setSize(geo.size().boundedTo(group->view()->maxSizeHint()));
595 geo.setSize(geo.size().expandedTo(group->view()->minSize()));
599 Core::AtomicSanityChecks checks(floatingWindow->dropArea()->rootItem());
600 floatingWindow->view()->show();
603 return floatingWindow;
609void DockWidget::Private::maybeMorphIntoFloatingWindow()
611 if (q->view()->isRootView() && q->isVisible())
612 morphIntoFloatingWindow();
615MDILayout *DockWidget::Private::mdiLayout()
const
620 if (
auto mdiLayout = p->asMDILayoutController()) {
623 }
else if (
auto dropArea = p->asDropAreaController()) {
626 if (!dropArea->isMDIWrapper())
638bool DockWidget::Private::isMDIWrapper()
const
640 return mdiDropAreaWrapper() !=
nullptr;
643DropArea *DockWidget::Private::mdiDropAreaWrapper()
const
645 if (
auto dropAreaGuest = guest ? q->guestView()->asDropAreaController() : nullptr) {
646 if (dropAreaGuest->isMDIWrapper())
647 return dropAreaGuest;
655 if (isMDIWrapper()) {
664 if (
auto dropArea = p->asDropAreaController()) {
665 if (dropArea->isMDIWrapper())
666 return dropArea->mdiDockWidgetWrapper();
683DockWidget::Private::~Private()
689Point DockWidget::Private::defaultCenterPosForFloating()
695 if (!mw || !q->isFloating())
701void DockWidget::Private::onWindowActivated(std::shared_ptr<View> rootView)
703 if (
View::equals(rootView.get(), q->view()->rootView().get()))
704 windowActiveAboutToChange.emit(
true);
707void DockWidget::Private::onWindowDeactivated(std::shared_ptr<View> rootView)
709 if (rootView->inDtor() || q->view()->inDtor())
712 if (
View::equals(rootView.get(), q->view()->rootView().get()))
713 windowActiveAboutToChange.emit(
false);
716void DockWidget::Private::updateTitle()
719 q->view()->rootView()->setWindowTitle(title);
721 toggleAction->setText(title);
724void DockWidget::Private::toggle(
bool enabled)
728 ScopedValueRollback guard(m_removingFromOverlay,
true);
729 sb->toggleOverlay(q);
740void DockWidget::Private::updateToggleAction()
742 ScopedValueRollback recursionGuard(m_updatingToggleAction,
745 if ((q->isVisible() || group()) && !toggleAction->isChecked()) {
746 toggleAction->setChecked(
true);
747 }
else if ((!q->isVisible() && !group()) && toggleAction->isChecked()) {
748 toggleAction->setChecked(
false);
752void DockWidget::Private::updateFloatAction()
754 if (m_willUpdateActions || m_removingFromOverlay)
757 ScopedValueRollback recursionGuard(m_updatingFloatAction,
760 if (q->isFloating()) {
761 floatAction->setEnabled(m_lastPosition->isValid());
762 floatAction->setChecked(
true);
763 floatAction->setToolTip(Object::tr(
"Dock"));
765 floatAction->setEnabled(
true);
766 floatAction->setChecked(
false);
767 floatAction->setToolTip(Object::tr(
"Detach"));
771void DockWidget::Private::close()
775 ScopedValueRollback guard(m_inClose,
true);
777 if (!m_processingToggleAction && !q->isOpen()) {
778 q->setParentView(
nullptr);
782 if (m_isPersistentCentralDockWidget)
789 auto mainWindow = sb->mainWindow();
790 if (mainWindow->overlayedDockWidget() == q) {
791 mainWindow->clearSideBarOverlay(
false);
795 if (!m_isForceClosing && q->isFloating()
799 m_lastPosition->setLastFloatingGeometry(q->view()->d->windowGeometry());
806 q->setParent(
nullptr);
807 q->setParentView(
nullptr);
808 group->removeWidget(q);
811 sb->removeDockWidget(q);
816 aboutToDeleteOnClose.emit();
821bool DockWidget::Private::restoreToPreviousPosition()
823 if (!m_lastPosition->isValid())
826 Core::Item *item = m_lastPosition->lastItem();
834void DockWidget::Private::maybeRestoreToPreviousPosition()
839 if (!m_lastPosition->isValid())
842 Core::Item *layoutItem = m_lastPosition->lastItem();
846 if (m_lastPosition->wasFloating())
860 if (q->view()->parentView()) {
866 restoreToPreviousPosition();
869int DockWidget::Private::currentTabIndex()
const
875void DockWidget::Private::saveTabIndex()
877 m_lastPosition->saveTabIndex(currentTabIndex(), q->isFloating());
880void DockWidget::Private::onParentChanged()
882 updateToggleAction();
885 actualTitleBarChanged.emit();
891 if (
auto group =
d->group()) {
892 d->m_lastOverlayedSize = group->
view()->
size();
894 KDDW_ERROR(
"Overlayed dock widget without group shouldn't happen");
907 dw->
d->m_wasRestored =
true;
910 KDDW_ERROR(
"Affinity name changed from {} to {}", dw->
affinities(),
"; to", saved->affinities);
911 dw->
d->affinities = saved->affinities;
925 return d->m_userType;
931 if (
auto wrapperDW =
d->mdiDockWidgetWrapper()) {
933 layout->moveDockWidget(wrapperDW,
pos);
935 layout->moveDockWidget(
this,
pos);
943 if (
auto wrapperDW =
d->mdiDockWidgetWrapper()) {
945 layout->resizeDockWidget(wrapperDW,
size);
947 layout->resizeDockWidget(
this,
size);
954 if (
Group *group =
d->group()) {
962 return d->m_isPersistentCentralDockWidget;
965LayoutSaver::DockWidget::Ptr DockWidget::Private::serialize()
const
967 auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
968 ptr->affinities = q->affinities();
973void DockWidget::Private::forceClose()
975 ScopedValueRollback rollback(m_isForceClosing,
true);
979DockWidget::Private::Private(
const QString &dockName, DockWidgetOptions options_,
980 LayoutSaverOptions layoutSaverOptions_,
DockWidget *qq)
986 , layoutSaverOptions(layoutSaverOptions_)
987 , toggleAction(
Config::self().viewFactory()->createAction(q,
"toggle"))
988 , floatAction(
Config::self().viewFactory()->createAction(q,
"float"))
991 [
this](
bool enabled) {
992 if (!m_updatingToggleAction) {
996 m_processingToggleAction =
true;
999 m_processingToggleAction =
false;
1003 m_floatActionConnection =
floatAction->
d->toggled.connect([
this](
bool checked) {
1004 if (!m_updatingFloatAction) {
1005 q->setFloating(checked);
1008 KDDW_TRACE(
"Emitting DockWidget::isFloatingChanged({})", checked);
1009 isFloatingChanged.emit(checked);
1012 if (checked && q->isOpen()) {
1014 sb->mainWindow()->clearSideBarOverlay(
false);
1015 sb->removeDockWidget(q);
1021void DockWidget::Private::addPlaceholderItem(Core::Item *item)
1024 m_lastPosition->addPlaceholderItem(item);
1027Position::Ptr &DockWidget::Private::lastPosition()
1029 return m_lastPosition;
1036 if (
auto group = p->asGroupController())
1038 p = p->parentView();
1043Core::Item *DockWidget::Private::item()
const
1045 auto group = this->group();
1046 if (!group || group->
inDtor())
1052void DockWidget::Private::saveLastFloatingGeometry()
1054 if (q->isFloating() && q->isVisible()) {
1056 lastPosition()->setLastFloatingGeometry(q->view()->d->windowGeometry());
1060void DockWidget::Private::onCloseEvent(CloseEvent *e)
1068 if (e->isAccepted())
1072void DockWidget::Private::setIsOpen(
bool is)
1074 if (is == m_isOpen || m_inOpenSetter)
1077 ScopedValueRollback guard(m_inOpenSetter,
true);
1085 maybeRestoreToPreviousPosition();
1087#ifdef KDDW_FRONTEND_QT
1093 updateToggleAction();
1094 updateFloatAction();
1100 isOpenChanged.emit(is);
1106 KDDW_ERROR(
"Call this function only before having a floating window");
1119 if (
auto group =
d->group())
1120 return group->
size();
1127 Item *item =
d->item();
1128 if (!item || item->m_inDtor)
1131 item->requestResize(left, top, right, bottom);
1135Draggable *draggableForDockWidget(
DockWidget *dw,
bool singleTab)
1137 Group *group = dw->
d->group();
1139 KDDW_WARN(
"draggableForDockWidget: Expected a group");
1154 return group->
stack();
1160 auto dc = DragController::instance();
1161 if (dc->isDragging()) {
1162 KDDW_WARN(
"DockWidget::startDragging: Dragging already ongoing");
1166 Draggable *
const draggable = draggableForDockWidget(
this, singleTab);
1168 KDDW_WARN(
"DockWidget::startDragging: Could not find a suitable draggable");
1173 if (draggable->asView() == tabBar->
view()) {
1175 tabBar->
dptr()->m_lastPressedDockWidget =
this;
1180 View *draggedView = draggable->asView();
1183 return dc->programmaticStartDrag(draggable, globalPos, offset);
1188 return d->m_wasRestored;
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...
void addDockWidget(KDDockWidgets::Core::DockWidget *dockWidget, KDDockWidgets::Location location, KDDockWidgets::Core::DockWidget *relativeTo=nullptr, KDDockWidgets::InitialOption initialOption={})
Docks a DockWidget into this main window.
A MultiSplitter with support for drop indicators when hovering over.
The MainWindow base-class that's shared between QtWidgets and QtQuick stack.
bool isEmpty() const const