15#include "kddockwidgets/Config.h"
21#include "FloatingWindow_p.h"
22#include "ScopedValueRollback_p.h"
33#include "core/TabBar_p.h"
36#include "DockWidget_p.h"
37#include "ObjectGuard_p.h"
39#include "core/Logging_p.h"
40#include "core/Utils_p.h"
41#include "core/View_p.h"
42#include "core/LayoutSaver_p.h"
43#include "core/Position_p.h"
44#include "core/WidgetResizeHandler_p.h"
45#include "core/DelayedCall_p.h"
46#include "core/layouting/Item_p.h"
52#define MARGIN_THRESHOLD 100
68 if (!isCentralGroup) {
74 options &= ~FrameOption_AlwaysShowsTabs;
98 , m_tabBar(m_stack->tabBar())
99 , m_titleBar(new Core::
TitleBar(this))
104 m_tabBar->
dptr()->currentDockWidgetChanged.connect([
this] {
111 view()->
d->closeRequested.connect([
this](CloseEvent *ev) { onCloseEvent(ev); });
122 d->m_layoutItem->unref();
124 delete m_resizeHandler;
125 m_resizeHandler =
nullptr;
136void Group::onCloseEvent(CloseEvent *e)
141 dock->view()->d->requestClose(e);
142 if (!e->isAccepted())
155 delete m_resizeHandler;
156 m_resizeHandler =
nullptr;
160 createMDIResizeHandler();
163 d->m_visibleWidgetCountChangedConnection =
167 d->isInMainWindowChanged.emit();
170 d->isMDIChanged.emit();
205 if (fw->hasSingleGroup()) {
206 fw->updateTitleAndIcon();
210 setObjectName(dw->uniqueName());
213 KDDW_ERROR(
"Invalid dock widget for group. index={}",
currentTabIndex());
243 KDDW_ERROR(
"Group::addTab: group is empty. group={}", (
void * )group);
249 addTab(dockWidget, addingOption);
256 for (
Group *f : groups)
265 KDDW_ERROR(
"Group::addTab dockWidget already exists. this={} ; dockWidget={}", (
void * )
this, (
void * )dockWidget);
269 dockWidget->
d->addPlaceholderItem(d->m_layoutItem);
280 if (!d->m_layoutItem) {
290 dockWidget->
d->setIsOpen(
true);
299 d->titleChangedConnections[dockWidget] = std::move(titleChangedConnection);
300 d->iconChangedConnections[dockWidget] = std::move(iconChangedConnection);
305 auto it = d->titleChangedConnections.find(dw);
306 if (it != d->titleChangedConnections.end())
307 d->titleChangedConnections.erase(it);
309 it = d->iconChangedConnections.find(dw);
310 if (it != d->iconChangedConnections.end())
311 d->iconChangedConnections.erase(it);
314 gvi->removeDockWidget(dw);
322 dockWidget->
d->saveTabIndex();
327 auto newGroup =
new Group();
328 const Point globalPoint =
mapToGlobal(Point(0, 0));
329 newGroup->addTab(dockWidget);
335 r.moveTopLeft(globalPoint);
380 dw->
d->onParentChanged();
411 scheduleDeleteLater();
418 d->hasTabsVisibleChanged.emit();
423 dock->d->updateFloatAction();
427 fw->dptr()->numDockWidgetsChanged.emit();
431 d->numDockWidgetsChanged.emit();
436 d->isFocusedChanged.emit();
441 d->focusedWidgetChanged.emit();
446 if (m_updatingTitleBar || m_beingDeleted) {
451 ScopedValueRollback guard(m_updatingTitleBar,
true);
453 bool visible =
false;
461 visible = !fw->hasSingleGroup();
464 visible = !dropArea->hasSingleGroup();
472 if (wasVisible != visible) {
473 d->actualTitleBarChanged.emit();
475 for (
auto dw : docks)
476 dw->d->actualTitleBarChanged.emit();
483 fw->updateTitleBarVisibility();
491 dw->d->updateFloatAction();
496 return rect().contains(
view()->mapFromGlobal(globalPos));
508 if (fw->hasSingleGroup())
509 return fw->titleBar();
511 if (mdiDropArea->hasSingleGroup()) {
537 for (
int i = 0; i < count; ++i)
546 for (
int i = 0, e = count; i != e; ++i) {
564 if (
auto fw = p->asFloatingWindowController())
567 if (p->equals(
view()->rootView())) {
581 KDDW_ERROR(
"Invalid usage, there's no tabs");
585 if (!d->m_layoutItem) {
586 KDDW_DEBUG(
"Group::restoreToPreviousPosition: There's no previous position known");
590 if (!d->m_layoutItem->isPlaceholder()) {
593 KDDW_DEBUG(
"Group::restoreToPreviousPosition: Previous position isn't a placeholder");
597 d->m_layoutItem->restore(d);
608 for (
auto dw : docks) {
620 for (
auto dw : docks) {
628void Group::Private::setLayoutItem_impl(Item *item)
632 const auto docks = q->dockWidgets();
635 dw->d->addPlaceholderItem(item);
638 dw->d->lastPosition()->removePlaceholders();
642LayoutingHost *Group::Private::host()
const
644 return q->m_layout ? q->m_layout->asLayoutingHost() :
nullptr;
647void Group::Private::setHost(LayoutingHost *host)
651 parent = layout->view();
654 q->setParentView(parent);
659 return d->m_layoutItem;
669 return m_beingDeleted;
684 return m->affinities();
693 d->setLayoutItem(item);
708 d->m_options &= ~FrameOption_IsOverlayed;
735 Group *group =
nullptr;
738 if (isPersistentCentralFrame) {
742 if (f.mainWindowUniqueName.isEmpty()) {
744 KDDW_ERROR(
"Group is the persistent central group but doesn't have"
745 "an associated window name");
748 group = mw->dropArea()->centralGroup();
751 KDDW_ERROR(
"Main window {} doesn't have central group", f.mainWindowUniqueName);
755 KDDW_ERROR(
"Couldn't find main window {}", f.mainWindowUniqueName);
763 group->setObjectName(f.objectName);
765 for (
const auto &savedDock : std::as_const(f.dockWidgets)) {
779 LayoutSaver::Group group;
780 group.isNull =
false;
784 group.objectName = objectName();
788 group.id =
view()->
d->id();
791 group.mainWindowUniqueName = mw->uniqueName();
795 group.dockWidgets.push_back(dock->d->serialize());
797 if (group.currentTabIndex == -1 && !docks.
isEmpty()) {
798 KDDW_ERROR(
"Group::serialize: Current index shouldn't be -1. Setting to 0 instead.");
799 group.currentTabIndex = 0;
805void Group::scheduleDeleteLater()
807 KDDW_TRACE(
"Group::scheduleDeleteLater: {}", (
void * )
this);
808 m_beingDeleted =
true;
811 if (item->parentContainer())
812 item->turnIntoPlaceholder();
820void Group::createMDIResizeHandler()
822 delete m_resizeHandler;
823 m_resizeHandler =
new WidgetResizeHandler(WidgetResizeHandler::EventFilterMode::Global,
824 WidgetResizeHandler::WindowMode::MDI,
view());
828 m_resizeHandler->setEventFilterStartsManually();
831 m_resizeHandler->setHandlesMouseCursor(
false);
837 Size
size = Item::hardcodedMinimumSize;
841 size =
size.expandedTo(dw->view()->minSize());
849 Size
size = Item::hardcodedMaximumSize;
854 const Size dwMax = dw->view()->maxSizeHint();
855 if (
size == Item::hardcodedMaximumSize) {
860 const bool hasMaxSize = dwMax != Item::hardcodedMaximumSize;
866 if (
size.width() == 0)
867 size.setWidth(Item::hardcodedMaximumSize.width());
868 if (
size.height() == 0)
869 size.setHeight(Item::hardcodedMaximumSize.height());
886 return gvi->dragRect();
893 return m_layout ? m_layout->
mainWindow() :
nullptr;
900 return std::all_of(docks.cbegin(), docks.cend(),
901 [option](
DockWidget *dw) { return dw->options() & option; });
908 return std::any_of(docks.cbegin(), docks.cend(),
909 [option](
DockWidget *dw) { return dw->options() & option; });
915 return std::all_of(docks.cbegin(), docks.cend(),
916 [option](
DockWidget *dw) { return dw->layoutSaverOptions() & option; });
922 return std::any_of(docks.cbegin(), docks.cend(),
923 [option](
DockWidget *dw) { return dw->layoutSaverOptions() & option; });
929 createMDIResizeHandler();
930 m_resizeHandler->setAllowedResizeSides(sides);
932 delete m_resizeHandler;
933 m_resizeHandler =
nullptr;
950 return dwWrapper->d->group();
967 auto dropArea = p ? p->asDropAreaController() :
nullptr;
968 if (dropArea && dropArea->isMDIWrapper())
975 return m_layout ? m_layout->
asMDILayout() :
nullptr;
984 KDDW_ERROR(
"Expected a single dock widget wrapper as group child");
993 return d->m_userType;
998 return m_resizeHandler;
1010 if (!dockwidgets.isEmpty())
1011 return dockwidgets.first()->floatingWindowFlags();
1018 return d->m_options;
1043Group::Private::Private(
Group *qq,
int userType, FrameOptions options)
1045 , m_userType(userType)
1046 , m_options(options)
1048 m_parentViewChangedConnection = q->Controller::dptr()->parentViewChanged.connect([
this] {
1049 hostChanged.emit(host());
1052 q->view()->d->layoutInvalidated.connect([
this] {
1053 if (
auto item = q->layoutItem()) {
1055 if (item->m_sizingInfo.minSize == minSize() && item->m_sizingInfo.maxSizeHint == maxSizeHint()) {
1061 if (m_invalidatingLayout) {
1069 ScopedValueRollback guard(m_invalidatingLayout,
true);
1073 layoutInvalidated.emit();
1078Group::Private::~Private()
1080 m_visibleWidgetCountChangedConnection->disconnect();
1082 beingDestroyed.emit();
1090 if (
auto guest = item->guest()) {
1091 if (
auto group =
dynamic_cast<Core::Group::Private *
>(guest))
A widget that supports an arbitrary number of splitters (called Separators) in any combination of ver...
A ScopedConnection is a RAII-style way to make sure a Connection is disconnected.
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.
static int s_dbg_numFrames
The MainWindow base-class that's shared between QtWidgets and QtQuick stack.