22#include <QWindowStateChangeEvent>
23#include <QXmlStreamWriter>
29#include <QApplication>
40class DockWindowPrivate
48 void loadStylesheet();
50 void mapDockWidget(DockWidget *w);
52 bool checkFormat(
const QByteArray &state,
int version);
53 bool restoreStateFromXml(
const QByteArray &state,
int version,
bool testing = internal::Restore);
54 bool restoreContainer(
int index, DockStateReader &stream,
bool testing);
55 bool restoreState(
const QByteArray &state,
int version);
57 void restoreDockWidgetsOpenState();
58 void restoreDockAreasIndices();
59 void emitTopLevelEvents();
60 void hideFloatingWidgets();
61 void markDockWidgetsDirty();
63 QList<DockContainer *> m_containers;
64 QMap<QString, DockWidget *> m_dockWidgetsMap;
65 QList<QPointer<DockFloatingContainer>> m_floatingContainers;
66 QList<QPointer<DockFloatingContainer>> m_hiddenFloatingContainers;
67 QVector<DockFloatingContainer *> m_uninitializedFloatingWidgets;
68 QMap<QString, QByteArray> m_perspectives;
69 DockWidget *m_centralWidget =
nullptr;
70 DockOverlay *m_containerOverlay;
71 DockOverlay *m_panelOverlay;
72 DockFocusController *m_focusController =
nullptr;
73 bool m_isLeavingMinimized =
false;
74 Qt::ToolButtonStyle m_toolBarStyleDocked = Qt::ToolButtonIconOnly;
75 Qt::ToolButtonStyle m_toolBarStyleFloating = Qt::ToolButtonTextUnderIcon;
76 QSize m_toolBarIconSizeDocked = QSize(16, 16);
77 QSize m_toolBarIconSizeFloating = QSize(24, 24);
78 DockWidget::DockWidgetFeatures m_lockedDockWidgetFeatures;
79 bool m_restoringState =
false;
82DockWindowPrivate::DockWindowPrivate()
86void DockWindowPrivate::init()
90 m_containerOverlay =
new DockOverlay(q, DockOverlay::PanelOverlayMode);
91 m_panelOverlay =
new DockOverlay(q, DockOverlay::ContainerOverlayMode);
93 if (DockManager::testConfigFlag(DockManager::FocusHighlighting)) {
94 m_focusController =
new DockFocusController(q);
102void DockWindowPrivate::loadStylesheet()
106 QString
fileName =
":/qxdock/res/stylesheets/";
107 fileName += DockManager::testConfigFlag(DockManager::FocusHighlighting) ?
"focus_highlighting" :
"default";
113 styleSheetFile.open(QIODevice::ReadOnly);
114 QTextStream styleSheetStream(&styleSheetFile);
115 result = styleSheetStream.readAll();
116 styleSheetFile.close();
117 q->setStyleSheet(result);
120void DockWindowPrivate::mapDockWidget(DockWidget *w)
122 const QString &objname = w->objectName();
123 DockWidget *oldWidget = m_dockWidgetsMap.value(objname,
nullptr);
125 qWarning() << QString(
"Object name (%1) of DockWidget already exists.").arg(objname);
127 m_dockWidgetsMap.insert(objname, w);
130bool DockWindowPrivate::checkFormat(
const QByteArray &state,
int version)
132 return restoreStateFromXml(state, version, internal::RestoreTesting);
135bool DockWindowPrivate::restoreStateFromXml(
const QByteArray &state,
int version,
bool testing)
140 if (state.isEmpty()) {
143 DockStateReader s(state);
144 s.readNextStartElement();
145 if (s.name() != QLatin1String(
"QxDock")) {
149 int v = s.attributes().value(
"Version").toInt(&ok);
150 if (!ok || v > CurrentVersion) {
157 if (!s.attributes().value(
"UserVersion").isEmpty()) {
158 v = s.attributes().value(
"UserVersion").toInt(&ok);
159 if (!ok || v != version) {
166 if (m_centralWidget) {
167 const auto centralWidgetAttribute = s.attributes().value(
"CentralWidget");
170 if (centralWidgetAttribute.isEmpty()) {
171 qWarning() <<
"Dock window has central widget but saved state does not have central widget.";
177 if (m_centralWidget->objectName() != centralWidgetAttribute.toString()) {
178 qWarning() <<
"Object name of central widget does not match name of central widget in saved state.";
183 int dockContainerCount = 0;
184 while (s.readNextStartElement()) {
185 if (s.name() == QLatin1String(
"Container")) {
186 result = restoreContainer(dockContainerCount, s, testing);
190 dockContainerCount++;
196 int floatingWidgetIndex = dockContainerCount - 1;
197 for (
int i = floatingWidgetIndex; i < m_floatingContainers.count(); ++i) {
198 DockFloatingContainer *floatingWidget = m_floatingContainers[i];
201 q->removeDockContainer(floatingWidget->dockContainer());
202 floatingWidget->deleteLater();
209bool DockWindowPrivate::restoreContainer(
int index, DockStateReader &stream,
bool testing)
217 if (index >= m_containers.count()) {
218 DockFloatingContainer *floatingWidget =
new DockFloatingContainer(q);
219 result = floatingWidget->restoreState(stream, testing);
221 auto container = m_containers[index];
222 if (container->isFloating()) {
223 result = container->floatingWidget()->restoreState(stream, testing);
225 result = container->restoreState(stream, testing);
232bool DockWindowPrivate::restoreState(
const QByteArray &state,
int version)
234 QByteArray s = state.startsWith(
"<?xml") ? state : qUncompress(state);
235 if (!checkFormat(s, version)) {
240 hideFloatingWidgets();
241 markDockWidgetsDirty();
243 if (!restoreStateFromXml(s, version)) {
247 restoreDockWidgetsOpenState();
248 restoreDockAreasIndices();
249 emitTopLevelEvents();
254void DockWindowPrivate::restoreDockWidgetsOpenState()
260 for (
auto dockWidget : m_dockWidgetsMap) {
261 if (dockWidget->property(internal::DirtyProperty).toBool()) {
264 if (dockWidget->isAutoHide()) {
265 dockWidget->autoHideContainer()->cleanupAndDelete();
267 dockWidget->flagAsUnassigned();
268 Q_EMIT dockWidget->viewToggled(
false);
270 dockWidget->toggleViewInternal(!dockWidget->property(internal::ClosedProperty).toBool());
275void DockWindowPrivate::restoreDockAreasIndices()
281 for (
auto dockContainer : m_containers) {
282 for (
int i = 0; i < dockContainer->dockPanelCount(); ++i) {
283 DockPanel *panel = dockContainer->dockPanel(i);
284 QString dockWidgetName = panel->property(
"currentDockWidget").toString();
285 DockWidget *dockWidget =
nullptr;
286 if (!dockWidgetName.isEmpty()) {
287 dockWidget = q->findDockWidget(dockWidgetName);
290 if (!dockWidget || dockWidget->isClosed()) {
291 int index = panel->indexOfFirstOpenDockWidget();
295 panel->setCurrentIndex(index);
297 panel->internalSetCurrentDockWidget(dockWidget);
303void DockWindowPrivate::emitTopLevelEvents()
307 for (
auto dockContainer : m_containers) {
308 DockWidget *topLevelWidget = dockContainer->topLevelDockWidget();
309 if (topLevelWidget) {
310 topLevelWidget->emitTopLevelChanged(
true);
312 for (
int i = 0; i < dockContainer->dockPanelCount(); ++i) {
313 auto panel = dockContainer->dockPanel(i);
314 for (
auto dockWidget : panel->dockWidgets()) {
315 dockWidget->emitTopLevelChanged(
false);
322void DockWindowPrivate::hideFloatingWidgets()
325 for (
auto floatingWidget : m_floatingContainers) {
326 if (floatingWidget) {
327 floatingWidget->hide();
332void DockWindowPrivate::markDockWidgetsDirty()
334 for (
auto dockWidget : m_dockWidgetsMap) {
335 dockWidget->setProperty(internal::DirtyProperty,
true);
339DockWindow::DockWindow(QWidget *parent)
349 window()->installEventFilter(
this);
352 connect(qApp, &QApplication::focusWindowChanged, [](QWindow *focusWindow) {
355 if (focusWindow && focusWindow->isModal()) {
356 focusWindow->raise();
365 std::vector<QPointer<DockPanel>> panels;
369 for (
auto p : panels) {
370 if (!p || p->dockWindow() !=
this) {
373 std::vector<QPointer<QWidget>> deleteWidgets;
374 for (
auto w : p->dockWidgets()) {
375 deleteWidgets.push_back(w);
377 for (
auto w : deleteWidgets) {
382 auto floatingContainers = d->m_floatingContainers;
383 for (
auto c : floatingContainers) {
388 for (
auto p : panels) {
419 if (container ==
nullptr) {
473 d->m_dockWidgetsMap.remove(w->objectName());
487 return d->m_dockWidgetsMap.value(objectName,
nullptr);
552 return d->m_containers;
562 return d->m_dockWidgetsMap;
568 return d->m_centralWidget;
596 d->m_centralWidget =
nullptr;
602 if (d->m_centralWidget) {
603 qWarning(
"Setting a central widget not possible because there is already a central widget.");
608 if (!d->m_dockWidgetsMap.isEmpty()) {
609 qWarning(
"Setting a central widget not possible - the central widget need to be the first "
610 "dock widget that is added to the dock window.");
618 d->m_centralWidget = widget;
634 return d->m_isLeavingMinimized;
641 return d->m_toolBarStyleFloating;
643 return d->m_toolBarStyleDocked;
659 d->m_toolBarStyleFloating = style;
661 d->m_toolBarStyleDocked = style;
669 return d->m_toolBarIconSizeFloating;
671 return d->m_toolBarIconSizeDocked;
685 d->m_toolBarIconSizeFloating = iconSize;
687 d->m_toolBarIconSizeDocked = iconSize;
698 return d->m_lockedDockWidgetFeatures;
727 if (d->m_lockedDockWidgetFeatures ==
features) {
731 d->m_lockedDockWidgetFeatures =
features;
734 for (
auto w : d->m_dockWidgetsMap) {
735 w->notifyFeaturesChanged();
750 return splitter->sizes();
772 if (splitter && splitter->count() == sizes.count()) {
773 splitter->setSizes(sizes);
793 QXmlStreamWriter s(&xmldata);
797 s.writeStartDocument();
798 s.writeStartElement(
"QxDock");
801 s.writeAttribute(
"UserVersion", QString::number(version));
802 s.writeAttribute(
"Containers", QString::number(d->m_containers.count()));
803 if (d->m_centralWidget) {
804 s.writeAttribute(
"CentralWidget", d->m_centralWidget->objectName());
806 for (
auto container : d->m_containers) {
807 container->saveState(s);
811 s.writeEndDocument();
829 if (d->m_restoringState) {
841 bool isHidden = this->isHidden();
845 d->m_restoringState =
true;
847 bool result = d->restoreState(state, version);
848 d->m_restoringState =
false;
863 return d->m_restoringState;
877 d->m_perspectives.insert(uniquePrespectiveName,
saveState());
890 for (
const auto &
name : names) {
891 count += d->m_perspectives.remove(
name);
903 return d->m_perspectives.keys();
908 settings.beginWriteArray(
"Perspectives", d_ptr->m_perspectives.size());
910 for (
auto it = d_ptr->m_perspectives.constBegin(); it != d_ptr->m_perspectives.constEnd(); ++it) {
911 settings.setArrayIndex(i);
912 settings.setValue(
"Name", it.key());
913 settings.setValue(
"State", it.value());
922 d->m_perspectives.clear();
923 int size = settings.beginReadArray(
"Perspectives");
929 for (
int i = 0; i < size; ++i) {
930 settings.setArrayIndex(i);
931 QString
name = settings.value(
"Name").toString();
932 QByteArray data = settings.value(
"State").toByteArray();
933 if (
name.isEmpty() || data.isEmpty()) {
937 d->m_perspectives.insert(
name, data);
953 if (d->m_focusController) {
954 d->m_focusController->setDockWidgetFocused(w);
961 d->m_isLeavingMinimized =
false;
962 this->activateWindow();
968 const auto iterator = d->m_perspectives.find(perspectiveName);
969 if (d->m_perspectives.end() == iterator) {
987 d->m_hiddenFloatingContainers.clear();
991 QList<DockWidget *> visibleWidgets;
993 if (dockWidget->toggleViewAction()->isChecked())
994 visibleWidgets.push_back(dockWidget);
1004 for (
auto dockWidget : visibleWidgets) {
1005 dockWidget->toggleViewAction()->setChecked(
true);
1014 d->m_containers.append(container);
1024 if (d &&
this != container) {
1025 d->m_containers.removeAll(container);
1045 return d->m_containerOverlay;
1051 return d->m_panelOverlay;
1057 if (d->m_focusController) {
1058 d->m_focusController->notifyDockAreaRelocation(droppedWidget);
1065 if (d->m_focusController) {
1073 return d->m_focusController;
1079 if (d->m_hiddenFloatingContainers.isEmpty()) {
1085 bool hasDockWidgetVisible =
false;
1092 if (dockWidget->toggleViewAction()->isChecked()) {
1093 dockWidget->toggleView(
true);
1094 hasDockWidgetVisible =
true;
1098 if (hasDockWidgetVisible) {
1103 d->m_hiddenFloatingContainers.clear();
1114 if (e->type() == QEvent::WindowActivate) {
1115 for (
auto _window : d->m_floatingContainers) {
1116 if (!_window->isVisible() ||
window()->isMinimized()) {
1122 if (QGuiApplication::platformName() == QLatin1String(
"xcb")) {
1123 internal::xcb_update_prop(
true, _window->window()->winId(),
"_NET_WM_STATE",
"_NET_WM_STATE_ABOVE",
1124 "_NET_WM_STATE_STAYS_ON_TOP");
1126 _window->setWindowFlag(Qt::WindowStaysOnTopHint,
true);
1129 }
else if (e->type() == QEvent::WindowDeactivate) {
1130 for (
auto _window : d->m_floatingContainers) {
1131 if (!_window->isVisible() ||
window()->isMinimized()) {
1135 if (QGuiApplication::platformName() == QLatin1String(
"xcb")) {
1136 internal::xcb_update_prop(
false, _window->window()->winId(),
"_NET_WM_STATE",
"_NET_WM_STATE_ABOVE",
1137 "_NET_WM_STATE_STAYS_ON_TOP");
1139 _window->setWindowFlag(Qt::WindowStaysOnTopHint,
false);
1146 if (e->type() == QEvent::WindowStateChange) {
1147 for (
auto _window : d->m_floatingContainers) {
1148 if (!_window->isVisible()) {
1152 if (
window()->isMinimized()) {
1153 _window->showMinimized();
1155 _window->setWindowState(_window->windowState() & (~Qt::WindowMinimized));
1158 if (!
window()->isMinimized()) {
1159 QApplication::setActiveWindow(
window());
1162 return Super::eventFilter(obj, e);
1168 if (e->type() == QEvent::WindowStateChange) {
1169 QWindowStateChangeEvent *ev =
static_cast<QWindowStateChangeEvent *
>(e);
1170 if (ev->oldState().testFlag(Qt::WindowMinimized)) {
1171 d->m_isLeavingMinimized =
true;
1172 QMetaObject::invokeMethod(
this,
"endLeavingMinimizedState", Qt::QueuedConnection);
1175 return Super::eventFilter(obj, e);
1182 Super::showEvent(e);
1185 if (d->m_uninitializedFloatingWidgets.empty()) {
1195 d->m_uninitializedFloatingWidgets.clear();
Auto hide container for hosting an auto hide dock widget
void collapseView(bool enable)
Container that manages a number of dock panels with single dock widgets or tabyfied dock widgets in e...
DockPanel * lastAddedDockPanel(Qx::DockWidgetArea area) const
This function returns the last added dock panel for the given area identifier or 0 if no dock panel h...
DockPanel * addDockWidget(Qx::DockWidgetArea area, DockWidget *w, DockPanel *p=nullptr, int index=-1)
Adds dockwidget into the given area.
void createRootSplitter()
void createSideTabBarWidgets()
void removeDockWidget(DockWidget *w)
int dockPanelCount() const
DockPanel * dockPanel(int index) const
DockWidget::DockWidgetFeatures features() const
This functions returns the dock widget features of all dock widget in this container.
DockAutoHideContainer * createAndSetupAutoHideContainer(Qx::DockSideBarArea area, DockWidget *w, int tabIndex=-1)
Creates and initializes a dockwidget auto hide container into the given area.
DockFloatingContainer * floatingWidget() const
If this dock container is in a floating widget, this function returns the floating widget.
bool hasOpenDockPanels() const
This function returns true, if the container has open dock panels.
This implements a floating widget that is a dock container that accepts docking of dock widgets like ...
DockContainer * dockContainer() const
QList< DockWidget * > dockWidgets() const
This function returns a list of all dock widget in this floating widget.
Manages focus styling of dock widgets and handling of focus changes
@ XmlAutoFormattingEnabled
static ConfigFlags configFlags()
DockOverlay paints a translucent rectangle over another widget.
DockPanel manages multiple instances of DockWidgets.
DockSplitter * parentSplitter() const
DockContainer * dockContainer() const
@ HideSingleWidgetTitleBar
void setDockAreaFlag(DockAreaFlag flag, bool on)
void removeDockWidget(DockWidget *w)
The central dock window that maintains the complete docking system.
void removeDockContainer(DockContainer *container)
DockWidget * findDockWidget(const QString &objectName) const
Searches for a registered dock widget with the given objectName
void perspectiveListChanged()
const QList< DockContainer * > dockContainers() const
Returns the list of all active and visible dock containers Dock containers are the main dock manager ...
void removePerspectives(const QStringList &names)
void removeDockWidget(DockWidget *w)
DockAutoHideContainer * addAutoHideDockWidget(Qx::DockSideBarArea area, DockWidget *w)
Adds an Auto-Hide widget to the dock window container pinned to the given side bar area.
bool isLeavingMinimizedState() const
This function returns true, if the DockWindow window is restoring from minimized state.
void removePerspective(const QString &name)
void dockWidgetAboutToBeRemoved(DockWidget *w)
QStringList perspectiveNames() const
void endLeavingMinimizedState()
void dockWidgetAdded(DockWidget *w)
DockAutoHideContainer * addAutoHideDockWidgetToContainer(Qx::DockSideBarArea area, DockWidget *w, DockContainer *container)
Adds an Auto-Hide widget to the given container pinned to the given side bar area in this container.
void openPerspective(const QString &perspectiveName)
void removeFloatingWidget(DockFloatingContainer *floatingWidget)
Qt::ToolButtonStyle dockWidgetToolBarStyle(DockWidget::State state) const
void dockWidgetRemoved(DockWidget *w)
bool isRestoringState() const
This function returns true between the restoringState() and stateRestored() signals.
QByteArray saveState(int version=0) const
Saves the current state of the dockwindow and all its dock widgets into the returned QByteArray.
DockWidget::DockWidgetFeatures globallyLockedDockWidgetFeatures() const
Returns all dock widget features that are globally locked by the dock window.
QMap< QString, DockWidget * > dockWidgetsMap() const
This function returns a readable reference to the internal dock widgets map so that it is possible to...
bool eventFilter(QObject *obj, QEvent *e) override
friend class DockFloatingContainer
void addPerspective(const QString &uniquePrespectiveName)
Saves the current perspective to the internal list of perspectives.
void setDockWidgetToolBarStyle(Qt::ToolButtonStyle style, DockWidget::State state)
This function sets the tool button style for the given dock widget state.
DockPanel * setCentralWidget(DockWidget *widget)
Adds dockwidget widget into the central area and marks it as central widget.
void notifyDockAreaRelocation(QWidget *droppedWidget)
void lockDockWidgetFeaturesGlobally(DockWidget::DockWidgetFeatures features=DockWidget::GloballyLockableFeatures)
Globally Lock features of all dock widgets to "freeze" the current workspace layout.
DockOverlay * panelOverlay() const
void floatingWidgetCreated(DockFloatingContainer *floatingWidget)
void perspectiveOpened(const QString &perspectiveName)
DockFloatingContainer * addDockWidgetFloating(DockWidget *w)
Adds the given DockWidget floating and returns the created DockFloatingContainer instance.
DockPanel * addDockWidgetTab(Qx::DockWidgetArea area, DockWidget *w)
This function will add the given DockWidget to the given dock area as a new tab.
void setDockWidgetFocused(DockWidget *w)
Request a focus change to the given dock widget.
void perspectiveListLoaded()
void setSplitterSizes(DockPanel *panel, const QList< int > &sizes)
Update the sizes of a splitter Programmatically updates the sizes of a given splitter by calling QSpl...
void perspectivesRemoved()
void savePerspectives(QSettings &settings) const
void setDockWidgetToolBarIconSize(const QSize &iconSize, DockWidget::State state)
This function sets the tool button icon size for the given state.
void hideWindowAndFloatingWidgets()
hide DockWindow and all floating widgets.
DockWidget * centralWidget() const
void loadPerspectives(QSettings &settings)
DockFocusController * dockFocusController() const
void notifyFloatingWidgetDrop(DockFloatingContainer *floatingWidget)
QList< int > splitterSizes(DockPanel *panel) const
Returns the sizes of the splitter that contains the dock panel.
void restoreHiddenFloatingWidgets()
DockOverlay * containerOverlay() const
void openingPerspective(const QString &perspectiveName)
void registerDockContainer(DockContainer *container)
void registerFloatingWidget(DockFloatingContainer *floatingWidget)
bool restoreState(const QByteArray &state, int version=0)
Restores the state of this dockwindow dockwidgets.
QSize dockWidgetToolBarIconSize(DockWidget::State state) const
DockPanel * addDockWidgetToContainer(Qx::DockWidgetArea area, DockWidget *w, DockContainer *container)
Adds dockwidget into the given container.
virtual void showEvent(QShowEvent *e) override
DockPanel * addDockWidget(Qx::DockWidgetArea area, DockWidget *w, DockPanel *p=nullptr, int index=-1)
Adds dockwidget into the given area.
@ CurrentVersion
CurrentVersion
@ InitialVersion
InitialVersion
#define QX_INIT_PRIVATE(Class)
#define QX_DECLARE_PUBLIC(Class)
#define QX_FINI_PRIVATE()
#define QX_DOCK_END_NAMESPACE
#define QX_DOCK_BEGIN_NAMESPACE