qtquick: Ported the old DockWidgetQuick to the new architecture

Mostly anyway. Facing several blockers that need to be ported first,
for example DockWidget::setWidget() is still receiving QWidget
This commit is contained in:
Sergio Martins
2022-05-08 13:27:37 +01:00
parent 984bcd5f06
commit 76b1a394f2
5 changed files with 169 additions and 317 deletions

View File

@@ -210,6 +210,8 @@ set(KDDW_QTQUICK_FRONTEND_SRCS
qtquick/TestHelpers_qtquick.cpp
qtquick/LayoutSaverInstantiator.cpp
qtquick/LayoutSaverInstantiator.h
# qtquick/views/DockWidget_qtquick.cpp
# qtquick/views/DockWidget_qtquick.h
qtquick/views/Frame_qtquick.cpp
qtquick/views/Frame_qtquick.h
qtquick/views/View_qtquick.cpp

View File

@@ -10,9 +10,15 @@
*/
#include "DockWidget_qtquick.h"
#include "FrameworkWidgetFactory.h"
#include "controllers/TitleBar.h"
#include "controllers/DockWidget.h"
#include "controllers/Frame.h"
#include <Config.h>
#include <QQuickItem>
#include <QCloseEvent>
#include <QVBoxLayout>
/**
* @file
@@ -22,32 +28,34 @@
*/
using namespace KDDockWidgets;
using namespace KDDockWidgets::Controllers;
using namespace KDDockWidgets::Views;
class DockWidget_qtquick::Private
{
public:
Private(DockWidget_qtquick *q, Controllers::DockWidget *controller)
: layout(new QVBoxLayout(q))
, m_controller(controller)
Private(DockWidget_qtquick *view, QQmlEngine *qmlengine)
: q(view->m_controller)
, m_visualItem(q->createItem(qmlengine,
Config::self().frameworkWidgetFactory()->dockwidgetFilename().toString()))
, m_qmlEngine(qmlengine)
{
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
// propagate the max-size constraints from the guest widget to the DockWidget
layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
Q_ASSERT(m_visualItem);
m_visualItem->setParent(view);
m_visualItem->setParentItem(view);
}
QVBoxLayout *const layout;
Controllers::DockWidget *const m_controller;
Controllers::DockWidget *const q;
QQuickItem *const m_visualItem;
QQmlEngine *const m_qmlEngine;
};
DockWidget_qtquick::DockWidget_qtquick(Controllers::DockWidget *controller,
Qt::WindowFlags windowFlags)
: View_qtquick<QWidget>(controller, Type::DockWidget, nullptr, windowFlags)
, d(new Private(this, controller))
Qt::WindowFlags windowFlags, QQmlEngine *engine)
: View_qtquick(controller, Type::DockWidget, nullptr, windowFlags)
, d(new Private(this, engine ? engine : Config::self().qmlEngine()))
{
// To mimic what QtWidgets does when creating a new QWidget.
setVisible(false);
}
DockWidget_qtquick::~DockWidget_qtquick()
@@ -55,38 +63,105 @@ DockWidget_qtquick::~DockWidget_qtquick()
delete d;
}
void DockWidget_qtquick::init()
void DockWidget_qtquick::setWidget(const QString &qmlFilename)
{
connect(d->m_controller, &DockWidgetBase::widgetChanged, this, [this](QWidget *w) {
d->layout->addWidget(w);
});
QQuickItem *guest = createItem(d->m_qmlEngine, qmlFilename);
if (!guest)
return;
setWidget(guest);
}
Controllers::DockWidget *DockWidget_qtquick::dockWidget() const
void DockWidget_qtquick::setWidget(QWidgetAdapter *widget)
{
return d->m_controller;
widget->QWidgetAdapter::setParent(this);
makeItemFillParent(widget);
DockWidget::setWidget(widget);
}
void DockWidget_qtquick::setWidget(QQuickItem *guest)
{
auto adapter = new View_qtquick(nullptr, Type::None, this);
adapter->setIsWrapper();
// In case the user app needs to use them:
adapter->setProperty("originalParent", QVariant::fromValue(guest->parent()));
adapter->setProperty("originalParentItem", QVariant::fromValue(guest->parentItem()));
guest->setParentItem(adapter);
guest->setParent(adapter);
makeItemFillParent(guest);
setWidget(adapter);
}
bool DockWidget_qtquick::event(QEvent *e)
{
if (e->type() == QEvent::ParentChange) {
d->m_controller->onParentChanged();
d->q->onParentChanged();
Q_EMIT d->q->actualTitleBarChanged();
} else if (e->type() == QEvent::Show) {
d->m_controller->onShown(e->spontaneous());
d->q->onShown(e->spontaneous());
} else if (e->type() == QEvent::Hide) {
d->m_controller->onHidden(e->spontaneous());
d->q->onHidden(e->spontaneous());
} else if (e->type() == QEvent::Close) {
d->q->onCloseEvent(static_cast<QCloseEvent *>(e));
}
return QWidget::event(e);
return DockWidget_qtquick::event(e);
}
void DockWidget_qtquick::closeEvent(QCloseEvent *e)
QSize DockWidget_qtquick::minSize() const
{
d->m_controller->onCloseEvent(e);
if (auto guestWidget = widget()) {
// The guests min-size is the same as the widget's, there's no spacing or margins.
return guestWidget->minimumSize();
}
return View_qtquick::minSize();
}
void DockWidget_qtquick::resizeEvent(QResizeEvent *e)
QSize DockWidget_qtquick::maximumSize() const
{
d->m_controller->onResize(e->size());
return QWidget::resizeEvent(e);
if (auto guestWidget = widget()) {
// The guests max-size is the same as the widget's, there's no spacing or margins.
return guestWidget->maximumSize();
}
return View_qtquick::maximumSize();
}
QObject *DockWidget_qtquick::actualTitleBar() const
{
if (Controllers::Frame *frame = d->q->d->frame())
return frame->actualTitleBar();
return nullptr;
}
QObject *DockWidget_qtquick::actualTitleBarObj() const
{
return actualTitleBar();
}
QQuickItem *DockWidget_qtquick::frameVisualItem() const
{
if (Controllers::Frame *frame = d->q->d->frame()) {
return frame->visualItem();
}
return nullptr;
}
void DockWidget_qtquick::onGeometryUpdated()
{
if (auto frame = qobject_cast<FrameQuick *>(DockWidgetBase::d->frame())) {
frame->updateConstriants();
frame->updateGeometry();
}
}
Frame *DockWidget_qtquick::frame() const
{
return qobject_cast<FrameQuick *>(DockWidgetBase::d->frame());
}

