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);
73 LayoutSaver::Private::restorePendingPositions(
this);
79 d->m_windowActivatedConnection->disconnect();
80 d->m_windowDeactivatedConnection->disconnect();
82 d->aboutToDelete.emit(
this);
96 KDDW_ERROR(
"Refusing to add dock widget into itself {}", (
void * )other);
101 KDDW_ERROR(
"dock widget is null");
106 KDDW_ERROR(
"Refusing to dock widget with incompatible affinity. {} {}", other->
affinities(),
affinities());
112 KDDW_ERROR(
"Refusing to dock non-dockable widget {}", (
void * )other);
117 KDDW_ERROR(
"Not supported with MainWindowOption_HasCentralWidget."
118 "MainWindowOption_HasCentralWidget can only have 1 widget in the center."
119 "Use MainWindowOption_HasCentralFrame instead, which is similar but supports "
128 KDDW_ERROR(
"Already contains {}", (
void * )other);
132 if (
view()->isRootView()) {
134 d->morphIntoFloatingWindow();
139 KDDW_ERROR(
"null group");
145 group->
addTab(other, option);
157 mw->addDockWidget(other, location, relativeTo, initialOption);
162 KDDW_ERROR(
"Refusing to dock widget with incompatible affinity. {} {}", other->
affinities(),
affinities());
168 KDDW_ERROR(
"Refusing to dock non-dockable widget {}", (
void * )other);
172 if (
view()->isRootView())
173 d->morphIntoFloatingWindow();
176 fw->addDockWidget(other, location, relativeTo, initialOption);
178 KDDW_ERROR(
"Couldn't find floating nested window");
189 if ((guest && guest->equals(
d->guest)) || (!guest && !
d->guest))
194 d->guest->setParent(
nullptr);
199 guest->setParent(
view());
201 d->guestViewChanged.emit();
206 if (
view()->isRootView())
216 return fw && fw->hasSingleDockWidget();
223 if (floats == alreadyFloating)
242 auto group =
d->group();
244 KDDW_ERROR(
"DockWidget::setFloating: Tabbed but no group exists", (
void * )
this);
249 group->detachTab(
this);
254 auto lastGeo =
d->lastPosition()->lastFloatingGeometry();
255 if (lastGeo.isValid()) {
261 d->saveLastFloatingGeometry();
262 return d->restoreToPreviousPosition();
268 return d->toggleAction;
273 return d->floatAction;
278 return d->uniqueName();
283 if (
d->isMDIWrapper()) {
286 auto dropAreaGuest =
d->guest ?
guestView()->asDropAreaController() :
nullptr;
287 assert(dropAreaGuest);
288 if (dropAreaGuest->hasSingleGroup()) {
289 return dropAreaGuest->groups().constFirst()->title();
303 d->titleChanged.emit(
title);
310 return f->view()->geometry();
323 return d->layoutSaverOptions;
330 "DockWidget::setOptions: Option_NotDockable not allowed to change. Pass via ctor only.");
345 return group->alwaysShowsTabs() || group->dockWidgetCount() > 1;
348 KDDW_ERROR(
"DockWidget::isTabbed() Couldn't find any tab widget.");
356 return group->currentIndex() == group->indexOfDockWidget(
const_cast<DockWidget *
>(
this));
365 group->setCurrentDockWidget(
this);
371 return group->indexOfDockWidget(
this);
378 if (
Group *group =
d->group())
379 return group->currentTabIndex();
387 d->titleBarIcon =
icon;
390 d->tabBarIcon =
icon;
393 d->toggleAction->setIcon(
icon);
395 d->iconChanged.emit();
401 return d->titleBarIcon;
404 return d->tabBarIcon;
407 return d->toggleAction->icon();
420 return f->actualTitleBar();
432 return d->affinities;
442 if (
view()->isRootView()
443 && (
d->m_lastPosition->wasFloating() || !
d->m_lastPosition->isValid())) {
446 d->morphIntoFloatingWindow();
461 fw->view()->activateWindow();
464 group->view()->raise();
477 return d->mainWindow() !=
nullptr;
482 return d->mainWindow();
503 if (!
d->affinities.isEmpty()) {
509 KDDW_ERROR(
"Affinity is already set, refusing to change."
510 "Submit a feature request with a good justification.");
520 m->moveToSideBar(
this);
526 if (
auto sb = m->sideBarForDockWidget(
this)) {
527 sb->removeDockWidget(
this);
535 return m->overlayedDockWidget() ==
this;
552 return d->m_lastPosition->isValid();
557 return d->m_lastOverlayedSize;
568 group->tabBar()->removeDockWidget(
this);
572 d->onParentChanged();
582 return d->m_lastCloseReason;
590 d->m_lastPosition->setLastFloatingGeometry(
geometry);
596 if (
auto fw =
view()->rootView()->asFloatingWindowController())
604 if (
auto fw = floatingWindow())
607 if (q->view()->isRootView()) {
608 Rect geo = m_lastPosition->lastFloatingGeometry();
615 const Point center = defaultCenterPosForFloating();
616 if (!center.isNull())
617 geo.moveCenter(center);
623 geo.setSize(geo.size().boundedTo(group->view()->maxSizeHint()));
624 geo.setSize(geo.size().expandedTo(group->view()->minSize()));
628 Core::AtomicSanityChecks checks(floatingWindow->dropArea()->rootItem());
629 floatingWindow->view()->show();
632 return floatingWindow;
638void DockWidget::Private::maybeMorphIntoFloatingWindow()
640 if (q->view()->isRootView() && q->isVisible())
641 morphIntoFloatingWindow();
644MDILayout *DockWidget::Private::mdiLayout()
const
649 if (
auto mdiLayout = p->asMDILayoutController()) {
652 }
else if (
auto dropArea = p->asDropAreaController()) {
655 if (!dropArea->isMDIWrapper())
667bool DockWidget::Private::isMDIWrapper()
const
669 return mdiDropAreaWrapper() !=
nullptr;
672DropArea *DockWidget::Private::mdiDropAreaWrapper()
const
674 if (
auto dropAreaGuest = guest ? q->guestView()->asDropAreaController() : nullptr) {
675 if (dropAreaGuest->isMDIWrapper())
676 return dropAreaGuest;
684 if (isMDIWrapper()) {
693 if (
auto dropArea = p->asDropAreaController()) {
694 if (dropArea->isMDIWrapper())
695 return dropArea->mdiDockWidgetWrapper();
712DockWidget::Private::~Private()
718Point DockWidget::Private::defaultCenterPosForFloating()
724 if (!mw || !q->isFloating())
730void DockWidget::Private::onWindowActivated(std::shared_ptr<View> rootView)
732 if (
View::equals(rootView.get(), q->view()->rootView().get()))
733 windowActiveAboutToChange.emit(
true);
736void DockWidget::Private::onWindowDeactivated(std::shared_ptr<View> rootView)
738 if (rootView->inDtor() || q->view()->inDtor())
741 if (
View::equals(rootView.get(), q->view()->rootView().get()))
742 windowActiveAboutToChange.emit(
false);
745void DockWidget::Private::updateTitle()
748 q->view()->rootView()->setWindowTitle(title);
750 toggleAction->setText(title);
753void DockWidget::Private::toggle(
bool enabled)
757 ScopedValueRollback guard(m_removingFromOverlay,
true);
758 sb->toggleOverlay(q);
769void DockWidget::Private::updateToggleAction()
771 ScopedValueRollback recursionGuard(m_updatingToggleAction,
781 if ((q->isVisible() || group()) && !toggleAction->isChecked()) {
782 toggleAction->setChecked(
true);
783 }
else if ((!q->isVisible() && !group()) && toggleAction->isChecked()) {
784 toggleAction->setChecked(
false);
788void DockWidget::Private::updateFloatAction()
793 ScopedValueRollback recursionGuard(m_updatingFloatAction,
796 if (q->isFloating()) {
797 floatAction->setEnabled(m_lastPosition->isValid());
798 floatAction->setChecked(
true);
799 floatAction->setToolTip(Object::tr(
"Dock"));
801 floatAction->setEnabled(
true);
802 floatAction->setChecked(
false);
803 floatAction->setToolTip(Object::tr(
"Detach"));
807void DockWidget::Private::close()
811 ScopedValueRollback guard(m_inClose,
true);
813 if (!m_processingToggleAction && !q->isOpen()) {
814 q->setParentView(
nullptr);
818 if (m_isPersistentCentralDockWidget)
826 auto mainWindow = sb->mainWindow();
827 if (mainWindow->overlayedDockWidget() == q) {
828 mainWindow->clearSideBarOverlay(
false);
832 if (!m_isForceClosing && q->isFloating()
836 m_lastPosition->setLastFloatingGeometry(q->view()->d->windowGeometry());
839 if (!m_removingFromOverlay)
844 q->setParent(
nullptr);
845 q->setParentView(
nullptr);
846 group->removeWidget(q);
849 sb->removeDockWidget(q);
854 aboutToDeleteOnClose.emit();
859bool DockWidget::Private::restoreToPreviousPosition()
861 if (!m_lastPosition->isValid())
864 Core::Item *item = m_lastPosition->lastItem();
872void DockWidget::Private::maybeRestoreToPreviousPosition()
877 if (!m_lastPosition->isValid())
880 Core::Item *layoutItem = m_lastPosition->lastItem();
884 if (m_lastPosition->wasFloating())
898 if (q->view()->parentView()) {
904 restoreToPreviousPosition();
907int DockWidget::Private::currentTabIndex()
const
913void DockWidget::Private::saveTabIndex()
915 m_lastPosition->saveTabIndex(currentTabIndex(), q->isFloating());
918void DockWidget::Private::onParentChanged()
920 updateToggleAction();
923 actualTitleBarChanged.emit();
929 if (
auto group =
d->group()) {
930 d->m_lastOverlayedSize = group->
view()->
size();
932 KDDW_ERROR(
"Overlayed dock widget without group shouldn't happen");
939 if (saved->skipsRestore())
948 dw->
d->m_wasRestored =
true;
951 KDDW_ERROR(
"Affinity name changed from {} to {}", dw->
affinities(),
"; to", saved->affinities);
952 dw->
d->affinities = saved->affinities;
955 dw->
dptr()->m_lastCloseReason = saved->lastCloseReason;
968 return d->m_userType;
974 if (
auto wrapperDW =
d->mdiDockWidgetWrapper()) {
976 layout->moveDockWidget(wrapperDW,
pos);
978 layout->moveDockWidget(
this,
pos);
986 if (
auto wrapperDW =
d->mdiDockWidgetWrapper()) {
988 layout->resizeDockWidget(wrapperDW,
size);
990 layout->resizeDockWidget(
this,
size);
997 if (
Group *group =
d->group()) {
1005 if (
Group *group =
d->group()) {
1015 return d->m_isPersistentCentralDockWidget;
1018LayoutSaver::DockWidget::Ptr DockWidget::Private::serialize()
const
1020 auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
1021 ptr->affinities = q->affinities();
1022 ptr->lastCloseReason = m_lastCloseReason;
1027void DockWidget::Private::forceClose()
1029 ScopedValueRollback rollback(m_isForceClosing,
true);
1033DockWidget::Private::Private(
const QString &dockName, DockWidgetOptions options_,
1034 LayoutSaverOptions layoutSaverOptions_,
DockWidget *qq)
1036 : m_uniqueName(dockName)
1040 , layoutSaverOptions(layoutSaverOptions_)
1041 , toggleAction(
Config::self().viewFactory()->createAction(q,
"toggle"))
1042 , floatAction(
Config::self().viewFactory()->createAction(q,
"float"))
1044 m_toggleActionConnection =
toggleAction->
d->toggled.connect(
1045 [
this](
bool enabled) {
1046 if (!m_updatingToggleAction) {
1050 m_processingToggleAction =
true;
1054 m_processingToggleAction =
false;
1058 m_floatActionConnection =
floatAction->
d->toggled.connect([
this](
bool checked) {
1059 if (!m_updatingFloatAction) {
1060 q->setFloating(checked);
1063 KDDW_TRACE(
"Emitting DockWidget::isFloatingChanged({})", checked);
1064 isFloatingChanged.emit(checked);
1067 if (checked && q->isOpen()) {
1069 sb->mainWindow()->clearSideBarOverlay(
false);
1070 sb->removeDockWidget(q);
1076void DockWidget::Private::addPlaceholderItem(Core::Item *item)
1079 m_lastPosition->addPlaceholderItem(item);
1082Position::Ptr &DockWidget::Private::lastPosition()
1084 return m_lastPosition;
1091 if (
auto group = p->asGroupController())
1093 p = p->parentView();
1098Core::Item *DockWidget::Private::item()
const
1100 auto group = this->group();
1101 if (!group || group->
inDtor())
1107void DockWidget::Private::saveLastFloatingGeometry()
1109 if (q->isFloating() && q->isVisible()) {
1111 lastPosition()->setLastFloatingGeometry(q->view()->d->windowGeometry());
1115void DockWidget::Private::onCloseEvent(CloseEvent *e)
1119 ScopedValueRollback guard(m_inCloseEvent,
true);
1123 if (
auto v = q->view()) {
1126 if (!e->isAccepted())
1133 if (!e->isAccepted())
1140void DockWidget::Private::setIsOpen(
bool is)
1142 if (is == m_isOpen || m_inOpenSetter)
1145 ScopedValueRollback guard(m_inOpenSetter,
true);
1153 maybeRestoreToPreviousPosition();
1155#ifdef KDDW_FRONTEND_QT
1161 updateToggleAction();
1162 updateFloatAction();
1164 if (is && !q->isOverlayed()) {
1167 q->removeFromSideBar();
1174 isOpenChanged.emit(is);
1177QString DockWidget::Private::uniqueName()
const
1179 return m_uniqueName;
1182void DockWidget::Private::setUniqueName(
const QString &name)
1185 KDDW_ERROR(
"DockWidget::Private::setUniqueName: Name is empty");
1187 m_uniqueName = name;
1194 KDDW_ERROR(
"Call this function only before having a floating window");
1207 if (
auto group =
d->group())
1208 return group->
size();
1215 Item *item =
d->item();
1216 if (!item || item->m_inDtor)
1219 item->requestResize(left, top, right, bottom);
1223Draggable *draggableForDockWidget(
DockWidget *dw,
bool singleTab)
1225 Group *group = dw->
d->group();
1227 KDDW_WARN(
"draggableForDockWidget: Expected a group");
1242 return group->
stack();
1248 auto dc = DragController::instance();
1249 if (dc->isDragging()) {
1250 KDDW_WARN(
"DockWidget::startDragging: Dragging already ongoing");
1254 Draggable *
const draggable = draggableForDockWidget(
this, singleTab);
1256 KDDW_WARN(
"DockWidget::startDragging: Could not find a suitable draggable");
1261 if (draggable->asView() == tabBar->
view()) {
1263 tabBar->
dptr()->m_lastPressedDockWidget =
this;
1268 View *draggedView = draggable->asView();
1271 return dc->programmaticStartDrag(draggable, globalPos, offset);
1276 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...
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