Skip to content

Commit

Permalink
feat: [gui/detailspace] appletfactory and uri format
Browse files Browse the repository at this point in the history
* Split AppletFactory;
* Update uri format as 'org.deepin.filemanager';
* DetailSpaceHelper adapt containment.

Log: AppletFactory and uri format.
  • Loading branch information
rb-union committed Jul 1, 2024
1 parent 08ad338 commit 77f52fd
Show file tree
Hide file tree
Showing 24 changed files with 235 additions and 167 deletions.
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.base

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.base

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

0 comments on commit 77f52fd

Please sign in to comment.