Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [gui/detailspace] appletfactory and uri format #2072

Merged
merged 1 commit into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/appletwindow/AppletItemEx.qml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import QtQuick 2.15
import QtQuick.Controls
import org.dfm.base
import org.deepin.filemanager.gui

AppletItem {
property int flag: 1
Expand Down
2 changes: 1 addition & 1 deletion examples/appletwindow/Panel.qml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import QtQuick 2.15
import QtQuick.Controls
import org.dfm.base
import org.deepin.filemanager.gui

ApplicationWindow {
height: 600
Expand Down
17 changes: 11 additions & 6 deletions include/dfm-gui/appletfactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,31 @@ class AppletFactoryData;
class AppletFactory
{
public:
using CreateFunc = std::function<Applet *(const QUrl &url, Containment *parent, QString *error)>;
using CreateFunc = std::function<Applet *(const QString &id, Containment *parent, QString *error)>;
static AppletFactory *instance();

bool regCreator(const QString &scheme, CreateFunc creator, QString *errorString = nullptr);
Applet *create(const QUrl &url, Containment *parent = nullptr, QString *errorString = nullptr);
bool regCreator(const QString &id, CreateFunc creator, QString *errorString = nullptr);
Applet *create(const QString &id, Containment *parent = nullptr, QString *errorString = nullptr);

protected:
private:
explicit AppletFactory();
QScopedPointer<AppletFactoryData> d;
};

class ViewAppletFactory : public AppletFactory
class ViewAppletFacotryData;
class ViewAppletFactory
{
public:
using CreateFunc = std::function<Applet *(const QUrl &url, Containment *parent, QString *error)>;
static ViewAppletFactory *instance();

bool regCreator(const QString &plugin, const QString &qmlFile, const QString &scheme,
AppletFactory::CreateFunc creator, QString *errorString = nullptr);
CreateFunc creator, QString *errorString = nullptr);
Applet *create(const QUrl &url, Containment *parent = nullptr, QString *errorString = nullptr);

private:
explicit ViewAppletFactory();
QScopedPointer<ViewAppletFacotryData> d;
};

DFMGUI_END_NAMESPACE
Expand Down
7 changes: 4 additions & 3 deletions src/dfm-declarative/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick REQUIRED)
# TODO:放到公共目录?
# 通过 Qt cmake 接口注册组件
qt_add_qml_module(${BIN_NAME}
URI org.dfm.${BASE_NAME}
URI org.deepin.filemanager.${BASE_NAME}
VERSION 1.0
SHARED
RESOURCE_PREFIX /
OUTPUT_DIRECTORY ${DFM_BUILD_PLUGIN_DIR}/qml/org/dfm/${BASE_NAME}
OUTPUT_DIRECTORY ${DFM_BUILD_PLUGIN_DIR}/qml/org/deepin/filemanager/${BASE_NAME}
QML_FILES ActionMenu.qml AnimationHSpliter.qml
)

Expand All @@ -50,4 +50,5 @@ set_target_properties(${BIN_NAME} PROPERTIES
)