View File

@@ -16,51 +16,101 @@
* @author Sérgio Martins \<sergio.martins@kdab.com\>
*/
#pragma once
#ifndef KD_DOCKWIDGET_QUICK_H
#define KD_DOCKWIDGET_QUICK_H
#include "controllers/DockWidget.h"
#include "View_qtquick.h"
QT_BEGIN_NAMESPACE
class QCloseEvent;
class QQmlEngine;
QT_END_NAMESPACE
namespace KDDockWidgets {
namespace Views {
namespace Controllers {
class Frame;
class TitleBar;
}
namespace Views {
/**
* @brief Represents a dock widget.
*
* Most of the interface lives in DockWidgetBase, to facilitate sharing with QtQuick.
*/
class DOCKS_EXPORT DockWidget_qtquick : public View_qtquick<QQuickItem>
class DOCKS_EXPORT DockWidget_qtquick : public Views::View_qtquick
{
Q_OBJECT
Q_PROPERTY(QObject *actualTitleBar READ actualTitleBarObj NOTIFY actualTitleBarChanged)
public:
/**
* @brief constructs a new DockWidget
* @param uniqueName Mandatory name that should be unique between all DockWidget instances.
* This name won't be user visible and just used internally for the save/restore.
* Use setTitle() for user visible text.
* @param uniqueName the name of the dockwidget, should be unique. Use title for user visible text.
* @param options optional options controlling behaviour
* @param layoutSaverOptions options regarding LayoutSaver behaviour
* @param engine the QML engine this dock widget will be created on. If not specified then
* Config::self().qmlEngine() will be used
*
* There's no parent argument. The DockWidget is either parented to FloatingWindow or MainWindow
* when visible, or stays without a parent when hidden. This allows to support docking
* to different main windows.
* when visible, or stays without a parent when hidden.
*/
explicit DockWidget_qtquick(Controllers::DockWidget *controller,
Qt::WindowFlags windowFlags = {});
Qt::WindowFlags windowFlags = {},
QQmlEngine *engine = nullptr);
///@brief destructor
~DockWidget_qtquick() override;
Controllers::DockWidget *dockWidget() const;
/// Sets the DockWidget's guest item
/// Similar to DockWidgetBase::setWidget(QQuickItem*)
void setWidget(const QString &qmlFilename);
/// @reimp
// void setWidget(QQuickItem *widget);
/// @reimp
Q_INVOKABLE void setWidget(QQuickItem *widget);
/// @reimp
QSize minSize() const override;
/// @reimp
QSize maximumSize() const override;
/// @brief Returns the title bar
QObject *actualTitleBar() const;
/// @brief Returns the title bar
/// Qt6 requires us to include TitleBar_p.h, so instead the Q_PROPERTY uses
/// QObject so we don't include private headers in public headers
QObject *actualTitleBarObj() const;
/// @brief Returns the visual item which represents Frame in the screen
/// Equivalent to Frame::visualItem().
QQuickItem *frameVisualItem() const;
///@internal
Q_INVOKABLE KDDockWidgets::Controllers::Frame *frame() const;
/// @brief Called by QtQuick when min-size changes
Q_INVOKABLE void onGeometryUpdated();
Q_SIGNALS:
/// @brief The geometry of the frame container this dock widget is in changed
/// For example, when dragging a dockwidget
void frameGeometryChanged(QRect);
protected:
bool event(QEvent *e) override;
private:
class Private;
Private *const d;
};
}
}
#endif

