// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "fancymainwindow.h" #include "algorithm.h" #include "qtcassert.h" #include "qtcsettings.h" #include "stringutils.h" #include "styledbar.h" #include "utilsicons.h" #include "utilstr.h" #include #include #include #include #include #include #include #include #include #include #include static const char ShowCentralWidgetKey[] = "ShowCentralWidget"; static const char StateKey[] = "State"; static const char HiddenDockAreasKey[] = "HiddenDockAreas"; static const char DockWidgetStatesKey[] = "CollapseState"; static const int settingsVersion = 2; static const char dockWidgetActiveState[] = "DockWidgetActiveState"; namespace Utils { class TitleBarWidget; struct DocksAndSizes { QList docks; QList sizes; QVariantMap toMap() const; static DocksAndSizes fromMap(const QVariantMap &store, const QList &allDocks); }; const char kDocksAndSizesDocks[] = "Docks"; const char kDocksAndSizesSizes[] = "Sizes"; QVariantMap DocksAndSizes::toMap() const { return {{kDocksAndSizesDocks, QVariant::fromValue(transform(docks, [](QDockWidget *w) { return w->objectName(); }))}, {kDocksAndSizesSizes, QVariant::fromValue(sizes)}}; } DocksAndSizes DocksAndSizes::fromMap(const QVariantMap &store, const QList &docks) { DocksAndSizes info; info.docks = transform(store.value(kDocksAndSizesDocks).toStringList(), [docks](const QString &objectName) { return findOrDefault(docks, [objectName](QDockWidget *w) { return w->objectName() == objectName; }); }); info.sizes = store.value(kDocksAndSizesSizes).value>(); // clean up for docks that could not be found for (int i = 0; i < info.docks.size(); ++i) { if (!info.docks.at(i)) { info.docks.removeAt(i); if (i < info.sizes.size()) info.sizes.removeAt(i); } } return info; } struct FancyMainWindowPrivate { FancyMainWindowPrivate(FancyMainWindow *parent); QVariantHash hiddenDockAreasToHash() const; void restoreHiddenDockAreasFromHash(const QVariantHash &hash); FancyMainWindow *q; bool m_handleDockVisibilityChanges; QAction m_showCentralWidget; QAction m_menuSeparator1; QAction m_resetLayoutAction; QHash m_hiddenAreas; // Qt::DockWidgetArea -> dock widgets // Usually dock widgets automatically uncollapse when e.g. other docks are hidden // and they are the only one left. We need to block that when hiding a complete // dock area to not change the collapse state bool m_blockAutoUncollapse = false; }; class DockWidget : public QDockWidget { Q_OBJECT public: DockWidget(QWidget *inner, FancyMainWindow *parent, bool immutable = false); ~DockWidget(); bool supportsCollapse(); bool isCollapsed() const; void setCollapsed(bool collapse); QVariant saveState() const; void restoreState(const QVariant &data); FancyMainWindow *q; signals: void collapseChanged(); private: QList docksInArea(); void setInnerWidgetShown(bool visible); DocksAndSizes verticallyArrangedDocks(); QWidget *m_hiddenInnerWidget = nullptr; int m_hiddenInnerWidgetHeight = 0; TitleBarWidget *m_titleBar; }; // Stolen from QDockWidgetTitleButton class DockWidgetTitleButton : public QAbstractButton { public: DockWidgetTitleButton(QWidget *parent) : QAbstractButton(parent) { setFocusPolicy(Qt::NoFocus); } QSize sizeHint() const override { ensurePolished(); int size = 2*style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, nullptr, this); if (!icon().isNull()) { int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this); QSize sz = icon().actualSize(QSize(iconSize, iconSize)); size += qMax(sz.width(), sz.height()); } return QSize(size, size); } QSize minimumSizeHint() const override { return sizeHint(); } void enterEvent(QEnterEvent *event) override { if (isEnabled()) update(); QAbstractButton::enterEvent(event); } void leaveEvent(QEvent *event) override { if (isEnabled()) update(); QAbstractButton::leaveEvent(event); } void paintEvent(QPaintEvent *event) override; }; const int titleMinWidth = 10; const int titleMaxWidth = 10000; const int titleInactiveHeight = 0; void DockWidgetTitleButton::paintEvent(QPaintEvent *) { QPainter p(this); QStyleOptionToolButton opt; opt.initFrom(this); opt.state |= QStyle::State_AutoRaise; opt.icon = icon(); opt.subControls = {}; opt.activeSubControls = {}; opt.features = QStyleOptionToolButton::None; opt.arrowType = Qt::NoArrow; int size = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this); opt.iconSize = QSize(size, size); style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, this); } class TitleBarWidget : public StyledBar { public: TitleBarWidget(DockWidget *parent) : StyledBar(parent) , q(parent) { m_titleLabel = new QLabel(this); m_collapseButton = new DockWidgetTitleButton(this); updateCollapse(); connect(m_collapseButton, &DockWidgetTitleButton::clicked, this, &TitleBarWidget::toggleCollapse); connect(q->q, &FancyMainWindow::dockWidgetsChanged, this, &TitleBarWidget::updateCollapse); connect(q, &DockWidget::collapseChanged, this, &TitleBarWidget::updateCollapse); m_floatButton = new DockWidgetTitleButton(this); m_floatButton->setIcon( Icon({{":/utils/images/app-on-top.png", Theme::IconsBaseColor}}).icon()); m_closeButton = new DockWidgetTitleButton(this); m_closeButton->setIcon(Icons::CLOSE_TOOLBAR.icon()); #ifndef QT_NO_ACCESSIBILITY m_floatButton->setAccessibleName(QDockWidget::tr("Float")); m_floatButton->setAccessibleDescription(QDockWidget::tr("Undocks and re-attaches the dock widget")); m_closeButton->setAccessibleName(QDockWidget::tr("Close")); m_closeButton->setAccessibleDescription(QDockWidget::tr("Closes the dock widget")); #endif auto layout = new QHBoxLayout(this); layout->setSpacing(0); layout->setContentsMargins(4, 0, 0, 0); layout->addWidget(m_collapseButton); layout->addWidget(m_titleLabel); layout->addStretch(); layout->addWidget(m_floatButton); layout->addWidget(m_closeButton); setLayout(layout); m_closeButton->setVisible(false); m_floatButton->setVisible(false); connect(parent, &QDockWidget::featuresChanged, this, [this] { updateChildren(); }); } void enterEvent(QEnterEvent *event) override { m_hovered = true; QWidget::enterEvent(event); updateChildren(); } void leaveEvent(QEvent *event) override { m_hovered = false; QWidget::leaveEvent(event); updateChildren(); } void setActive(bool on) { m_active = on; updateChildren(); } void updateChildren() { setVisible(m_active); m_floatButton->setVisible(m_hovered && q->features().testFlag(QDockWidget::DockWidgetFloatable)); m_closeButton->setVisible(m_hovered && q->features().testFlag(QDockWidget::DockWidgetClosable)); updateCollapse(); } QSize sizeHint() const override { ensurePolished(); return m_active ? QSize(titleMaxWidth, StyledBar::minimumHeight()) : QSize(titleMaxWidth, titleInactiveHeight); } QSize minimumSizeHint() const override { ensurePolished(); return m_active ? QSize(titleMinWidth, StyledBar::minimumHeight()) : QSize(titleMinWidth, titleInactiveHeight); } void toggleCollapse() { q->setCollapsed(!q->isCollapsed()); } void updateCollapse() { const bool supported = q->supportsCollapse(); m_collapseButton->setVisible(supported); if (q->isCollapsed()) m_collapseButton->setIcon(Icons::NEXT_TOOLBAR.icon()); else m_collapseButton->setIcon(Icons::ARROW_DOWN_TOOLBAR.icon()); } private: DockWidget *q; bool m_active = true; bool m_hovered = false; public: QLabel *m_titleLabel; DockWidgetTitleButton *m_collapseButton; DockWidgetTitleButton *m_floatButton; DockWidgetTitleButton *m_closeButton; }; DockWidget::DockWidget(QWidget *inner, FancyMainWindow *parent, bool immutable) : QDockWidget(parent) , q(parent) { setWidget(inner); setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable); setObjectName(inner->objectName() + QLatin1String("DockWidget")); setMouseTracking(true); QString title = inner->windowTitle(); toggleViewAction()->setProperty("original_title", title); title = stripAccelerator(title); setWindowTitle(title); QStyleOptionDockWidget opt; initStyleOption(&opt); m_titleBar = new TitleBarWidget(this); m_titleBar->m_titleLabel->setText(title); setTitleBarWidget(m_titleBar); if (immutable) { m_titleBar->setActive(false); return; } connect(toggleViewAction(), &QAction::triggered, this, [this] { if (isVisible()) raise(); }); auto origFloatButton = findChild(QLatin1String("qt_dockwidget_floatbutton")); connect(m_titleBar->m_floatButton, &QAbstractButton::clicked, origFloatButton, &QAbstractButton::clicked); auto origCloseButton = findChild(QLatin1String("qt_dockwidget_closebutton")); connect(m_titleBar->m_closeButton, &QAbstractButton::clicked, origCloseButton, &QAbstractButton::clicked); connect(q, &FancyMainWindow::dockWidgetsChanged, this, [this] { if (!q->isBlockingAutomaticUncollapse() && q->isVisible() && isVisible() && !supportsCollapse()) { setInnerWidgetShown(true); } }); } DockWidget::~DockWidget() { delete m_hiddenInnerWidget; } QList DockWidget::docksInArea() { return q->docksInArea(q->dockWidgetArea(this)); } void DockWidget::setInnerWidgetShown(bool visible) { if (visible && m_hiddenInnerWidget) { delete widget(); setWidget(m_hiddenInnerWidget); m_hiddenInnerWidget = nullptr; } else if (!visible && !m_hiddenInnerWidget) { m_hiddenInnerWidgetHeight = height() - m_titleBar->sizeHint().height(); m_hiddenInnerWidget = widget(); auto w = new QWidget; w->setMaximumHeight(0); setWidget(w); } } bool DockWidget::supportsCollapse() { // not if floating if (isFloating()) return false; // not if tabbed if (!filtered(q->tabifiedDockWidgets(this), [](QDockWidget *w) { return w->isVisible(); }).isEmpty()) return false; const QList inArea = docksInArea(); // not if only dock in area if (inArea.size() <= 1) return false; // not if in horizontal layout // - This is just a workaround. There could be two columns and a dock widget in the other // column at the same height as this one. In that case we wrongly return false here. if (anyOf(inArea, [this, y = y()](QDockWidget *w) { return w->y() == y && w != this; })) return false; return true; } bool DockWidget::isCollapsed() const { return m_hiddenInnerWidget; } void DockWidget::setCollapsed(bool collapse) { if (!supportsCollapse() || collapse == isCollapsed()) return; // save dock widget sizes before the change DocksAndSizes verticalDocks = verticallyArrangedDocks(); const auto titleBarHeight = [this] { return m_titleBar->sizeHint().height(); }; if (collapse) { setInnerWidgetShown(false); if (verticalDocks.docks.size() > 1) { // not only this dock // fixup dock sizes, so the dock below this one gets the space if possible const int selfIndex = indexOf(verticalDocks.docks, [this](QDockWidget *w) { return w == this; }); if (QTC_GUARD(0 <= selfIndex && selfIndex < verticalDocks.docks.size())) { verticalDocks.sizes[selfIndex] = titleBarHeight(); if (selfIndex + 1 < verticalDocks.sizes.size()) verticalDocks.sizes[selfIndex + 1] += m_hiddenInnerWidgetHeight; else verticalDocks.sizes[selfIndex - 1] += m_hiddenInnerWidgetHeight; q->resizeDocks(verticalDocks.docks, verticalDocks.sizes, Qt::Vertical); } } } else { setInnerWidgetShown(true); if (verticalDocks.docks.size() > 1) { // not only this dock // steal space from dock below if possible const int selfIndex = indexOf(verticalDocks.docks, [this](QDockWidget *w) { return w == this; }); if (QTC_GUARD(0 <= selfIndex && selfIndex < verticalDocks.docks.size())) { verticalDocks.sizes[selfIndex] = titleBarHeight() + m_hiddenInnerWidgetHeight; if (selfIndex + 1 < verticalDocks.sizes.size()) { verticalDocks.sizes[selfIndex + 1] = std::max(1, verticalDocks.sizes[selfIndex + 1] - m_hiddenInnerWidgetHeight); } else { verticalDocks.sizes[selfIndex - 1] = std::max(1, verticalDocks.sizes[selfIndex - 1] - m_hiddenInnerWidgetHeight); } q->resizeDocks(verticalDocks.docks, verticalDocks.sizes, Qt::Vertical); } } } emit collapseChanged(); } const char kDockWidgetInnerWidgetHeight[] = "InnerWidgetHeight"; QVariant DockWidget::saveState() const { QVariantMap state; if (m_hiddenInnerWidget) state.insert(kDockWidgetInnerWidgetHeight, m_hiddenInnerWidgetHeight); return state; } void DockWidget::restoreState(const QVariant &data) { const auto state = data.toMap(); bool ok; const int hiddenInnerWidgetHeight = state.value(kDockWidgetInnerWidgetHeight).toString().toInt(&ok); if (!ok) { // dock was not collapsed, make sure to uncollapse setInnerWidgetShown(true); return; } setInnerWidgetShown(false); m_hiddenInnerWidgetHeight = hiddenInnerWidgetHeight; } DocksAndSizes DockWidget::verticallyArrangedDocks() { DocksAndSizes result; const QList inArea = docksInArea(); // This is just a workaround. There could be two rows and a dock widget in the other row // exactly below this one. In that case we include widgets here that are not in a // vertical layout together. result.docks = filtered(inArea, [this](QDockWidget *w) { return w->x() == x() && w->width() == width(); }); Utils::sort(result.docks, [](QDockWidget *a, QDockWidget *b) { return a->y() < b->y(); }); result.sizes = transform(result.docks, [](QDockWidget *w) { return w->height(); }); return result; } /*! \class Utils::FancyMainWindow \inmodule QtCreator \brief The FancyMainWindow class is a MainWindow with dock widgets and additional "lock" functionality (locking the dock widgets in place) and "reset layout" functionality. The dock actions and the additional actions should be accessible in a Window-menu. */ FancyMainWindowPrivate::FancyMainWindowPrivate(FancyMainWindow *parent) : q(parent) , m_handleDockVisibilityChanges(true) , m_showCentralWidget(Tr::tr("Central Widget"), nullptr) , m_menuSeparator1(nullptr) , m_resetLayoutAction(Tr::tr("Reset to Default Layout"), nullptr) { m_showCentralWidget.setCheckable(true); m_showCentralWidget.setChecked(true); m_menuSeparator1.setSeparator(true); QObject::connect(&m_showCentralWidget, &QAction::toggled, q, [this](bool visible) { if (q->centralWidget()) q->centralWidget()->setVisible(visible); }); } QVariantHash FancyMainWindowPrivate::hiddenDockAreasToHash() const { QVariantHash hash; for (auto it = m_hiddenAreas.constKeyValueBegin(); it != m_hiddenAreas.constKeyValueEnd(); ++it) { hash.insert(QString::number(it->first), it->second.toMap()); } return hash; } void FancyMainWindowPrivate::restoreHiddenDockAreasFromHash(const QVariantHash &hash) { m_hiddenAreas.clear(); const QList docks = q->dockWidgets(); for (auto it = hash.constKeyValueBegin(); it != hash.constKeyValueEnd(); ++it) { bool ok; const int area = it->first.toInt(&ok); if (!ok || (area != Qt::LeftDockWidgetArea && area != Qt::TopDockWidgetArea && area != Qt::RightDockWidgetArea && area != Qt::BottomDockWidgetArea)) { continue; } const DocksAndSizes info = DocksAndSizes::fromMap(it->second.toMap(), docks); if (!info.docks.isEmpty()) m_hiddenAreas.insert(area, info); } } FancyMainWindow::FancyMainWindow(QWidget *parent) : QMainWindow(parent), d(new FancyMainWindowPrivate(this)) { connect(&d->m_resetLayoutAction, &QAction::triggered, this, [this] { d->m_hiddenAreas.clear(); emit resetLayout(); }); } FancyMainWindow::~FancyMainWindow() { delete d; } QDockWidget *FancyMainWindow::addDockForWidget(QWidget *widget, bool immutable) { QTC_ASSERT(widget, return nullptr); QTC_CHECK(widget->objectName().size()); QTC_CHECK(widget->windowTitle().size()); auto dockWidget = new DockWidget(widget, this, immutable); if (!immutable) { connect(dockWidget, &QDockWidget::visibilityChanged, this, [this, dockWidget](bool visible) { if (d->m_handleDockVisibilityChanges) dockWidget->setProperty(dockWidgetActiveState, visible); }); connect(dockWidget->toggleViewAction(), &QAction::triggered, dockWidget, [dockWidget] { if (dockWidget->isVisible()) dockWidget->raise(); }, Qt::QueuedConnection); dockWidget->setProperty(dockWidgetActiveState, true); const auto handleDockWidgetChanged = [this, dockWidget] { // If the dock moved to an area that was hidden, unhide the area. const Qt::DockWidgetArea area = dockWidgetArea(dockWidget); if (dockWidget->isVisible() && !dockWidget->isFloating() && d->m_hiddenAreas.contains(area)) { setDockAreaVisible(area, true); } emit dockWidgetsChanged(); }; connect(dockWidget, &QDockWidget::dockLocationChanged, this, handleDockWidgetChanged); connect(dockWidget, &QDockWidget::topLevelChanged, this, handleDockWidgetChanged); connect(dockWidget, &QDockWidget::visibilityChanged, this, handleDockWidgetChanged); } return dockWidget; } void FancyMainWindow::setTrackingEnabled(bool enabled) { if (enabled) { d->m_handleDockVisibilityChanges = true; for (QDockWidget *dockWidget : dockWidgets()) dockWidget->setProperty(dockWidgetActiveState, dockWidget->isVisible()); } else { d->m_handleDockVisibilityChanges = false; } } void FancyMainWindow::hideEvent(QHideEvent *event) { Q_UNUSED(event) handleVisibilityChanged(false); } void FancyMainWindow::showEvent(QShowEvent *event) { Q_UNUSED(event) handleVisibilityChanged(true); } void FancyMainWindow::contextMenuEvent(QContextMenuEvent *event) { QMenu menu; addDockActionsToMenu(&menu); menu.exec(event->globalPos()); } void FancyMainWindow::handleVisibilityChanged(bool visible) { d->m_handleDockVisibilityChanges = false; for (QDockWidget *dockWidget : dockWidgets()) { if (dockWidget->isFloating()) { dockWidget->setVisible(visible && dockWidget->property(dockWidgetActiveState).toBool()); } } if (visible) d->m_handleDockVisibilityChanges = true; } void FancyMainWindow::saveSettings(QtcSettings *settings) const { const Store hash = saveSettings(); for (auto it = hash.cbegin(), end = hash.cend(); it != end; ++it) settings->setValue(it.key(), it.value()); } void FancyMainWindow::restoreSettings(const QtcSettings *settings) { Store hash; const KeyList childKeys = settings->childKeys(); for (const Key &key : childKeys) hash.insert(key, settings->value(key)); restoreSettings(hash); } Store FancyMainWindow::saveSettings() const { Store settings; settings.insert(StateKey, saveState(settingsVersion)); settings.insert(ShowCentralWidgetKey, d->m_showCentralWidget.isChecked()); QVariantHash dockWidgetStates; for (QDockWidget *dockWidget : dockWidgets()) { settings.insert(keyFromString(dockWidget->objectName()), dockWidget->property(dockWidgetActiveState)); if (DockWidget *dock = qobject_cast(dockWidget)) dockWidgetStates.insert(dockWidget->objectName(), dock->saveState()); } settings.insert(DockWidgetStatesKey, dockWidgetStates); settings.insert(HiddenDockAreasKey, d->hiddenDockAreasToHash()); return settings; } bool FancyMainWindow::restoreSettings(const Store &settings) { bool success = true; QByteArray ba = settings.value(StateKey, QByteArray()).toByteArray(); if (!ba.isEmpty()) { success = restoreFancyState(ba, settingsVersion); if (!success) qWarning() << "Restoring the state of dock widgets failed."; } d->m_showCentralWidget.setChecked(settings.value(ShowCentralWidgetKey, true).toBool()); const QVariantHash dockWidgetStates = settings.value(DockWidgetStatesKey).toHash(); for (QDockWidget *widget : dockWidgets()) { widget->setProperty(dockWidgetActiveState, settings.value(keyFromString(widget->objectName()), false)); if (DockWidget *dock = qobject_cast(widget)) dock->restoreState(dockWidgetStates.value(widget->objectName())); } d->restoreHiddenDockAreasFromHash(settings.value(HiddenDockAreasKey).toHash()); emit dockWidgetsChanged(); return success; } bool FancyMainWindow::restoreFancyState(const QByteArray &state, int version) { const bool result = restoreState(state, version); emit dockWidgetsChanged(); return result; } static void findDockChildren(QWidget *parent, QList &result) { for (QObject *child : parent->children()) { QWidget *childWidget = qobject_cast(child); if (!childWidget) continue; if (auto dockWidget = qobject_cast(child)) result.append(dockWidget); else if (!qobject_cast(child)) findDockChildren(qobject_cast(child), result); } } const QList FancyMainWindow::dockWidgets() const { QList result; findDockChildren((QWidget *) this, result); return result; } QList FancyMainWindow::docksInArea(Qt::DockWidgetArea area) const { return filtered(dockWidgets(), [this, area](QDockWidget *w) { return w->isVisible() && !w->isFloating() && dockWidgetArea(w) == area; }); } bool FancyMainWindow::isCentralWidgetShown() const { return d->m_showCentralWidget.isChecked(); } void FancyMainWindow::showCentralWidget(bool on) { d->m_showCentralWidget.setChecked(on); } void FancyMainWindow::setDockAreaVisible(Qt::DockWidgetArea area, bool visible) { const auto orientationForArea = [](Qt::DockWidgetArea area) { if (area == Qt::LeftDockWidgetArea || area == Qt::RightDockWidgetArea) return Qt::Vertical; return Qt::Horizontal; }; d->m_blockAutoUncollapse = true; if (visible) { const DocksAndSizes dockInfo = d->m_hiddenAreas.value(area); for (QDockWidget *w : std::as_const(dockInfo.docks)) w->setVisible(true); resizeDocks(dockInfo.docks, dockInfo.sizes, orientationForArea(area)); d->m_hiddenAreas.remove(area); } else { const QList docks = docksInArea(area); if (!docks.isEmpty()) { const QList sizes = transform(docks, [](QDockWidget *w) { return w->height(); }); d->m_hiddenAreas.insert(area, DocksAndSizes{docks, sizes}); for (QDockWidget *w : docks) w->setVisible(false); } } d->m_blockAutoUncollapse = false; } bool FancyMainWindow::isDockAreaVisible(Qt::DockWidgetArea area) const { if (d->m_hiddenAreas.contains(area)) return false; return !docksInArea(area).isEmpty(); } bool FancyMainWindow::isDockAreaAvailable(Qt::DockWidgetArea area) const { if (d->m_hiddenAreas.contains(area)) return true; return !docksInArea(area).isEmpty(); } bool FancyMainWindow::isBlockingAutomaticUncollapse() const { return d->m_blockAutoUncollapse; } void FancyMainWindow::addDockActionsToMenu(QMenu *menu) { QList actions; QList dockwidgets = findChildren(); for (int i = 0; i < dockwidgets.size(); ++i) { QDockWidget *dockWidget = dockwidgets.at(i); if (dockWidget->property("managed_dockwidget").isNull() && dockWidget->parentWidget() == this) { QAction *action = dockWidget->toggleViewAction(); action->setText(action->property("original_title").toString()); actions.append(action); } } sort(actions, [](const QAction *action1, const QAction *action2) { QTC_ASSERT(action1, return true); QTC_ASSERT(action2, return false); return stripAccelerator(action1->text()).toLower() < stripAccelerator(action2->text()).toLower(); }); for (QAction *action : std::as_const(actions)) menu->addAction(action); menu->addAction(&d->m_showCentralWidget); menu->addAction(&d->m_menuSeparator1); menu->addAction(&d->m_resetLayoutAction); } QAction *FancyMainWindow::menuSeparator1() const { return &d->m_menuSeparator1; } QAction *FancyMainWindow::resetLayoutAction() const { return &d->m_resetLayoutAction; } QAction *FancyMainWindow::showCentralWidgetAction() const { return &d->m_showCentralWidget; } void FancyMainWindow::setDockActionsVisible(bool v) { for (const QDockWidget *dockWidget : dockWidgets()) dockWidget->toggleViewAction()->setVisible(v); d->m_showCentralWidget.setVisible(v); d->m_menuSeparator1.setVisible(v); d->m_resetLayoutAction.setVisible(v); } } // namespace Utils #include "fancymainwindow.moc"