# install module
install(DIRECTORY ${DFM_BUILD_PLUGIN_DIR}/qml/org/dfm/${BASE_NAME} DESTINATION ${DFM_QML_MODULE}/org/dfm)
install(DIRECTORY ${DFM_BUILD_PLUGIN_DIR}/qml/org/deepin/filemanager/${BASE_NAME}
DESTINATION ${DFM_QML_MODULE}/org/deepin/filemanager)
15 changes: 9 additions & 6 deletions src/dfm-gui/applet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ AppletPrivate::AppletPrivate(Applet *q)
AppletPrivate::~AppletPrivate()
{
// 释放关联的 QQuickItem
if (rootObject && QJSEngine::CppOwnership == QJSEngine::objectOwnership(rootObject)) {
Q_ASSERT_X(rootObject->parent() == q_ptr, "AppletItem memory management", "Undefined behaviour, unmanaged QQuickItem");

if (rootObject) {
QObject::disconnect(rootObject, nullptr, q_ptr, nullptr);
rootObject->deleteLater();
if (QJSEngine::CppOwnership == QJSEngine::objectOwnership(rootObject)) {
Q_ASSERT_X(rootObject->parent() == q_ptr, "AppletItem memory management", "Undefined behaviour, unmanaged QQuickItem");

rootObject->deleteLater();
}
}
}

Expand Down Expand Up @@ -62,12 +64,13 @@ bool AppletPrivate::createComplete(SharedQmlEngine *engine)
Q_FALLTHROUGH();
case Applet::kContainment:
if (auto *item = qobject_cast<AppletItem *>(rootObject)) {
// 先设置关联,再抛出信号
item->setApplet(q);
setRootObject(item);

if (auto *containment = q->containment()) {
rootObject->setParent(containment->rootObject());
}

setRootObject(item);
return true;
}

Expand Down
161 changes: 96 additions & 65 deletions src/dfm-gui/appletfactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,17 @@

#include <dfm-framework/lifecycle/lifecycle.h>

#include <QFileInfo>
#include <QDir>
#include <QFileInfo>

DFMGUI_BEGIN_NAMESPACE

class AppletFactoryData
{
public:
bool regCreator(const QString &scheme, AppletFactory::CreateFunc creator, QString *errorString, QUrl qmlUrl = {});

struct CreateInfo
{
QUrl qmlComponent;
AppletFactory::CreateFunc func;
};

bool checkRoute { false };
dfmbase::DThreadMap<QString, CreateInfo> constructList {};
dfmbase::DThreadMap<QString, AppletFactory::CreateFunc> constructList {};
};

bool AppletFactoryData::regCreator(const QString &scheme, AppletFactory::CreateFunc creator, QString *errorString, QUrl qmlUrl)
{
QString error;
dfmbase::FinallyUtil finally([&]() {
if (errorString)
*errorString = error;
});

if (constructList.contains(scheme)) {
error = "The current url has registered "
"the associated construction class";
return false;
}

constructList.insert(scheme, { qmlUrl, creator });
finally.dismiss();
return true;
}

/*!
* \class AppletFactory
* \brief 类似 SchemeFactory 提供拓展 Applet 类创建函数的注册管理
Expand All @@ -67,61 +39,72 @@ AppletFactory *AppletFactory::instance()
}

/*!
* \brief 注册Applet创建器 \a creator 与 \a scheme 的关联
* \return 注册结果,如果当前已存在 \a scheme 的关联,则返回 false ,错误信息会写入 \a errorString
* \brief 注册Applet创建器 \a creator 与 \a id 的关联
* \return 注册结果,如果当前已存在 \a id 的关联,则返回 false ,错误信息会写入 \a errorString
*/
bool AppletFactory::regCreator(const QString &scheme, CreateFunc creator, QString *errorString)
bool AppletFactory::regCreator(const QString &id, CreateFunc creator, QString *errorString)
{
return d->regCreator(scheme, creator, errorString);
QString error;
dfmbase::FinallyUtil finally([&]() {
if (errorString)
*errorString = error;
});

if (d->constructList.contains(id)) {
error = "The current url has registered "
"the associated construction class";
return false;
}

d->constructList.insert(id, creator);
finally.dismiss();
return true;
}

/*!
* \brief 根据需要构造的 \a url 进行顶层类构造,调用该函数存在前置条件,否则将创建空指针
* (ViewAppletFactory)需要注册scheme到DFMUrlRoute类
* 需要注册scheme到 AppletFactory 类
* 构造函数可识别传入的 \a parent 进行绑定或属性设置等处理
* \brief 根据需要构造的标识 \a id 进行已注册 Applet 的构造,此函数一般用于存在静态元信息的插件注册
* 构造函数可识别传入的 \a parent 进行绑定或属性设置等处理
*
* \return 构造的 Applet 指针
* (ViewAppletFactory)如果没有注册 scheme 到 DFMUrlRoute,返回空指针
* 如果没有注册 scheme 与 class 构造函数规则,返回空指针
* 如果出现错误,错误信息会写入 \a errorString
* \return 构造的 Applet 指针,出现错误返回 nullptr,错误信息会写入 \a errorString
*/
Applet *AppletFactory::create(const QUrl &url, Containment *parent, QString *errorString)
Applet *AppletFactory::create(const QString &id, Containment *parent, QString *errorString)
{
QString error;
dfmbase::FinallyUtil finally([&]() {
if (errorString)
*errorString = error;
});

const QString scheme = url.scheme();
if (d->checkRoute && !dfmbase::UrlRoute::hasScheme(scheme)) {
error = "No scheme found for "
"URL registration";
return nullptr;
}

auto creator = d->constructList.value(scheme);
if (!creator.func) {
error = "Scheme should be call registered 'regClass()' function "
CreateFunc constantFunc = d->constructList.value(id);
if (!constantFunc) {
error = "url should be call registered 'regClass()' function "
"before create function";
return nullptr;
}

Applet *applet = creator.func(url, parent, &error);
if (!creator.qmlComponent.isEmpty()) {
applet->setComponentUrl(creator.qmlComponent);
}
return applet;
Applet *info = constantFunc(id, parent, &error);
return info;
}

class ViewAppletFacotryData
{
public:
struct CreateInfo
{
QUrl qmlComponent;
ViewAppletFactory::CreateFunc func;
};

dfmbase::DThreadMap<QString, CreateInfo> constructList {};
};

/*!
* \class ViewAppletFactory
* \brief 类似 ViewFactory 提供较灵活的 QML 组件注册管理方式
*/
ViewAppletFactory::ViewAppletFactory()
: d(new ViewAppletFacotryData)
{
d->checkRoute = true;
}

ViewAppletFactory *ViewAppletFactory::instance()
Expand All @@ -131,17 +114,16 @@ ViewAppletFactory *ViewAppletFactory::instance()
}

/*!
* \brief 用于视图模块动态注册QML组件,不同于通过插件元信息的注册,这类 Applet 是匿名的,不会注册
* \brief 注册Applet创建器 \a creator 与 \a id 的关联
* \details 用于视图模块动态注册QML组件,不同于通过插件元信息的注册,这类 Applet 是匿名的,不会注册
* 到 Applet 管理中,也不存在默认的依赖关系。
* 传入插件名 \a plugin 和QML文件 \a qml 用于查找 Applet 关联的QML组件,组件文件路径如下组合:
* `[插件路径]/[插件名]/qml路径`
* 其它参考 AppletFactory::regCreator()
*
* \return 是否注册成功,对于 ViewAppletFactory ,如果为查找到 \a plugin 对应插件,或
* \a qmlFile 文件不在制定路径,返回 false
* \return 是否注册成功,如果未查找到 \a plugin 对应插件,或 \a qmlFile 文件不在制定路径,返回 false
*/
bool ViewAppletFactory::regCreator(const QString &plugin, const QString &qmlFile, const QString &scheme,
AppletFactory::CreateFunc creator, QString *errorString)
CreateFunc creator, QString *errorString)
{
QString error;
dfmbase::FinallyUtil finally([&]() {
Expand All @@ -164,7 +146,56 @@ bool ViewAppletFactory::regCreator(const QString &plugin, const QString &qmlFile
}

QUrl qmlUrl = QUrl::fromLocalFile(fullPath);
return d->regCreator(scheme, creator, &error, qmlUrl);

if (d->constructList.contains(scheme)) {
error = "The current url has registered "
"the associated construction class";
return false;
}

d->constructList.insert(scheme, { qmlUrl, creator });
finally.dismiss();
return true;
}

/*!
* \brief 根据需要构造的 \a url (含scheme信息)进行顶层类构造,调用该函数存在前置条件,否则将创建空指针
* 需要注册scheme到DFMUrlRoute类
* 需要注册scheme到 AppletFactory 类
* 构造函数可识别传入的 \a parent 进行绑定或属性设置等处理
*
* \return 构造的 Applet 指针
* 如果没有注册 scheme 到 DFMUrlRoute,返回空指针
* 如果没有注册 scheme 与 class 构造函数规则,返回空指针
* 如果出现错误,错误信息会写入 \a errorString
*/
Applet *ViewAppletFactory::create(const QUrl &url, Containment *parent, QString *errorString)
{
QString error;
dfmbase::FinallyUtil finally([&]() {
if (errorString)
*errorString = error;
});

const QString scheme = url.scheme();
if (!dfmbase::UrlRoute::hasScheme(scheme)) {
error = "No scheme found for "
"URL registration";
return nullptr;
}

auto creator = d->constructList.value(scheme);
if (!creator.func) {
error = "Scheme should be call registered 'regClass()' function "
"before create function";
return nullptr;
}

Applet *applet = creator.func(url, parent, &error);
if (!creator.qmlComponent.isEmpty()) {
applet->setComponentUrl(creator.qmlComponent);
}
return applet;
}

DFMGUI_END_NAMESPACE
4 changes: 1 addition & 3 deletions src/dfm-gui/appletmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,7 @@ Applet *AppletManager::createAppletFromInfo(const dpf::PluginQuickMetaPtr &metaP

Applet *appletPtr = nullptr;
if (!metaPtr->applet().isEmpty()) {
QUrl appletUrl;
appletUrl.setScheme(metaPtr->applet());
appletPtr = AppletFactory::instance()->create(appletUrl, parent, &error);
appletPtr = AppletFactory::instance()->create(metaPtr->applet(), parent, &error);
if (!appletPtr) {
return nullptr;
}
Expand Down
5 changes: 1 addition & 4 deletions src/dfm-gui/sharedqmlengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ SharedQmlEnginePrivate::SharedQmlEnginePrivate(SharedQmlEngine *q)
*/
bool SharedQmlEnginePrivate::continueLoading()
{
if (!component) {
qCWarning(logDFMGui) << "No QQmlComponent";
return false;
}
Q_ASSERT_X(nullptr != component, "Create qml component", "Undefined component");

if (component->isReady()) {
rootObject = component->beginCreate(rootContext);
Expand Down
Loading
Loading