View File

@@ -1,164 +0,0 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "DockWidgetQuick.h"
#include "FrameworkWidgetFactory.h"
#include "private/TitleBar_p.h"
#include "private/DockWidget_p.h"
#include "private/quick/FrameQuick_p.h"
#include <Config.h>
#include <QQuickItem>
#include <QCloseEvent>
/**
* @file
* @brief Represents a dock widget.
*
* @author Sérgio Martins \<sergio.martins@kdab.com\>
*/
using namespace KDDockWidgets;
class DockWidgetQuick::Private
{
public:
Private(DockWidgetQuick *dw, QQmlEngine *qmlengine)
: q(dw)
, m_visualItem(q->createItem(qmlengine,
Config::self().frameworkWidgetFactory()->dockwidgetFilename().toString()))
, m_qmlEngine(qmlengine)
{
Q_ASSERT(m_visualItem);
m_visualItem->setParent(q);
m_visualItem->setParentItem(q);
}
DockWidgetBase *const q;
QQuickItem *const m_visualItem;
QQmlEngine *const m_qmlEngine;
};
DockWidgetQuick::DockWidgetQuick(const QString &name, Options options,
LayoutSaverOptions layoutSaverOptions, QQmlEngine *engine)
: DockWidgetBase(name, options, layoutSaverOptions)
, d(new Private(this, engine ? engine : Config::self().qmlEngine()))
{
// To mimic what QtWidgets does when creating a new QWidget.
setVisible(false);
}
DockWidgetQuick::~DockWidgetQuick()
{
delete d;
}
void DockWidgetQuick::setWidget(const QString &qmlFilename)
{
QQuickItem *guest = createItem(d->m_qmlEngine, qmlFilename);
if (!guest)
return;
setWidget(guest);
}
void DockWidgetQuick::setWidget(QWidgetAdapter *widget)
{
widget->QWidgetAdapter::setParent(this);
QWidgetAdapter::makeItemFillParent(widget);
DockWidgetBase::setWidget(widget);
}
void DockWidgetQuick::setWidget(QQuickItem *guest)
{
auto adapter = new QWidgetAdapter(this);
adapter->setIsWrapper();
// In case the user app needs to use them:
adapter->setProperty("originalParent", QVariant::fromValue(guest->parent()));
adapter->setProperty("originalParentItem", QVariant::fromValue(guest->parentItem()));
guest->setParentItem(adapter);
guest->setParent(adapter);
QWidgetAdapter::makeItemFillParent(guest);
setWidget(adapter);
}
bool DockWidgetQuick::event(QEvent *e)
{
if (e->type() == QEvent::ParentChange) {
onParentChanged();
Q_EMIT actualTitleBarChanged();
} else if (e->type() == QEvent::Show) {
onShown(e->spontaneous());
} else if (e->type() == QEvent::Hide) {
onHidden(e->spontaneous());
} else if (e->type() == QEvent::Close) {
onCloseEvent(static_cast<QCloseEvent *>(e));
}
return DockWidgetBase::event(e);
}
QSize DockWidgetQuick::minimumSize() const
{
if (QWidgetAdapter *guestWidget = widget()) {
// The guests min-size is the same as the widget's, there's no spacing or margins.
return guestWidget->minimumSize();
}
return DockWidgetBase::minimumSize();
}
QSize DockWidgetQuick::maximumSize() const
{
if (QWidgetAdapter *guestWidget = widget()) {
// The guests max-size is the same as the widget's, there's no spacing or margins.
return guestWidget->maximumSize();
}
return DockWidgetBase::maximumSize();
}
TitleBar *DockWidgetQuick::actualTitleBar() const
{
if (Frame *frame = DockWidgetBase::d->frame())
return frame->actualTitleBar();
return nullptr;
}
QObject *DockWidgetQuick::actualTitleBarObj() const
{
return actualTitleBar();
}
QQuickItem *DockWidgetQuick::frameVisualItem() const
{
if (auto frame = qobject_cast<FrameQuick *>(DockWidgetBase::d->frame()))
return frame->visualItem();
return nullptr;
}
void DockWidgetQuick::onGeometryUpdated()
{
if (auto frame = qobject_cast<FrameQuick *>(DockWidgetBase::d->frame())) {
frame->updateConstriants();
frame->updateGeometry();
}
}
Frame *DockWidgetQuick::frame() const
{
return qobject_cast<FrameQuick *>(DockWidgetBase::d->frame());
}

