QtCanpool 3.3.0
载入中...
搜索中...
未找到
dockwindow.cpp
浏览该文件的文档.
1
6#include "dockwindow.h"
7#include "dockpanel.h"
8#include "dockwidget.h"
10#include "dockoverlay.h"
11#include "dockfocuscontroller.h"
12#include "dockmanager.h"
14#include "dockutils.h"
15#include "dockstatereader.h"
16#include "docksplitter.h"
17
18#if QX_DOCK_X11
20#endif
21
22#include <QWindowStateChangeEvent>
23#include <QXmlStreamWriter>
24#include <QFile>
25#include <QSettings>
26#include <QTextStream>
27#include <QPointer>
28#include <QDebug>
29#include <QApplication>
30#include <QAction>
31
33
39
40class DockWindowPrivate
41{
42public:
43 QX_DECLARE_PUBLIC(DockWindow)
44public:
45 DockWindowPrivate();
46
47 void init();
48 void loadStylesheet();
49
50 void mapDockWidget(DockWidget *w);
51
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);
56
57 void restoreDockWidgetsOpenState();
58 void restoreDockAreasIndices();
59 void emitTopLevelEvents();
60 void hideFloatingWidgets();
61 void markDockWidgetsDirty();
62public:
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;
80};
81
82DockWindowPrivate::DockWindowPrivate()
83{
84}
85
86void DockWindowPrivate::init()
87{
88 Q_Q(DockWindow);
89
90 m_containerOverlay = new DockOverlay(q, DockOverlay::PanelOverlayMode);
91 m_panelOverlay = new DockOverlay(q, DockOverlay::ContainerOverlayMode);
92
93 if (DockManager::testConfigFlag(DockManager::FocusHighlighting)) {
94 m_focusController = new DockFocusController(q);
95 }
96
97#ifndef QX_DOCK_DEBUG
98 loadStylesheet();
99#endif
100}
101
102void DockWindowPrivate::loadStylesheet()
103{
104 Q_Q(DockWindow);
105 QString result;
106 QString fileName = ":/qxdock/res/stylesheets/";
107 fileName += DockManager::testConfigFlag(DockManager::FocusHighlighting) ? "focus_highlighting" : "default";
108#if QX_DOCK_X11
109 fileName += "_linux";
110#endif
111 fileName += ".css";
112 QFile styleSheetFile(fileName);
113 styleSheetFile.open(QIODevice::ReadOnly);
114 QTextStream styleSheetStream(&styleSheetFile);
115 result = styleSheetStream.readAll();
116 styleSheetFile.close();
117 q->setStyleSheet(result);
118}
119
120void DockWindowPrivate::mapDockWidget(DockWidget *w)
121{
122 const QString &objname = w->objectName();
123 DockWidget *oldWidget = m_dockWidgetsMap.value(objname, nullptr);
124 if (oldWidget) {
125 qWarning() << QString("Object name (%1) of DockWidget already exists.").arg(objname);
126 }
127 m_dockWidgetsMap.insert(objname, w);
128}
129
130bool DockWindowPrivate::checkFormat(const QByteArray &state, int version)
131{
132 return restoreStateFromXml(state, version, internal::RestoreTesting);
133}
134
135bool DockWindowPrivate::restoreStateFromXml(const QByteArray &state, int version, bool testing)
136{
137 Q_UNUSED(version);
138 Q_Q(DockWindow);
139
140 if (state.isEmpty()) {
141 return false;
142 }
143 DockStateReader s(state);
144 s.readNextStartElement();
145 if (s.name() != QLatin1String("QxDock")) {
146 return false;
147 }
148 bool ok;
149 int v = s.attributes().value("Version").toInt(&ok);
150 if (!ok || v > CurrentVersion) {
151 return false;
152 }
153 s.setFileVersion(v);
154
155 // Older files do not support UserVersion but we still want to load them so
156 // we first test if the attribute exists
157 if (!s.attributes().value("UserVersion").isEmpty()) {
158 v = s.attributes().value("UserVersion").toInt(&ok);
159 if (!ok || v != version) {
160 return false;
161 }
162 }
163
164 bool result = true;
165
166 if (m_centralWidget) {
167 const auto centralWidgetAttribute = s.attributes().value("CentralWidget");
168 // If we have a central widget but a state without central widget, then
169 // something is wrong.
170 if (centralWidgetAttribute.isEmpty()) {
171 qWarning() << "Dock window has central widget but saved state does not have central widget.";
172 return false;
173 }
174
175 // If the object name of the central widget does not match the name of the
176 // saved central widget, the something is wrong
177 if (m_centralWidget->objectName() != centralWidgetAttribute.toString()) {
178 qWarning() << "Object name of central widget does not match name of central widget in saved state.";
179 return false;
180 }
181 }
182
183 int dockContainerCount = 0;
184 while (s.readNextStartElement()) {
185 if (s.name() == QLatin1String("Container")) {
186 result = restoreContainer(dockContainerCount, s, testing);
187 if (!result) {
188 break;
189 }
190 dockContainerCount++;
191 }
192 }
193
194 if (!testing) {
195 // Delete remaining empty floating widgets
196 int floatingWidgetIndex = dockContainerCount - 1;
197 for (int i = floatingWidgetIndex; i < m_floatingContainers.count(); ++i) {
198 DockFloatingContainer *floatingWidget = m_floatingContainers[i];
199 if (!floatingWidget)
200 continue;
201 q->removeDockContainer(floatingWidget->dockContainer());
202 floatingWidget->deleteLater();
203 }
204 }
205
206 return result;
207}
208
209bool DockWindowPrivate::restoreContainer(int index, DockStateReader &stream, bool testing)
210{
211 Q_Q(DockWindow);
212 if (testing) {
213 index = 0;
214 }
215
216 bool result = false;
217 if (index >= m_containers.count()) {
218 DockFloatingContainer *floatingWidget = new DockFloatingContainer(q);
219 result = floatingWidget->restoreState(stream, testing);
220 } else {
221 auto container = m_containers[index];
222 if (container->isFloating()) {
223 result = container->floatingWidget()->restoreState(stream, testing);
224 } else {
225 result = container->restoreState(stream, testing);
226 }
227 }
228
229 return result;
230}
231
232bool DockWindowPrivate::restoreState(const QByteArray &state, int version)
233{
234 QByteArray s = state.startsWith("<?xml") ? state : qUncompress(state);
235 if (!checkFormat(s, version)) {
236 return false;
237 }
238
239 // Hide updates of floating widgets from use
240 hideFloatingWidgets();
241 markDockWidgetsDirty();
242
243 if (!restoreStateFromXml(s, version)) {
244 return false;
245 }
246
247 restoreDockWidgetsOpenState();
248 restoreDockAreasIndices();
249 emitTopLevelEvents();
250
251 return true;
252}
253
254void DockWindowPrivate::restoreDockWidgetsOpenState()
255{
256 // All dock widgets, that have not been processed in the restore state
257 // function are invisible to the user now and have no assigned dock area
258 // They do not belong to any dock container, until the user toggles the
259 // toggle view action the next time
260 for (auto dockWidget : m_dockWidgetsMap) {
261 if (dockWidget->property(internal::DirtyProperty).toBool()) {
262 // If the DockWidget is an auto hide widget that is not assigned yet,
263 // then we need to delete the auto hide container now
264 if (dockWidget->isAutoHide()) {
265 dockWidget->autoHideContainer()->cleanupAndDelete();
266 }
267 dockWidget->flagAsUnassigned();
268 Q_EMIT dockWidget->viewToggled(false);
269 } else {
270 dockWidget->toggleViewInternal(!dockWidget->property(internal::ClosedProperty).toBool());
271 }
272 }
273}
274
275void DockWindowPrivate::restoreDockAreasIndices()
276{
277 Q_Q(DockWindow);
278 // Now all dock panels are properly restored and we setup the index of
279 // The dock panels because the previous toggleView() action has changed
280 // the dock panel index
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);
288 }
289
290 if (!dockWidget || dockWidget->isClosed()) {
291 int index = panel->indexOfFirstOpenDockWidget();
292 if (index < 0) {
293 continue;
294 }
295 panel->setCurrentIndex(index);
296 } else {
297 panel->internalSetCurrentDockWidget(dockWidget);
298 }
299 }
300 }
301}
302
303void DockWindowPrivate::emitTopLevelEvents()
304{
305 // Finally we need to send the topLevelChanged() signals for all dock
306 // widgets if top level changed
307 for (auto dockContainer : m_containers) {
308 DockWidget *topLevelWidget = dockContainer->topLevelDockWidget();
309 if (topLevelWidget) {
310 topLevelWidget->emitTopLevelChanged(true);
311 } else {
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);
316 }
317 }
318 }
319 }
320}
321
322void DockWindowPrivate::hideFloatingWidgets()
323{
324 // Hide updates of floating widgets from user
325 for (auto floatingWidget : m_floatingContainers) {
326 if (floatingWidget) {
327 floatingWidget->hide();
328 }
329 }
330}
331
332void DockWindowPrivate::markDockWidgetsDirty()
333{
334 for (auto dockWidget : m_dockWidgetsMap) {
335 dockWidget->setProperty(internal::DirtyProperty, true);
336 }
337}
338
339DockWindow::DockWindow(QWidget *parent)
340 : DockContainer{this, parent}
341{
345 Q_D(DockWindow);
346 d->init();
348
349 window()->installEventFilter(this);
350
351#if QX_DOCK_X11
352 connect(qApp, &QApplication::focusWindowChanged, [](QWindow *focusWindow) {
353 // bring modal dialogs to foreground to ensure that they are in front of any
354 // floating dock widget
355 if (focusWindow && focusWindow->isModal()) {
356 focusWindow->raise();
357 }
358 });
359#endif
360}
361
363{
364 Q_D(DockWindow);
365 std::vector<QPointer<DockPanel>> panels;
366 for (int i = 0; i < dockPanelCount(); ++i) {
367 panels.push_back(dockPanel(i));
368 }
369 for (auto p : panels) {
370 if (!p || p->dockWindow() != this) {
371 continue;
372 }
373 std::vector<QPointer<QWidget>> deleteWidgets;
374 for (auto w : p->dockWidgets()) {
375 deleteWidgets.push_back(w);
376 }
377 for (auto w : deleteWidgets) {
378 delete w;
379 }
380 }
381
382 auto floatingContainers = d->m_floatingContainers;
383 for (auto c : floatingContainers) {
384 c->deleteContent();
385 delete c;
386 }
387
388 for (auto p : panels) {
389 delete p;
390 }
391
393}
394
415{
416 Q_D(DockWindow);
417 d->mapDockWidget(w);
418 DockContainer *container = p ? p->dockContainer() : this;
419 if (container == nullptr) {
420 container = this;
421 p = nullptr; // panel is not contained by any container, can not be used again
422 }
423 DockPanel *panel = container->addDockWidget(area, w, p, index);
424 if (panel) {
425 Q_EMIT dockWidgetAdded(w);
426 }
427 return panel;
428}
429
435{
436 DockPanel *panel = lastAddedDockPanel(area);
437 if (panel) {
438 return addDockWidget(Qx::CenterDockWidgetArea, w, panel);
439 } else {
440 return addDockWidget(area, w, nullptr);
441 }
442}
443
453
461{
462 Q_D(DockWindow);
463 d->mapDockWidget(w);
464 auto panel = container->addDockWidget(area, w);
465 Q_EMIT dockWidgetAdded(w);
466 return panel;
467}
468
470{
471 Q_D(DockWindow);
473 d->m_dockWidgetsMap.remove(w->objectName());
475 w->setDockWindow(nullptr);
476 Q_EMIT dockWidgetRemoved(w);
477}
478
484DockWidget *DockWindow::findDockWidget(const QString &objectName) const
485{
486 Q_D(const DockWindow);
487 return d->m_dockWidgetsMap.value(objectName, nullptr);
488}
489
499
506 DockContainer *container)
507{
508 Q_D(DockWindow);
509 if (area == Qx::DockSideBarNone) {
510 return nullptr;
511 }
512 d->mapDockWidget(w);
513 auto c = container->createAndSetupAutoHideContainer(area, w);
514 c->collapseView(true);
515
516 Q_EMIT dockWidgetAdded(w);
517 return c;
518}
519
525{
526 Q_D(DockWindow);
527 d->mapDockWidget(w);
528 DockPanel *oldPanel = w->dockPanel();
529 if (oldPanel) {
530 oldPanel->removeDockWidget(w);
531 }
532
533 w->setDockWindow(this);
535 floatingWidget->resize(w->size());
536 if (isVisible()) {
537 floatingWidget->show();
538 } else {
539 d->m_uninitializedFloatingWidgets.append(floatingWidget);
540 }
541 Q_EMIT dockWidgetAdded(w);
542 return floatingWidget;
543}
544
549const QList<DockContainer *> DockWindow::dockContainers() const
550{
551 Q_D(const DockWindow);
552 return d->m_containers;
553}
554
559QMap<QString, DockWidget *> DockWindow::dockWidgetsMap() const
560{
561 Q_D(const DockWindow);
562 return d->m_dockWidgetsMap;
563}
564
566{
567 Q_D(const DockWindow);
568 return d->m_centralWidget;
569}
570
593{
594 Q_D(DockWindow);
595 if (!widget) {
596 d->m_centralWidget = nullptr;
597 return nullptr;
598 }
599
600 // Setting a new central widget is not allowed if there is already a central
601 // widget or if there are already other dock widgets
602 if (d->m_centralWidget) {
603 qWarning("Setting a central widget not possible because there is already a central widget.");
604 return nullptr;
605 }
606
607 // Setting a central widget is not allowed if there are already other dock widgets.
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.");
611 return nullptr;
612 }
613
618 d->m_centralWidget = widget;
619 DockPanel *centralPanel = addDockWidget(Qx::CenterDockWidgetArea, widget);
621 return centralPanel;
622}
623
632{
633 Q_D(const DockWindow);
634 return d->m_isLeavingMinimized;
635}
636
638{
639 Q_D(const DockWindow);
640 if (DockWidget::StateFloating == state) {
641 return d->m_toolBarStyleFloating;
642 } else {
643 return d->m_toolBarStyleDocked;
644 }
645}
646
655void DockWindow::setDockWidgetToolBarStyle(Qt::ToolButtonStyle style, DockWidget::State state)
656{
657 Q_D(DockWindow);
658 if (DockWidget::StateFloating == state) {
659 d->m_toolBarStyleFloating = style;
660 } else {
661 d->m_toolBarStyleDocked = style;
662 }
663}
664
666{
667 Q_D(const DockWindow);
668 if (DockWidget::StateFloating == state) {
669 return d->m_toolBarIconSizeFloating;
670 } else {
671 return d->m_toolBarIconSizeDocked;
672 }
673}
674
682{
683 Q_D(DockWindow);
684 if (DockWidget::StateFloating == state) {
685 d->m_toolBarIconSizeFloating = iconSize;
686 } else {
687 d->m_toolBarIconSizeDocked = iconSize;
688 }
689}
690
695DockWidget::DockWidgetFeatures DockWindow::globallyLockedDockWidgetFeatures() const
696{
697 Q_D(const DockWindow);
698 return d->m_lockedDockWidgetFeatures;
699}
700
722void DockWindow::lockDockWidgetFeaturesGlobally(DockWidget::DockWidgetFeatures features)
723{
724 Q_D(DockWindow);
725 // Limit the features to DockWidget::GloballyLockableFeatures
727 if (d->m_lockedDockWidgetFeatures == features) {
728 return;
729 }
730
731 d->m_lockedDockWidgetFeatures = features;
732 // Call the notifyFeaturesChanged() function for all dock widgets to update
733 // the state of the close and detach buttons
734 for (auto w : d->m_dockWidgetsMap) {
735 w->notifyFeaturesChanged();
736 }
737}
738
745QList<int> DockWindow::splitterSizes(DockPanel *panel) const
746{
747 if (panel) {
748 auto splitter = panel->parentSplitter();
749 if (splitter) {
750 return splitter->sizes();
751 }
752 }
753 return QList<int>();
754}
755
765void DockWindow::setSplitterSizes(DockPanel *panel, const QList<int> &sizes)
766{
767 if (!panel) {
768 return;
769 }
770
771 auto splitter = panel->parentSplitter();
772 if (splitter && splitter->count() == sizes.count()) {
773 splitter->setSizes(sizes);
774 }
775}
776
789QByteArray DockWindow::saveState(int version) const
790{
791 Q_D(const DockWindow);
792 QByteArray xmldata;
793 QXmlStreamWriter s(&xmldata);
794 auto configFlags = DockManager::configFlags();
795 s.setAutoFormatting(configFlags.testFlag(DockManager::XmlAutoFormattingEnabled));
796
797 s.writeStartDocument();
798 s.writeStartElement("QxDock");
799
800 s.writeAttribute("Version", QString::number(CurrentVersion));
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());
805 }
806 for (auto container : d->m_containers) {
807 container->saveState(s);
808 }
809
810 s.writeEndElement();
811 s.writeEndDocument();
812
813 return configFlags.testFlag(DockManager::XmlCompressionEnabled) ? qCompress(xmldata, 9) : xmldata;
814}
815
824bool DockWindow::restoreState(const QByteArray &state, int version)
825{
826 Q_D(DockWindow);
827 // Prevent multiple calls as long as state is not restore. This may
828 // happen, if QApplication::processEvents() is called somewhere
829 if (d->m_restoringState) {
830 return false;
831 }
832
833 // We hide the complete dock window here. Restoring the state means
834 // that DockWidgets are removed from the DockArea internal stack layout
835 // which in turn means, that each time a widget is removed the stack
836 // will show and raise the next available widget which in turn
837 // triggers show events for the dock widgets. To avoid this we hide the
838 // dock window. Because there will be no processing of application
839 // events until this function is finished, the user will not see this
840 // hiding
841 bool isHidden = this->isHidden();
842 if (!isHidden) {
843 hide();
844 }
845 d->m_restoringState = true;
846 Q_EMIT restoringState();
847 bool result = d->restoreState(state, version);
848 d->m_restoringState = false;
849 if (!isHidden) {
850 show();
851 }
852 Q_EMIT stateRestored();
853 return result;
854}
855
861{
862 Q_D(const DockWindow);
863 return d->m_restoringState;
864}
865
874void DockWindow::addPerspective(const QString &uniquePrespectiveName)
875{
876 Q_D(DockWindow);
877 d->m_perspectives.insert(uniquePrespectiveName, saveState());
878 Q_EMIT perspectiveListChanged();
879}
880
882{
884}
885
886void DockWindow::removePerspectives(const QStringList &names)
887{
888 Q_D(DockWindow);
889 int count = 0;
890 for (const auto &name : names) {
891 count += d->m_perspectives.remove(name);
892 }
893
894 if (count) {
895 Q_EMIT perspectivesRemoved();
896 Q_EMIT perspectiveListChanged();
897 }
898}
899
901{
902 Q_D(const DockWindow);
903 return d->m_perspectives.keys();
904}
905
906void DockWindow::savePerspectives(QSettings &settings) const
907{
908 settings.beginWriteArray("Perspectives", d_ptr->m_perspectives.size());
909 int i = 0;
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());
914 ++i;
915 }
916 settings.endArray();
917}
918
919void DockWindow::loadPerspectives(QSettings &settings)
920{
921 Q_D(DockWindow);
922 d->m_perspectives.clear();
923 int size = settings.beginReadArray("Perspectives");
924 if (!size) {
925 settings.endArray();
926 return;
927 }
928
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()) {
934 continue;
935 }
936
937 d->m_perspectives.insert(name, data);
938 }
939
940 settings.endArray();
941 Q_EMIT perspectiveListChanged();
942 Q_EMIT perspectiveListLoaded();
943}
944
951{
952 Q_D(DockWindow);
953 if (d->m_focusController) {
954 d->m_focusController->setDockWidgetFocused(w);
955 }
956}
957
959{
960 Q_D(DockWindow);
961 d->m_isLeavingMinimized = false;
962 this->activateWindow();
963}
964
965void DockWindow::openPerspective(const QString &perspectiveName)
966{
967 Q_D(DockWindow);
968 const auto iterator = d->m_perspectives.find(perspectiveName);
969 if (d->m_perspectives.end() == iterator) {
970 return;
971 }
972
973 Q_EMIT openingPerspective(perspectiveName);
974 restoreState(iterator.value());
975 Q_EMIT perspectiveOpened(perspectiveName);
976}
977
983{
984 Q_D(DockWindow);
985 hide();
986
987 d->m_hiddenFloatingContainers.clear();
988 // Hide updates of floating widgets from user
989 for (auto floatingWidget : d->m_floatingContainers) {
990 if (floatingWidget->isVisible()) {
991 QList<DockWidget *> visibleWidgets;
992 for (auto dockWidget : floatingWidget->dockWidgets()) {
993 if (dockWidget->toggleViewAction()->isChecked())
994 visibleWidgets.push_back(dockWidget);
995 }
996
997 // save as floating widget to be shown when DockWindow will be shown back
998 d->m_hiddenFloatingContainers.push_back(floatingWidget);
999 floatingWidget->hide();
1000
1001 // hiding floating widget automatically marked contained DockWidgets as hidden
1002 // but they must remain marked as visible as we want them to be restored visible
1003 // when DockWindow will be shown back
1004 for (auto dockWidget : visibleWidgets) {
1005 dockWidget->toggleViewAction()->setChecked(true);
1006 }
1007 }
1008 }
1009}
1010
1012{
1013 Q_D(DockWindow);
1014 d->m_containers.append(container);
1015}
1016
1018{
1019 Q_D(DockWindow);
1020
1021 // A container that is a child of this window is destroyed by ~QWidget(),
1022 // which runs after ~DockWindow() deleted the private data. Dropping it from
1023 // a list that is going away anyway is a no-op, not a reason to crash.
1024 if (d && this != container) {
1025 d->m_containers.removeAll(container);
1026 }
1027}
1028
1030{
1031 Q_D(DockWindow);
1032 d->m_floatingContainers.append(floatingWidget);
1034}
1035
1037{
1038 Q_D(DockWindow);
1039 d->m_floatingContainers.removeAll(floatingWidget);
1040}
1041
1043{
1044 Q_D(const DockWindow);
1045 return d->m_containerOverlay;
1046}
1047
1049{
1050 Q_D(const DockWindow);
1051 return d->m_panelOverlay;
1052}
1053
1054void DockWindow::notifyDockAreaRelocation(QWidget *droppedWidget)
1055{
1056 Q_D(DockWindow);
1057 if (d->m_focusController) {
1058 d->m_focusController->notifyDockAreaRelocation(droppedWidget);
1059 }
1060}
1061
1063{
1064 Q_D(DockWindow);
1065 if (d->m_focusController) {
1066 d->m_focusController->notifyFloatingWidgetDrop(floatingWidget);
1067 }
1068}
1069
1071{
1072 Q_D(const DockWindow);
1073 return d->m_focusController;
1074}
1075
1077{
1078 Q_D(DockWindow);
1079 if (d->m_hiddenFloatingContainers.isEmpty()) {
1080 return;
1081 }
1082
1083 // Restore floating widgets that were hidden upon hideWindowAndFloatingWidgets
1084 for (auto floatingWidget : d->m_hiddenFloatingContainers) {
1085 bool hasDockWidgetVisible = false;
1086
1087 // Needed to prevent DockFloatingContainer being shown empty
1088 // Could make sense to move this to DockFloatingContainer::showEvent(QShowEvent *event)
1089 // if experiencing DockFloatingContainer being shown empty in other situations, but let's keep
1090 // it here for now to make sure changes to fix Issue #380 does not impact existing behaviours
1091 for (auto dockWidget : floatingWidget->dockWidgets()) {
1092 if (dockWidget->toggleViewAction()->isChecked()) {
1093 dockWidget->toggleView(true);
1094 hasDockWidgetVisible = true;
1095 }
1096 }
1097
1098 if (hasDockWidgetVisible) {
1099 floatingWidget->show();
1100 }
1101 }
1102
1103 d->m_hiddenFloatingContainers.clear();
1104}
1105
1106#if QX_DOCK_X11
1107bool DockWindow::eventFilter(QObject *obj, QEvent *e)
1108{
1109 Q_D(DockWindow);
1110 // Emulate Qt:Tool behaviour.
1111 // Required because on some WMs Tool windows can't be maximized.
1112
1113 // Window always on top of the MainWindow.
1114 if (e->type() == QEvent::WindowActivate) {
1115 for (auto _window : d->m_floatingContainers) {
1116 if (!_window->isVisible() || window()->isMinimized()) {
1117 continue;
1118 }
1119 // setWindowFlags(Qt::WindowStaysOnTopHint) will hide the window and thus requires a show call.
1120 // This then leads to flickering and a nasty endless loop (also buggy behaviour on Ubuntu).
1121 // So we just do it ourself.
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");
1125 } else {
1126 _window->setWindowFlag(Qt::WindowStaysOnTopHint, true);
1127 }
1128 }
1129 } else if (e->type() == QEvent::WindowDeactivate) {
1130 for (auto _window : d->m_floatingContainers) {
1131 if (!_window->isVisible() || window()->isMinimized()) {
1132 continue;
1133 }
1134
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");
1138 } else {
1139 _window->setWindowFlag(Qt::WindowStaysOnTopHint, false);
1140 }
1141 _window->raise();
1142 }
1143 }
1144
1145 // Sync minimize with MainWindow
1146 if (e->type() == QEvent::WindowStateChange) {
1147 for (auto _window : d->m_floatingContainers) {
1148 if (!_window->isVisible()) {
1149 continue;
1150 }
1151
1152 if (window()->isMinimized()) {
1153 _window->showMinimized();
1154 } else {
1155 _window->setWindowState(_window->windowState() & (~Qt::WindowMinimized));
1156 }
1157 }
1158 if (!window()->isMinimized()) {
1159 QApplication::setActiveWindow(window());
1160 }
1161 }
1162 return Super::eventFilter(obj, e);
1163}
1164#else
1165bool DockWindow::eventFilter(QObject *obj, QEvent *e)
1166{
1167 Q_D(DockWindow);
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);
1173 }
1174 }
1175 return Super::eventFilter(obj, e);
1176}
1177#endif
1178
1179void DockWindow::showEvent(QShowEvent *e)
1180{
1181 Q_D(DockWindow);
1182 Super::showEvent(e);
1183
1185 if (d->m_uninitializedFloatingWidgets.empty()) {
1186 return;
1187 }
1188
1189 for (auto floatingWidget : d->m_uninitializedFloatingWidgets) {
1190 // Check, if someone closed a floating dock widget before the dock window is shown
1192 floatingWidget->show();
1193 }
1194 }
1195 d->m_uninitializedFloatingWidgets.clear();
1196}
1197
Auto hide container for hosting an auto hide dock widget
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 removeDockWidget(DockWidget *w)
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 ...
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
static ConfigFlags configFlags()
DockOverlay paints a translucent rectangle over another widget.
Definition dockoverlay.h:19
DockPanel manages multiple instances of DockWidgets.
Definition dockpanel.h:31
DockSplitter * parentSplitter() const
DockContainer * dockContainer() const
void setDockAreaFlag(DockAreaFlag flag, bool on)
void removeDockWidget(DockWidget *w)
The DockWidget class provides a widget that can be docked inside a DockWindow or floated as a top-lev...
Definition dockwidget.h:31
void setDockWindow(DockWindow *window)
Assigns the dock window that manages this dock widget
DockPanel * dockPanel() const
Returns the dock panel this dock widget belongs to or 0 if this dock widget has not been docked yet
void setFeature(DockWidgetFeature flag, bool on)
Sets the feature flag for this dock widget if on is true; otherwise clears the flag.
The central dock window that maintains the complete docking system.
Definition dockwindow.h:36
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
Definition dockwindow.h:128
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.
@ Version1
Version1
@ CurrentVersion
CurrentVersion
@ InitialVersion
InitialVersion
DockSideBarArea
@ DockSideBarNone
DockWidgetArea
@ CenterDockWidgetArea
#define QX_INIT_PRIVATE(Class)
#define QX_DECLARE_PUBLIC(Class)
#define QX_FINI_PRIVATE()
#define QX_DOCK_END_NAMESPACE
#define QX_DOCK_BEGIN_NAMESPACE
const char * fileName
Definition qxtheme.cpp:26
const char * name
Definition qxtheme.cpp:25
QColor window