From 4b863d1155b1381d8e77661d3d59a868bb3c94da Mon Sep 17 00:00:00 2001 From: renbin Date: Tue, 18 Jun 2024 10:51:59 +0800 Subject: [PATCH] fix: [framework] improve appletitem management Add debugging assistance function. Fix the bug that appletitem cannot be released correctly. Log: Improve item management. --- .../lifecycle/pluginquickmetadata.h | 1 + include/dfm-gui/applet.h | 2 + include/dfm-gui/appletitem.h | 2 + include/dfm-gui/windowhandle.h | 4 +- src/dfm-base/utils/clipboard.cpp | 2 +- .../lifecycle/pluginmetaobject.cpp | 25 +++++++---- src/dfm-gui/applet.cpp | 42 ++++++++++++++----- src/dfm-gui/applet_p.h | 1 + src/dfm-gui/appletitem.cpp | 11 +++++ src/dfm-gui/appletmanager.cpp | 8 +++- src/dfm-gui/attachedproperty.cpp | 21 +--------- src/dfm-gui/windowhandle.cpp | 8 ++-- src/dfm-gui/windowmanager.cpp | 1 + 13 files changed, 82 insertions(+), 46 deletions(-) diff --git a/include/dfm-framework/lifecycle/pluginquickmetadata.h b/include/dfm-framework/lifecycle/pluginquickmetadata.h index 6cc7d8bede..45d67b3e09 100644 --- a/include/dfm-framework/lifecycle/pluginquickmetadata.h +++ b/include/dfm-framework/lifecycle/pluginquickmetadata.h @@ -63,6 +63,7 @@ class PluginQuickMetaDataCreator final QT_BEGIN_NAMESPACE #ifndef QT_NO_DEBUG_STREAM Q_CORE_EXPORT QDebug operator<<(QDebug, const DPF_NAMESPACE::PluginQuickMetaData &); +Q_CORE_EXPORT QDebug operator<<(QDebug, const DPF_NAMESPACE::PluginQuickMetaPtr &); #endif // QT_NO_DEBUG_STREAM QT_END_NAMESPACE diff --git a/include/dfm-gui/applet.h b/include/dfm-gui/applet.h index 8bc8389de0..43ed475499 100644 --- a/include/dfm-gui/applet.h +++ b/include/dfm-gui/applet.h @@ -55,6 +55,8 @@ class Applet : public QObject void setComponentUrl(const QUrl &url); Q_SIGNAL void componentUrlChanged(const QUrl &url); + void dumpAppletTree(); + protected: explicit Applet(AppletPrivate &dd, QObject *parent = nullptr); QScopedPointer dptr; diff --git a/include/dfm-gui/appletitem.h b/include/dfm-gui/appletitem.h index a58e21f3d8..f09b2d5192 100644 --- a/include/dfm-gui/appletitem.h +++ b/include/dfm-gui/appletitem.h @@ -23,6 +23,8 @@ class AppletItem : public QQuickItem Applet *applet() const; void setApplet(Applet *applet); + bool isCreateComplete() const; + Q_INVOKABLE QQuickWindow *itemWindow() const; Q_SIGNAL void itemWindowChanged(QQuickWindow *window); diff --git a/include/dfm-gui/windowhandle.h b/include/dfm-gui/windowhandle.h index 5660ce72df..d08682ceec 100644 --- a/include/dfm-gui/windowhandle.h +++ b/include/dfm-gui/windowhandle.h @@ -15,7 +15,7 @@ class QQuickWindow; DFMGUI_BEGIN_NAMESPACE class Panel; -class FileManagerWindowHandleData; +class WindowHandleData; class WindowHandle { @@ -32,7 +32,7 @@ class WindowHandle private: Q_DISABLE_COPY(WindowHandle); - QScopedPointer data; + QScopedPointer data; }; using WindowHandlePtr = QSharedPointer; diff --git a/src/dfm-base/utils/clipboard.cpp b/src/dfm-base/utils/clipboard.cpp index 701f937a5a..aff01d60d3 100644 --- a/src/dfm-base/utils/clipboard.cpp +++ b/src/dfm-base/utils/clipboard.cpp @@ -62,7 +62,7 @@ void onClipboardDataChanged() return; } const QString &data = mimeData->data(kGnomeCopyKey); - const static QRegExp regCut("cut\nfile://"), regCopy("copy\nfile://"); + const static QRegularExpression regCut("cut\nfile://"), regCopy("copy\nfile://"); if (data.contains(regCut)) { clipboardAction = ClipBoard::kCutAction; } else if (data.contains(regCopy)) { diff --git a/src/dfm-framework/lifecycle/pluginmetaobject.cpp b/src/dfm-framework/lifecycle/pluginmetaobject.cpp index bc16aff208..d2c1616d11 100644 --- a/src/dfm-framework/lifecycle/pluginmetaobject.cpp +++ b/src/dfm-framework/lifecycle/pluginmetaobject.cpp @@ -221,7 +221,20 @@ Q_CORE_EXPORT QDebug operator<<(QDebug out, const DPF_NAMESPACE::PluginMetaObjec } /*! - * \brief 重定向全局Debug打印 PluginQuickInfo 对象的函数 + * \brief operator << + * 重定向全局Debug入口函数 + * \param out + * \param pointer + * \return + */ +Q_CORE_EXPORT QDebug operator<<(QDebug out, const DPF_NAMESPACE::PluginMetaObjectPointer &pointer) +{ + out << *pointer; + return out; +} + +/*! + * \brief 重定向全局Debug打印 PluginQuickMetaData 对象的函数 */ Q_CORE_EXPORT QDebug operator<<(QDebug out, const DPF_NAMESPACE::PluginQuickMetaData &quickMeta) { @@ -237,15 +250,11 @@ Q_CORE_EXPORT QDebug operator<<(QDebug out, const DPF_NAMESPACE::PluginQuickMeta } /*! - * \brief operator << - * 重定向全局Debug入口函数 - * \param out - * \param pointer - * \return + * \brief 重定向全局Debug打印 PluginQuickMetaPtr 的函数 */ -Q_CORE_EXPORT QDebug operator<<(QDebug out, const DPF_NAMESPACE::PluginMetaObjectPointer &pointer) +Q_CORE_EXPORT QDebug operator<<(QDebug out, const DPF_NAMESPACE::PluginQuickMetaPtr &quickMetaPtr) { - out << *pointer; + out << *quickMetaPtr; return out; } diff --git a/src/dfm-gui/applet.cpp b/src/dfm-gui/applet.cpp index c6da4561a9..6eaad9801b 100644 --- a/src/dfm-gui/applet.cpp +++ b/src/dfm-gui/applet.cpp @@ -5,6 +5,7 @@ #include #include #include "applet_p.h" +#include "containment_p.h" #include @@ -19,6 +20,7 @@ AppletPrivate::~AppletPrivate() { // 释放关联的 QQuickItem if (rootObject && QJSEngine::CppOwnership == QJSEngine::objectOwnership(rootObject)) { + Q_ASSERT_X(rootObject->parent() == q_ptr, "AppletItem memory management", "Undefined behaviour, unmanaged QQuickItem"); rootObject->deleteLater(); } } @@ -34,6 +36,24 @@ void AppletPrivate::setRootObject(QObject *item) Q_EMIT q_func()->rootObjectChanged(item); } +/*! + * \brief 按层级递归打印当前 Applet 树信息 + */ +void AppletPrivate::dumpAppletTreeImpl(int level) +{ + QString indent = QString(' ').repeated(level * 4); + qCDebug(logDFMGui) << indent << metaPtr; + + if (flag.testFlag(Applet::kContainment)) { + if (auto containment = dynamic_cast(this)) { + qCDebug(logDFMGui) << indent << QStringLiteral("Applet chiledren:"); + for (Applet *child : containment->applets) { + child->dptr->dumpAppletTreeImpl(level + 1); + } + } + } +} + /*! * \class Applet * \brief 管理插件 QML 组件的最小单元,包含基础的组件信息. @@ -94,22 +114,16 @@ QObject *Applet::rootObject() const } /*! - * \brief 返回当前 Applet 的容器 Containment , 若自身是容器则会返回当前对象 - * \return 容器指针 + * \brief 返回当前 Applet 的容器 Containment , 会递归向上查找 + * \return 容器指针,若父对象没有容器,返回 nullptr */ Containment *Applet::containment() const { - Containment *contain = qobject_cast(const_cast(this)); - if (contain) { - return contain; - } - contain = nullptr; - + Containment *contain = nullptr; QObject *parent = this->parent(); while (parent) { - Containment *tmp = qobject_cast(parent); - if (tmp) { + if (Containment *tmp = qobject_cast(parent)) { contain = tmp; break; } @@ -155,4 +169,12 @@ void Applet::setComponentUrl(const QUrl &url) } } +/*! + * \brief 打印当前 Applet 树信息 + */ +void Applet::dumpAppletTree() +{ + d_func()->dumpAppletTreeImpl(); +} + DFMGUI_END_NAMESPACE diff --git a/src/dfm-gui/applet_p.h b/src/dfm-gui/applet_p.h index 6206aa09ae..73d371c7d0 100644 --- a/src/dfm-gui/applet_p.h +++ b/src/dfm-gui/applet_p.h @@ -23,6 +23,7 @@ class AppletPrivate virtual ~AppletPrivate(); void setRootObject(QObject *item); + void dumpAppletTreeImpl(int level = 0); Applet *q_ptr; QUrl currentUrl; // 当前 Applet 操作的文件 Url diff --git a/src/dfm-gui/appletitem.cpp b/src/dfm-gui/appletitem.cpp index 21010e9377..b6bbb783a3 100644 --- a/src/dfm-gui/appletitem.cpp +++ b/src/dfm-gui/appletitem.cpp @@ -38,6 +38,16 @@ void AppletItem::setApplet(Applet *applet) d_func()->applet = applet; } +/*! + * \return 返回当前 Item 是否被初始化完成,目前是对 QQuickItem::isComponentComplete + * 的封装,用于判断是否被 QQmlEngine 完成创建 + */ +bool AppletItem::isCreateComplete() const +{ + Q_D(const AppletItem); + return isComponentComplete() && d->applet; +} + /*! * \return 当前 Item 所在的顶层窗体 */ @@ -81,6 +91,7 @@ AppletItem *AppletItem::itemForApplet(Applet *applet) QObject *rootObject = engine.rootObject(); if (rootObject) { if (auto item = qobject_cast(rootObject)) { + item->setApplet(applet); applet->dptr->setRootObject(item); return item; } diff --git a/src/dfm-gui/appletmanager.cpp b/src/dfm-gui/appletmanager.cpp index e2884762ac..933bf044af 100644 --- a/src/dfm-gui/appletmanager.cpp +++ b/src/dfm-gui/appletmanager.cpp @@ -77,10 +77,14 @@ Applet *AppletManagerPrivate::createAppletFromNode(const AppletTemplateNode::Ptr } if (applet->flags().testFlag(Applet::kContainment) && !node->childNode.isEmpty()) { - Containment *cotainment = applet->containment(); + Containment *containment = qobject_cast(applet); + if (!containment) { + return nullptr; + } + for (auto childNode : std::as_const(node->childNode)) { Applet *childApplet = createAppletFromNode(childNode, nullptr); - cotainment->appendApplet(childApplet); + containment->appendApplet(childApplet); } } diff --git a/src/dfm-gui/attachedproperty.cpp b/src/dfm-gui/attachedproperty.cpp index 9ffd913c9a..b884d92230 100644 --- a/src/dfm-gui/attachedproperty.cpp +++ b/src/dfm-gui/attachedproperty.cpp @@ -24,24 +24,6 @@ AppletAttached::~AppletAttached() { } Applet *AppletAttached::qmlAttachedProperties(QObject *object) { - AppletItem *item = qobject_cast(object); - if (item) { - return item->applet(); - } - Applet *applet = qobject_cast(object); - if (applet) { - return applet; - } - - QObject *parent = object->parent(); - while (parent) { - if (auto parItem = qobject_cast(parent)) { - return parItem->applet(); - } - - parent = parent->parent(); - } - if (auto context = qmlContext(object)) { return context->contextProperty("_dfm_applet").value(); } @@ -62,7 +44,8 @@ ContainmentAttached::~ContainmentAttached() { } Containment *ContainmentAttached::qmlAttachedProperties(QObject *object) { - return qobject_cast(AppletAttached::qmlAttachedProperties(object)); + auto contain = qobject_cast(AppletAttached::qmlAttachedProperties(object)); + return contain; } DFMGUI_END_NAMESPACE diff --git a/src/dfm-gui/windowhandle.cpp b/src/dfm-gui/windowhandle.cpp index a951aa5c68..45d35aedc5 100644 --- a/src/dfm-gui/windowhandle.cpp +++ b/src/dfm-gui/windowhandle.cpp @@ -9,7 +9,7 @@ DFMGUI_BEGIN_NAMESPACE -class FileManagerWindowHandleData : public QSharedData +class WindowHandleData : public QSharedData { public: QPointer panel; @@ -22,18 +22,18 @@ class FileManagerWindowHandleData : public QSharedData * \brief 提供用于操作的窗口和Applet指针 */ WindowHandle::WindowHandle() - : data(new FileManagerWindowHandleData) + : data(new WindowHandleData) { } WindowHandle::WindowHandle(const QString &error) - : data(new FileManagerWindowHandleData) + : data(new WindowHandleData) { data->errorString = error; } WindowHandle::WindowHandle(Panel *p, QQuickWindow *w) - : data(new FileManagerWindowHandleData) + : data(new WindowHandleData) { data->panel = p; data->window = w; diff --git a/src/dfm-gui/windowmanager.cpp b/src/dfm-gui/windowmanager.cpp index 1161450500..f7cc55a390 100644 --- a/src/dfm-gui/windowmanager.cpp +++ b/src/dfm-gui/windowmanager.cpp @@ -40,6 +40,7 @@ void WindowManagerPrivate::asyncLoadQuickItem(Applet *applet) tmpEngine->completeCreation(); QObject *rootObject = tmpEngine->rootObject(); if (AppletItem *item = qobject_cast(rootObject)) { + item->setApplet(applet); applet->dptr->setRootObject(item); if (auto containment = applet->containment()) {