From 7017ce8396519d2fc2c17e4f2c00ac386d15613d Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Sat, 18 Jun 2022 12:15:42 +0100 Subject: [PATCH] Move KDBindings usage from View.h to View_p.h KDBindings is implementation detail. User won't have to install it, at this point. --- src/View.cpp | 15 ++++++++--- src/View.h | 24 ++++------------- src/ViewGuard.cpp | 3 ++- src/controllers/DockWidget_p.h | 3 ++- src/controllers/FloatingWindow.cpp | 17 ++++++++++--- src/controllers/FloatingWindow.h | 6 ++++- src/controllers/Frame.cpp | 22 ++++++++++++---- src/controllers/Frame.h | 3 ++- src/controllers/Layout.cpp | 5 ++-- src/private/View_p.h | 33 ++++++++++++++++++++++++ src/private/multisplitter/Item.cpp | 4 ++- src/qtquick/TestHelpers_qtquick.cpp | 3 ++- src/qtquick/views/Frame_qtquick.cpp | 4 +-- src/qtquick/views/View_qtquick.cpp | 9 ++++--- src/qtwidgets/views/Frame_qtwidgets.cpp | 3 ++- src/qtwidgets/views/Stack_qtwidgets.cpp | 1 + src/qtwidgets/views/View_qtwidgets.cpp | 34 +++++++++++++++++++++++++ src/qtwidgets/views/View_qtwidgets.h | 30 +++------------------- tests/tst_view.cpp | 3 ++- 19 files changed, 150 insertions(+), 72 deletions(-) create mode 100644 src/private/View_p.h diff --git a/src/View.cpp b/src/View.cpp index e941e1b5..d5ca0937 100644 --- a/src/View.cpp +++ b/src/View.cpp @@ -10,7 +10,7 @@ */ #include "View.h" - +#include "private/View_p.h" #include "private/multisplitter/Item_p.h" #include "controllers/FloatingWindow.h" @@ -35,7 +35,8 @@ static qint64 s_nextId = 1; } View::View(Controller *controller, Type type, QObject *thisObj) - : m_controller(controller) + : d(new Private()) + , m_controller(controller) , m_thisObj(thisObj) , m_id(QString::number(KDDockWidgets::s_nextId++)) , m_type(type) @@ -45,7 +46,7 @@ View::View(Controller *controller, Type type, QObject *thisObj) View::~View() { m_inDtor = true; - beingDestroyed.emit(); + d->beingDestroyed.emit(); if (!freed() && !is(Type::ViewWrapper)) { // TODOm3 @@ -55,6 +56,8 @@ View::~View() // and destroy its controller, which was the old behaviour. delete m_controller; } + + delete d; } QString View::id() const @@ -398,3 +401,9 @@ std::shared_ptr View::transientWindow() const return {}; } + +bool View::onResize(QSize newSize) +{ + d->resized.emit(newSize); + return false; +} diff --git a/src/View.h b/src/View.h index 85fd72c0..297afced 100644 --- a/src/View.h +++ b/src/View.h @@ -19,8 +19,6 @@ #include #include -#include "kdbindings/signal.h" - #include namespace Layouting { @@ -178,11 +176,7 @@ public: virtual void setCursor(Qt::CursorShape) = 0; virtual void setMouseTracking(bool) = 0; - virtual bool onResize(QSize newSize) - { - resized.emit(newSize); - return false; - } + virtual bool onResize(QSize newSize); virtual bool onFocusInEvent(QFocusEvent *) { @@ -273,20 +267,12 @@ public: Controller *firstParentOfType(KDDockWidgets::Type) const; public: - /// @brief signal emitted once ~View starts - KDBindings::Signal<> beingDestroyed; - - /// @brief signal emitted when something tried to close this view - KDBindings::Signal closeRequested; - - /// @brief signal emitted when constraints change, for example min/max sizes - KDBindings::Signal<> layoutInvalidated; - - /// @brief signal emitted when the view is resized - KDBindings::Signal resized; + class Private; + Private *const d; protected: - virtual void free_impl(); + virtual void + free_impl(); Controller *const m_controller; QObject *const m_thisObj; diff --git a/src/ViewGuard.cpp b/src/ViewGuard.cpp index 641055f4..a8c62c34 100644 --- a/src/ViewGuard.cpp +++ b/src/ViewGuard.cpp @@ -11,6 +11,7 @@ #include "ViewGuard.h" #include "View.h" +#include "private/View_p.h" using namespace KDDockWidgets; @@ -81,7 +82,7 @@ void ViewGuard::setView(View *view) v = view; if (v) { - m_onDestroy = v->beingDestroyed.connect([this] { + m_onDestroy = v->d->beingDestroyed.connect([this] { v = nullptr; }); } diff --git a/src/controllers/DockWidget_p.h b/src/controllers/DockWidget_p.h index ab179ff3..0c46b74e 100644 --- a/src/controllers/DockWidget_p.h +++ b/src/controllers/DockWidget_p.h @@ -17,6 +17,7 @@ #include "private/Position_p.h" #include "ViewWrapper.h" #include "Action.h" +#include "private/View_p.h" #include #include @@ -59,7 +60,7 @@ public: void init() { updateTitle(); - q->view()->closeRequested.connect([this](QCloseEvent *ev) { + q->view()->d->closeRequested.connect([this](QCloseEvent *ev) { onCloseEvent(ev); }); } diff --git a/src/controllers/FloatingWindow.cpp b/src/controllers/FloatingWindow.cpp index b04557b5..caf606a5 100644 --- a/src/controllers/FloatingWindow.cpp +++ b/src/controllers/FloatingWindow.cpp @@ -28,6 +28,9 @@ #include "private/multisplitter/Item_p.h" #include "View.h" +#include "private/View_p.h" + +#include "kdbindings/signal.h" #include #include @@ -45,6 +48,12 @@ using namespace KDDockWidgets; using namespace KDDockWidgets::Controllers; +class FloatingWindow::Private +{ +public: + KDBindings::ScopedConnection m_visibleWidgetCountConnection; +}; + /** static */ Qt::WindowFlags FloatingWindow::s_windowFlagsOverride = {}; @@ -108,6 +117,7 @@ MainWindow *actualParent(MainWindow *candidate) FloatingWindow::FloatingWindow(QRect suggestedGeometry, MainWindow *parent) : Controller(Type::FloatingWindow, Config::self().viewFactory()->createFloatingWindow(this, actualParent(parent), windowFlagsToUse())) , Draggable(view(), KDDockWidgets::usesNativeDraggingAndResizing()) // FloatingWindow is only draggable when using a native title bar. Otherwise the KDDockWidgets::TitleBar is the draggable + , d(new Private()) , m_dropArea(new DropArea(view(), MainWindowOption_None)) , m_titleBar(new Controllers::TitleBar(this)) { @@ -137,17 +147,17 @@ FloatingWindow::FloatingWindow(QRect suggestedGeometry, MainWindow *parent) updateTitleBarVisibility(); - m_visibleWidgetCountConnection = m_dropArea->visibleWidgetCountChanged.connect([this](int count) { + d->m_visibleWidgetCountConnection = m_dropArea->visibleWidgetCountChanged.connect([this](int count) { onFrameCountChanged(count); numFramesChanged(); onVisibleFrameCountChanged(count); }); - view()->closeRequested.connect([this](QCloseEvent *ev) { + view()->d->closeRequested.connect([this](QCloseEvent *ev) { onCloseEvent(ev); }); - view()->layoutInvalidated.connect([this] { + view()->d->layoutInvalidated.connect([this] { updateSizeConstraints(); }); @@ -224,6 +234,7 @@ FloatingWindow::~FloatingWindow() DockRegistry::self()->unregisterFloatingWindow(this); delete m_titleBar; + delete d; } void FloatingWindow::maybeCreateResizeHandler() diff --git a/src/controllers/FloatingWindow.h b/src/controllers/FloatingWindow.h index 1a696c3c..502f4645 100644 --- a/src/controllers/FloatingWindow.h +++ b/src/controllers/FloatingWindow.h @@ -214,6 +214,10 @@ Q_SIGNALS: void numFramesChanged(); void windowStateChanged(QWindowStateChangeEvent *); +private: + class Private; + Private *const d; + protected: QPointer m_dropArea; Controllers::TitleBar *const m_titleBar; @@ -225,12 +229,12 @@ private: void onVisibleFrameCountChanged(int count); void onCloseEvent(QCloseEvent *); void updateSizeConstraints(); + bool m_disableSetVisible = false; bool m_deleteScheduled = false; bool m_inDtor = false; bool m_updatingTitleBarVisibility = false; QMetaObject::Connection m_layoutDestroyedConnection; - KDBindings::ScopedConnection m_visibleWidgetCountConnection; QAbstractNativeEventFilter *m_nchittestFilter = nullptr; Qt::WindowState windowStateOverride() const; #ifdef Q_OS_WIN diff --git a/src/controllers/Frame.cpp b/src/controllers/Frame.cpp index 9ecd1f59..b7f18950 100644 --- a/src/controllers/Frame.cpp +++ b/src/controllers/Frame.cpp @@ -27,15 +27,19 @@ #include "controllers/Layout.h" #include "controllers/MainWindow.h" -#include "private/Logging_p.h" -#include "private/Utils_p.h" #include "DockRegistry.h" #include "DockWidget_p.h" + +#include "private/Logging_p.h" +#include "private/Utils_p.h" +#include "private/View_p.h" #include "private/LayoutSaver_p.h" #include "private/Position_p.h" #include "private/WidgetResizeHandler_p.h" #include "private/multisplitter/Item_p.h" +#include "kdbindings/signal.h" + #include #include @@ -48,6 +52,12 @@ using namespace KDDockWidgets::Controllers; namespace KDDockWidgets { +class Frame::Private +{ +public: + KDBindings::ScopedConnection m_visibleWidgetCountChangedConnection; +}; + static FrameOptions actualOptions(FrameOptions options) { if (Config::self().flags() & Config::Flag_AlwaysShowTabs) @@ -71,6 +81,7 @@ static StackOptions tabWidgetOptions(FrameOptions options) Frame::Frame(View *parent, FrameOptions options, int userType) : Controller(Type::Frame, Config::self().viewFactory()->createFrame(this, parent)) , FocusScope(view()) + , d(new Private()) , m_tabWidget(new Controllers::Stack(this, tabWidgetOptions(options))) , m_titleBar(new Controllers::TitleBar(this)) , m_options(actualOptions(options)) @@ -85,7 +96,7 @@ Frame::Frame(View *parent, FrameOptions options, int userType) setLayout(parent ? parent->asLayout() : nullptr); view()->init(); - view()->closeRequested.connect([this](QCloseEvent *ev) { + view()->d->closeRequested.connect([this](QCloseEvent *ev) { onCloseEvent(ev); }); @@ -108,6 +119,7 @@ Frame::~Frame() setLayout(nullptr); delete m_titleBar; delete m_tabWidget; + delete d; } void Frame::onCloseEvent(QCloseEvent *e) @@ -138,8 +150,8 @@ void Frame::setLayout(Layout *dt) m_resizeHandler = new WidgetResizeHandler(/*topLevel=*/false, view()); // We keep the connect result so we don't dereference m_layout at shutdown - m_visibleWidgetCountChangedConnection->disconnect(); // TODOm3: Remove if tests pass. It's a KDBindings bug. - m_visibleWidgetCountChangedConnection = m_layout->visibleWidgetCountChanged.connect(&Frame::updateTitleBarVisibility, this); + d->m_visibleWidgetCountChangedConnection->disconnect(); // TODOm3: Remove if tests pass. It's a KDBindings bug. + d->m_visibleWidgetCountChangedConnection = m_layout->visibleWidgetCountChanged.connect(&Frame::updateTitleBarVisibility, this); updateTitleBarVisibility(); if (wasInMainWindow != isInMainWindow()) Q_EMIT isInMainWindowChanged(); diff --git a/src/controllers/Frame.h b/src/controllers/Frame.h index 2923342a..ed56d24a 100644 --- a/src/controllers/Frame.h +++ b/src/controllers/Frame.h @@ -347,6 +347,8 @@ public: int nonContentsHeight() const; private: + class Private; + Private *const d; bool m_inCtor = true; // Needs to be initialized early, as pointed out by UBSAN protected: bool m_inDtor = false; @@ -369,7 +371,6 @@ private: bool m_updatingTitleBar = false; bool m_beingDeleted = false; int m_userType = 0; - KDBindings::ScopedConnection m_visibleWidgetCountChangedConnection; }; } diff --git a/src/controllers/Layout.cpp b/src/controllers/Layout.cpp index 0eafafa8..645de63d 100644 --- a/src/controllers/Layout.cpp +++ b/src/controllers/Layout.cpp @@ -15,6 +15,7 @@ #include "Platform.h" #include "kddockwidgets/ViewFactory.h" #include "private/Utils_p.h" +#include "private/View_p.h" #include "controllers/Layout.h" #include "controllers/DropArea.h" @@ -32,11 +33,11 @@ using namespace KDDockWidgets::Controllers; Layout::Layout(Type type, View *view) : Controller(type, view) { - view->layoutInvalidated.connect([this] { + view->d->layoutInvalidated.connect([this] { updateSizeConstraints(); }); - view->resized.connect(&Layout::onResize, this); + view->d->resized.connect(&Layout::onResize, this); } Layout::~Layout() diff --git a/src/private/View_p.h b/src/private/View_p.h new file mode 100644 index 00000000..95929c6e --- /dev/null +++ b/src/private/View_p.h @@ -0,0 +1,33 @@ +/* + This file is part of KDDockWidgets. + + SPDX-FileCopyrightText: 2020-2022 Klarälvdalens Datakonsult AB, a KDAB Group company + Author: Sérgio Martins + + SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only + + Contact KDAB at for commercial licensing options. +*/ + +#pragma once + +#include "../View.h" +#include "kdbindings/signal.h" + +namespace KDDockWidgets { +class View::Private +{ +public: + /// @brief signal emitted once ~View starts + KDBindings::Signal<> beingDestroyed; + + /// @brief signal emitted when something tried to close this view + KDBindings::Signal closeRequested; + + /// @brief signal emitted when constraints change, for example min/max sizes + KDBindings::Signal<> layoutInvalidated; + + /// @brief signal emitted when the view is resized + KDBindings::Signal resized; +}; +} diff --git a/src/private/multisplitter/Item.cpp b/src/private/multisplitter/Item.cpp index 4d33b57a..6d73b5a9 100644 --- a/src/private/multisplitter/Item.cpp +++ b/src/private/multisplitter/Item.cpp @@ -17,6 +17,8 @@ #include "ItemFreeContainer_p.h" #include "kdbindings/signal.h" #include "Window.h" +#include "../View_p.h" + #include #include @@ -201,7 +203,7 @@ void Item::setGuestView(View *guest) connect(newWidget, &QObject::destroyed, this, &Item::onWidgetDestroyed); m_layoutInvalidatedConnection->disconnect(); - m_layoutInvalidatedConnection = guest->layoutInvalidated.connect(&Item::onWidgetLayoutRequested, this); + m_layoutInvalidatedConnection = guest->d->layoutInvalidated.connect(&Item::onWidgetLayoutRequested, this); if (m_sizingInfo.geometry.isEmpty()) { // Use the widgets geometry, but ensure it's at least hardcodedMinimumSize diff --git a/src/qtquick/TestHelpers_qtquick.cpp b/src/qtquick/TestHelpers_qtquick.cpp index ac1f97a6..b9ee3757 100644 --- a/src/qtquick/TestHelpers_qtquick.cpp +++ b/src/qtquick/TestHelpers_qtquick.cpp @@ -15,6 +15,7 @@ #include "kddockwidgets/views/MainWindow_qtquick.h" #include "kddockwidgets/controllers/MainWindow.h" #include "Helpers_p.h" +#include "private/View_p.h" #include #include @@ -109,7 +110,7 @@ View *Platform_qtquick::tests_createNonClosableView(View *parent) CreateViewOptions opts; opts.isVisible = true; auto view = tests_createView(opts, parent); - view->closeRequested.connect([](QCloseEvent *ev) { + view->d->closeRequested.connect([](QCloseEvent *ev) { ev->ignore(); }); diff --git a/src/qtquick/views/Frame_qtquick.cpp b/src/qtquick/views/Frame_qtquick.cpp index f03ffeba..337b19e5 100644 --- a/src/qtquick/views/Frame_qtquick.cpp +++ b/src/qtquick/views/Frame_qtquick.cpp @@ -61,7 +61,7 @@ void Frame_qtquick::init() this, SLOT(updateConstriants())); connect(this, &View_qtquick::geometryUpdated, this, [this] { - layoutInvalidated.emit(); + View::d->layoutInvalidated.emit(); }); /// QML interface connect, since controllers won't be QObjects for much longer: @@ -100,7 +100,7 @@ void Frame_qtquick::updateConstriants() setProperty("kddockwidgets_min_size", minSize()); setProperty("kddockwidgets_max_size", maximumSize()); - layoutInvalidated.emit(); + View::d->layoutInvalidated.emit(); } void Frame_qtquick::removeWidget_impl(Controllers::DockWidget *dw) diff --git a/src/qtquick/views/View_qtquick.cpp b/src/qtquick/views/View_qtquick.cpp index 204cf8c4..f1cc918c 100644 --- a/src/qtquick/views/View_qtquick.cpp +++ b/src/qtquick/views/View_qtquick.cpp @@ -11,6 +11,7 @@ #include "View_qtquick.h" #include "private/Utils_p.h" +#include "private/View_p.h" #include "ViewWrapper_qtquick.h" #include "private/multisplitter/Item_p.h" #include "kddockwidgets/Window_qtquick.h" @@ -230,7 +231,7 @@ void View_qtquick::move(int x, int y) bool View_qtquick::event(QEvent *ev) { if (ev->type() == QEvent::Close) - closeRequested.emit(static_cast(ev)); + View::d->closeRequested.emit(static_cast(ev)); return QQuickItem::event(ev); } @@ -268,7 +269,7 @@ bool View_qtquick::close(QQuickItem *item) { if (auto viewqtquick = qobject_cast(item)) { QCloseEvent ev; - viewqtquick->closeRequested.emit(&ev); + viewqtquick->View::d->closeRequested.emit(&ev); if (ev.isAccepted()) { viewqtquick->setVisible(false); @@ -459,7 +460,7 @@ void View_qtquick::setMaximumSize(QSize sz) if (maximumSize() != sz) { setProperty("kddockwidgets_max_size", sz); updateGeometry(); - layoutInvalidated.emit(); + View::d->layoutInvalidated.emit(); } } @@ -772,7 +773,7 @@ void View_qtquick::setMinimumSize(QSize sz) if (minSize() != sz) { setProperty("kddockwidgets_min_size", sz); updateGeometry(); - layoutInvalidated.emit(); + View::d->layoutInvalidated.emit(); } } diff --git a/src/qtwidgets/views/Frame_qtwidgets.cpp b/src/qtwidgets/views/Frame_qtwidgets.cpp index 79218261..13f776d6 100644 --- a/src/qtwidgets/views/Frame_qtwidgets.cpp +++ b/src/qtwidgets/views/Frame_qtwidgets.cpp @@ -20,6 +20,7 @@ #include "kddockwidgets/controllers/TabBar.h" #include "kddockwidgets/controllers/TitleBar.h" #include "Config.h" +#include "private/View_p.h" #include #include @@ -44,7 +45,7 @@ public: if (m_frameWidget->inDtor()) return; QVBoxLayout::invalidate(); - m_frameWidget->layoutInvalidated.emit(); + m_frameWidget->d->layoutInvalidated.emit(); } Frame_qtwidgets *const m_frameWidget; diff --git a/src/qtwidgets/views/Stack_qtwidgets.cpp b/src/qtwidgets/views/Stack_qtwidgets.cpp index 1b2dd1a2..8107db4b 100644 --- a/src/qtwidgets/views/Stack_qtwidgets.cpp +++ b/src/qtwidgets/views/Stack_qtwidgets.cpp @@ -17,6 +17,7 @@ #include "qtwidgets/views/DockWidget_qtwidgets.h" #include "DockRegistry.h" #include "Config.h" +#include "private/View_p.h" #include #include diff --git a/src/qtwidgets/views/View_qtwidgets.cpp b/src/qtwidgets/views/View_qtwidgets.cpp index f33fff3f..d52cd7ee 100644 --- a/src/qtwidgets/views/View_qtwidgets.cpp +++ b/src/qtwidgets/views/View_qtwidgets.cpp @@ -11,6 +11,7 @@ #include "View_qtwidgets.h" #include "../Window_qtwidgets.h" +#include "private/View_p.h" #include #include @@ -75,6 +76,39 @@ std::shared_ptr View_qtwidgets::window() const return {}; } +template +void View_qtwidgets::setMaximumSize(QSize sz) +{ + if (sz != QWidget::maximumSize()) { + T::setMaximumSize(sz); + d->layoutInvalidated.emit(); + } +} + +template +bool View_qtwidgets::event(QEvent *e) +{ + if (e->type() == QEvent::LayoutRequest) + d->layoutInvalidated.emit(); + + return T::event(e); +} + +template +void View_qtwidgets::closeEvent(QCloseEvent *ev) +{ + d->closeRequested.emit(ev); +} + +template +void View_qtwidgets::setMinimumSize(QSize sz) +{ + if (sz != QWidget::minimumSize()) { + QWidget::setMinimumSize(sz); + d->layoutInvalidated.emit(); + } +} + namespace KDDockWidgets::Views { template class View_qtwidgets; } diff --git a/src/qtwidgets/views/View_qtwidgets.h b/src/qtwidgets/views/View_qtwidgets.h index fbdd972f..6112f5ed 100644 --- a/src/qtwidgets/views/View_qtwidgets.h +++ b/src/qtwidgets/views/View_qtwidgets.h @@ -71,13 +71,7 @@ public: return Base::minimumSizeHint(); } - void setMinimumSize(QSize sz) override - { - if (sz != QWidget::minimumSize()) { - QWidget::setMinimumSize(sz); - layoutInvalidated.emit(); - } - } + void setMinimumSize(QSize sz) override; QSize maxSizeHint() const override { @@ -120,13 +114,7 @@ public: Base::setGeometry(geo); } - void setMaximumSize(QSize sz) override - { - if (sz != QWidget::maximumSize()) { - Base::setMaximumSize(sz); - layoutInvalidated.emit(); - } - } + void setMaximumSize(QSize sz) override; bool isVisible() const override { @@ -469,13 +457,8 @@ public: } protected: - bool event(QEvent *e) override - { - if (e->type() == QEvent::LayoutRequest) - layoutInvalidated.emit(); - - return Base::event(e); - } + bool event(QEvent *e) override; + void closeEvent(QCloseEvent *ev) override; void resizeEvent(QResizeEvent *ev) override { @@ -483,11 +466,6 @@ protected: Base::resizeEvent(ev); } - void closeEvent(QCloseEvent *ev) override - { - closeRequested.emit(ev); - } - private: Q_DISABLE_COPY(View_qtwidgets) }; diff --git a/tests/tst_view.cpp b/tests/tst_view.cpp index 2ed7a1e0..3dd008f0 100644 --- a/tests/tst_view.cpp +++ b/tests/tst_view.cpp @@ -10,6 +10,7 @@ */ #include "main.h" +#include "private/View_p.h" TEST_CASE("View::setParent()") { @@ -173,7 +174,7 @@ TEST_CASE("View::closeRequested") auto rootView = createViewAndWindow({}); bool signalArrived = false; - KDBindings::ScopedConnection connection = rootView->closeRequested.connect([&signalArrived](QCloseEvent *ev) { + KDBindings::ScopedConnection connection = rootView->d->closeRequested.connect([&signalArrived](QCloseEvent *ev) { signalArrived = true; CHECK(ev->isAccepted()); });