View File

@@ -1,111 +0,0 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
/**
* @file
* @brief Represents a dock widget.
*
* @author Sérgio Martins \<sergio.martins@kdab.com\>
*/
#ifndef KD_DOCKWIDGET_QUICK_H
#define KD_DOCKWIDGET_QUICK_H
#include "DockWidget.h"
QT_BEGIN_NAMESPACE
class QCloseEvent;
class QQmlEngine;
QT_END_NAMESPACE
namespace KDDockWidgets {
class Frame;
class TitleBar;
/**
* @brief Represents a dock widget.
*
* Most of the interface lives in DockWidgetBase, to facilitate sharing with QtQuick.
*/
class DOCKS_EXPORT DockWidgetQuick : public DockWidgetBase
{
Q_OBJECT
Q_PROPERTY(QObject *actualTitleBar READ actualTitleBarObj NOTIFY actualTitleBarChanged)
public:
/**
* @brief constructs a new DockWidget
* @param uniqueName the name of the dockwidget, should be unique. Use title for user visible text.
* @param options optional options controlling behaviour
* @param layoutSaverOptions options regarding LayoutSaver behaviour
* @param engine the QML engine this dock widget will be created on. If not specified then
* Config::self().qmlEngine() will be used
*
* There's no parent argument. The DockWidget is either parented to FloatingWindow or MainWindow
* when visible, or stays without a parent when hidden.
*/
explicit DockWidgetQuick(const QString &uniqueName, Options options = {},
LayoutSaverOptions layoutSaverOptions = LayoutSaverOptions(),
QQmlEngine *engine = nullptr);
///@brief destructor
~DockWidgetQuick() override;
/// Sets the DockWidget's guest item
/// Similar to DockWidgetBase::setWidget(QQuickItem*)
void setWidget(const QString &qmlFilename);
/// @reimp
void setWidget(QWidgetAdapter *widget) override;
/// @reimp
Q_INVOKABLE void setWidget(QQuickItem *widget);
/// @reimp
QSize minimumSize() const override;
/// @reimp
QSize maximumSize() const override;
/// @brief Returns the title bar
TitleBar *actualTitleBar() const;
/// @brief Returns the title bar
/// Qt6 requires us to include TitleBar_p.h, so instead the Q_PROPERTY uses
/// QObject so we don't include private headers in public headers
QObject *actualTitleBarObj() const;
/// @brief Returns the visual item which represents Frame in the screen
/// Equivalent to Frame::visualItem().
QQuickItem *frameVisualItem() const;
///@internal
Q_INVOKABLE KDDockWidgets::Frame *frame() const;
/// @brief Called by QtQuick when min-size changes
Q_INVOKABLE void onGeometryUpdated();
Q_SIGNALS:
/// @brief The geometry of the frame container this dock widget is in changed
/// For example, when dragging a dockwidget
void frameGeometryChanged(QRect);
protected:
bool event(QEvent *e) override;
private:
class Private;
Private *const d;
};
}
#endif