-
Notifications
You must be signed in to change notification settings - Fork 140
feat: migrate QML plugins to Qt6 resource system #2925
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
base: master
Are you sure you want to change the base?
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: caixr23 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Reviewer's GuideMigrates QML plugin handling and control center QML loading from filesystem-based directories to Qt 6’s qrc-based QML module system, updating plugin discovery/loading logic, icon theme search paths, URL handling for local resources, and CMake build/install rules, while adding system/device plugins as proper subdirectories. Sequence diagram for updated QML plugin loading (QRC and file-based)sequenceDiagram
participant App as ControlCenter
participant PM as PluginManager
participant TP as QThreadPool
participant Task as LoadPluginTask
participant QFile
participant QQmlFile
participant QQmlComponent
App->>PM: loadModules(root, async, blacklist)
loop For each plugin directory
PM->>PM: create PluginData(name, path)
PM->>PM: loadMetaData(plugin)
alt plugin has lib<name>_qml.so
PM->>TP: start(new LoadPluginTask(plugin, this, true))
TP-->>Task: run()
Task->>Task: doLoadQrc()
Task->>QFile: exists(soPath)
alt soPath exists
Task->>PM: updatePluginStatus(MetaDataLoad)
Task->>Task: load shared object via QLibrary
else soPath missing
Task->>PM: updatePluginStatus(MetaDataErr | MetaDataEnd)
end
Task->>Task: build qmlPaths list via pluginQmlPath()
loop probe candidate QML URLs
Task->>QQmlFile: isLocalFile(path)
alt local file
Task->>QFile: QFileInfo(urlToLocalFileOrQrc(path)).exists()
else qrc or nonlocal
Task->>QFile: QFileInfo(path).exists()
end
alt exists
Task->>Task: m_data->qmlPathType = matchedType
Task->>Task: break
end
end
Task->>PM: updatePluginStatus(MetaDataEnd)
else no lib<name>_qml.so
PM->>PM: updatePluginStatus(MetaDataEnd)
end
end
loop For each PluginData in m_plugins
PM->>PM: loadPlugin(plugin)
PM->>PM: loadModule(plugin)
PM->>PM: qmlPath = pluginQmlPath(plugin, plugin->qmlPathType, PT_MODULE)
PM->>PM: paths = DIconTheme::dciThemeSearchPaths()
PM->>PM: paths.append(pluginQmlPath(plugin, plugin->qmlPathType, PT_DIR))
PM->>PM: DIconTheme::setDciThemeSearchPaths(paths)
alt qmlPathType is not QMLPATH_IsQrc and !QFile::exists(qmlPath)
PM->>PM: updatePluginStatus(ModuleErr | ModuleEnd)
else
PM->>PM: updatePluginStatus(ModuleLoad)
PM->>QQmlComponent: new QQmlComponent(engine)
PM->>QQmlComponent: setProperty(PluginData, plugin)
PM->>QQmlComponent: loadUrl(qmlPath, Asynchronous)
end
PM->>PM: loadMain(plugin)
PM->>PM: updatePluginStatus(MainObjLoad)
PM->>PM: mainPath = pluginQmlPath(plugin, plugin->qmlPathType, PT_MAIN)
alt mainPath not empty
PM->>QQmlComponent: new QQmlComponent(engine)
PM->>QQmlComponent: setProperty(PluginData, plugin)
PM->>QQmlComponent: loadUrl(mainPath, Asynchronous)
end
end
Class diagram for updated QML plugin loading structuresclassDiagram
class PluginManager {
+PluginManager(DccManager *parent)
+void loadMetaData(PluginData *plugin)
+void loadModule(PluginData *plugin)
+void loadMain(PluginData *plugin)
+void loadModules(DccObject *root, bool async, const QStringList &blacklist)
+void loadPlugin(PluginData *plugin)
+bool isDeleting() const
+QThreadPool* threadPool()
+Q_SIGNAL void updatePluginStatus(PluginData *plugin, int status, const QString &msg)
}
class LoadPluginTask {
-PluginManager *m_pManager
-PluginData *m_data
-bool m_isQrc
+LoadPluginTask(PluginData *data, PluginManager *pManager, bool isQrc=false)
+void run() override
-void doLoadSo()
-void doLoadQrc()
}
class PluginData {
+QString name
+QString path
+uint qmlPathType
+DccObject *module
+DccObject *mainObj
+DccObject *soObj
+QThread *thread
+PluginData(const QString &_name, const QString &_path)
+~PluginData()
}
class PluginQmlPathType {
<<enumeration>>
QMLPATH_IsQrc = 0x01
QMLPATH_IsQmlDir = 0x02
QMLPATH_IsCapitalize = 0x04
QML_Local_Lower = 0
QML_Local_Capitalize
QML_QRC_Capitalize
QML_QRC_Lower
QML_QRC_QML_Capitalize
QML_QRC_QML_Lower
}
class PathType {
<<enumeration>>
PT_MODULE
PT_MAIN
PT_DIR
PT_QTC_DIR
}
class PluginStatus {
<<enumeration>>
PluginBegin = 0x10000000
PluginEnd = 0x20000000
MetaDataLoad = 0x02000000
MetaDataEnd = 0x04000000
MetaDataErr = 0x08000000
ModuleLoad
ModuleErr
MainObjLoad
DataBegin
DataEnd
MainObjEnd
PluginEndMask
}
PluginManager "1" --> "*" PluginData : manages
PluginManager "1" --> "*" LoadPluginTask : creates
LoadPluginTask "1" --> "1" PluginData : loads
LoadPluginTask "1" --> "1" PluginManager : reports_status
PluginData --> PluginQmlPathType : uses_qmlPathType
PluginManager --> PluginQmlPathType : uses
PluginManager --> PathType : uses
LoadPluginTask --> PluginStatus : emits
class GlobalFunctions {
+QString pluginQmlPath(PluginData *plugin, uint pathType, PathType type)
}
GlobalFunctions --> PluginData
GlobalFunctions --> PluginQmlPathType
GlobalFunctions --> PathType
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - I've found 3 issues, and left some high level feedback:
- In
DeepinIDUserInfo.qmlthe avatar source is now always prefixed withfile://; consider following the pattern used elsewhere (checking for an absolute path and usingQUrl::fromLocalFileor equivalent) to avoid double-prefixing when the model already provides a URL. - In
PluginManager::loadModule,DIconTheme::dciThemeSearchPathsis appended to on every plugin load but never restored, which can lead to unbounded growth and duplicates; consider computing per-plugin paths without mutating global state repeatedly or restoring the original list after use. - In
LoadPluginTask::doLoadQrc, a missinglib*_qml.soemitsMetaDataErr | MetaDataEndbut the function still proceeds to QML path probing and finally emitsMetaDataEndagain; it may be clearer either to return early on error or to adjust the status flags to avoid conflicting signals for the same plugin.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `DeepinIDUserInfo.qml` the avatar source is now always prefixed with `file://`; consider following the pattern used elsewhere (checking for an absolute path and using `QUrl::fromLocalFile` or equivalent) to avoid double-prefixing when the model already provides a URL.
- In `PluginManager::loadModule`, `DIconTheme::dciThemeSearchPaths` is appended to on every plugin load but never restored, which can lead to unbounded growth and duplicates; consider computing per-plugin paths without mutating global state repeatedly or restoring the original list after use.
- In `LoadPluginTask::doLoadQrc`, a missing `lib*_qml.so` emits `MetaDataErr | MetaDataEnd` but the function still proceeds to QML path probing and finally emits `MetaDataEnd` again; it may be clearer either to return early on error or to adjust the status flags to avoid conflicting signals for the same plugin.
## Individual Comments
### Comment 1
<location> `src/dde-control-center/pluginmanager.cpp:117-126` </location>
<code_context>
+ }
+ path += QString(":/org/deepin/dcc/") + plugin->name;
+
+ } else {
+ path = plugin->path;
+ }
</code_context>
<issue_to_address>
**issue (bug_risk):** Missing early return after SO-missing error causes double MetaDataEnd emission and inconsistent state.
When `soPath` does not exist in `doLoadQrc()`, you emit `MetaDataErr | MetaDataEnd` but still run the QML path detection loop and emit `MetaDataEnd` again. This double emission can make consumers see a normal completion after an error, complicating state handling. Please either return immediately after emitting the error or avoid emitting the final `MetaDataEnd` in this branch to keep the status sequence consistent.
</issue_to_address>
### Comment 2
<location> `src/dde-control-center/pluginmanager.cpp:280` </location>
<code_context>
+ };
+
+ for (const auto &path : qmlPaths) {
+ if ((QQmlFile::isLocalFile(path.first) && QFileInfo(QQmlFile::urlToLocalFileOrQrc(path.first)).exists()) || QFileInfo(path.first).exists()) {
+ m_data->qmlPathType = path.second;
+ break;
</code_context>
<issue_to_address>
**issue (bug_risk):** QML file existence check does not work for qrc URLs and likely never marks qmlPathType as QML-based.
In `doLoadQrc()`, this condition never succeeds for `qrc:/...` URLs: `QQmlFile::isLocalFile("qrc:/...")` is false, and `QFileInfo("qrc:/...").exists()` is also false because it expects a local path. That leaves `qmlPathType` at the default local type even when the QML actually lives in resources, sending `pluginQmlPath` and `loadModule/loadMain` down the wrong paths. Use `QQmlFile::urlToLocalFileOrQrc(path.first)` (or `QQmlFile::exists`) for all URLs and run the existence check on the resolved path so qrc resources are correctly detected.
</issue_to_address>
### Comment 3
<location> `src/dde-control-center/pluginmanager.cpp:108` </location>
<code_context>
+ PT_QTC_DIR, // qrc:/org/deepin/dcc 形式
+};
+
+static QString pluginQmlPath(PluginData *plugin, uint pathType, PathType type)
+{
+ QString path;
</code_context>
<issue_to_address>
**issue (complexity):** Consider refactoring the new QML path logic by separating path-building from existence checks and centralizing the search strategy into small helpers instead of inlined bitmask logic.
You can keep all current behavior but significantly reduce complexity and coupling by (1) splitting path construction from existence checks and (2) avoiding raw bitmask use at call sites.
### 1. Split `pluginQmlPath` responsibilities
Right now `pluginQmlPath` both builds paths and does existence checking for `PT_MAIN`. That makes it hard to reason about and forces extra flags. You can keep the same external behavior by separating **pattern construction** from **existence resolution**:
```cpp
// Keep using PluginQmlPathType + PathType, but make this builder "dumb".
static QString buildQmlPath(const PluginData *plugin, uint pathType, PathType type)
{
QString path;
if (pathType & PluginQmlPathType::QMLPATH_IsQrc) {
if (type != PT_DIR && type != PT_MAIN) {
path = QStringLiteral("qrc");
}
path += QStringLiteral(":/org/deepin/dcc/") + plugin->name;
} else {
path = plugin->path;
}
if (pathType & PluginQmlPathType::QMLPATH_IsQmlDir) {
path += QStringLiteral("/qml");
}
if (type & PT_DIR) {
return path;
}
const QString baseName = (pathType & PluginQmlPathType::QMLPATH_IsCapitalize)
? plugin->name.left(1).toUpper() + plugin->name.mid(1)
: plugin->name;
if (type == PT_MAIN) {
// just return first candidate, don't check here
return path + "/" + baseName + "Main.qml";
}
return path + "/" + baseName + ".qml";
}
// small helper to try the main.qml variants and do existence checks
static QString resolveMainQml(const PluginData *plugin, uint pathType)
{
const QString base = buildQmlPath(plugin, pathType, PT_DIR);
QStringList candidates{
base + "/" + plugin->name.left(1).toUpper() + plugin->name.mid(1) + "Main.qml",
base + "/main.qml",
};
for (const auto &qmlPath : candidates) {
const QString url = (pathType & PluginQmlPathType::QMLPATH_IsQrc)
? QStringLiteral("qrc") + qmlPath
: qmlPath;
if ((QQmlFile::isLocalFile(url) &&
QFileInfo(QQmlFile::urlToLocalFileOrQrc(url)).exists()) ||
QFileInfo(url).exists()) {
return url;
}
}
return {};
}
```
Then `loadMain` becomes simpler and no longer depends on `PT_MAIN` doing extra work:
```cpp
void PluginManager::loadMain(PluginData *plugin)
{
if (isDeleting()) {
return;
}
Q_EMIT updatePluginStatus(plugin, MainObjLoad, "load Main");
const QString qmlPath = resolveMainQml(plugin, plugin->qmlPathType);
if (qmlPath.isEmpty()) {
Q_EMIT updatePluginStatus(plugin, MainObjErr | MainObjEnd, "Main.qml not exists");
return;
}
auto *component = new QQmlComponent(m_manager->engine(), m_manager->engine());
component->setProperty("PluginData", QVariant::fromValue(plugin));
connect(component, &QQmlComponent::statusChanged, this, &PluginManager::mainLoading);
component->loadUrl(qmlPath, QQmlComponent::Asynchronous);
}
```
This keeps all existing search behavior but makes it clear where patterns are built vs where files are verified.
### 2. Reduce repetition in `doLoadQrc`
You can keep `PluginQmlPathType` as-is but express the search strategy in a compact, data-driven loop so it’s easier to see and maintain:
```cpp
void LoadPluginTask::doLoadQrc()
{
// ... existing .so loading ...
static const uint candidates[] = {
PluginQmlPathType::QML_QRC_QML_Lower,
PluginQmlPathType::QML_QRC_QML_Capitalize,
PluginQmlPathType::QML_QRC_Lower,
PluginQmlPathType::QML_QRC_Capitalize,
PluginQmlPathType::QML_Local_Lower,
PluginQmlPathType::QML_Local_Capitalize,
};
for (uint type : candidates) {
const QString modulePath = buildQmlPath(m_data, type, PT_MODULE);
const QString mainPath = resolveMainQml(m_data, type);
const QString chosen = !mainPath.isEmpty() ? mainPath : modulePath;
if (chosen.isEmpty()) {
continue;
}
if ((QQmlFile::isLocalFile(chosen) &&
QFileInfo(QQmlFile::urlToLocalFileOrQrc(chosen)).exists()) ||
QFileInfo(chosen).exists()) {
m_data->qmlPathType = type;
break;
}
}
Q_EMIT m_pManager->updatePluginStatus(
m_data, MetaDataEnd,
": load qml qrc finished. elasped time :" + QString::number(timer.elapsed()));
}
```
Benefits:
- No 12-line hardcoded list; the pattern `{module,main} × types` is explicit.
- All path construction logic lives in `buildQmlPath`/`resolveMainQml`, so if you change layout rules you only touch those helpers.
- `qmlPathType` remains the “descriptor” of the chosen layout, but the resolution logic is localized and easier to follow.
These two small refactors keep your new QRC support and icon-path integration fully intact, while cutting down on branching, redundant calls, and bitmask-related cognitive load.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| } else { | ||
| path = plugin->path; | ||
| } | ||
| if (pathType & PluginQmlPathType::QMLPATH_IsQmlDir) { | ||
| path += "/qml"; | ||
| } | ||
| if (type & PT_DIR) { | ||
| return path; | ||
| } | ||
| QString name = (pathType & PluginQmlPathType::QMLPATH_IsCapitalize) ? plugin->name.left(1).toUpper() + plugin->name.mid(1) : plugin->name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): Missing early return after SO-missing error causes double MetaDataEnd emission and inconsistent state.
When soPath does not exist in doLoadQrc(), you emit MetaDataErr | MetaDataEnd but still run the QML path detection loop and emit MetaDataEnd again. This double emission can make consumers see a normal completion after an error, complicating state handling. Please either return immediately after emitting the error or avoid emitting the final MetaDataEnd in this branch to keep the status sequence consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR migrates the DDE Control Center from file-based QML plugin loading to Qt6's resource system for improved performance and deployment. The changes introduce qt_add_qml_module for proper QML module management, add support for resource-based plugin paths, and convert local file paths to file:// URLs for QML compatibility.
Key Changes
- Replaced manual QML file copying with
qt_add_qml_modulein the build system, enabling proper Qt6 QML module integration - Enhanced plugin loading logic to support both resource-based (
qrc://) and file-based plugins with multiple path resolution strategies - Added
file://URL prefixes for local file paths in C++ models to ensure proper QML image source handling
Reviewed changes
Copilot reviewed 16 out of 27 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/plugin-system/qml/system.qml | New system plugin entry QML file with basic metadata |
| src/plugin-system/qml/metadata.json | Plugin metadata descriptor for system plugin |
| src/plugin-system/qml/commoninfo.dci | DCI icon resource for system plugin |
| src/plugin-system/CMakeLists.txt | Build configuration for system plugin using dcc_install_plugin macro |
| src/plugin-device/qml/device.qml | New device plugin entry QML file |
| src/plugin-device/qml/metadata.json | Plugin metadata descriptor for device plugin |
| src/plugin-device/qml/hardware.dci | DCI icon resource for device plugin |
| src/plugin-device/CMakeLists.txt | Build configuration for device plugin |
| src/plugin-privacy/operation/privacysecuritymodel.cpp | Converts local file icon paths to file:// URLs for QML |
| src/plugin-personalization/operation/personalizationinterface.cpp | Converts theme picture paths to file:// URLs |
| src/plugin-deepinid/qml/DeepinIDUserInfo.qml | Adds file:// prefix to avatar image source |
| src/plugin-deepinid/operation/syncinfolistmodel.cpp | Converts displayIcon paths to file:// URLs |
| src/plugin-deepinid/operation/appinfolistmodel.cpp | Converts app icon paths to file:// URLs |
| src/dde-control-center/pluginmanager.cpp | Major refactor: adds resource path resolution, QRC plugin loading, and DCI theme search path updates |
| src/dde-control-center/main.cpp | Changes main window loading from file path to QML module import |
| src/dde-control-center/frame/plugin/sidebar.dci | New sidebar icon resource file |
| src/dde-control-center/frame/plugin/reddot.dci | New notification badge icon resource |
| src/dde-control-center/frame/plugin/SecondPage.qml | New second-level navigation page with sidebar and content areas |
| src/dde-control-center/frame/plugin/HomePage.qml | Updated font reference to use D.DTK namespace |
| src/dde-control-center/frame/plugin/DccWindow.qml | New main window QML component with navigation and search |
| src/dde-control-center/frame/plugin/DccUtils.js | Moved .pragma library directive to proper location at file start |
| src/dde-control-center/frame/plugin/Crumb.qml | New breadcrumb navigation component |
| src/dde-control-center/frame/plugin/CMakeLists.txt | Updated to include resource files in qt_add_qml_module |
| src/dde-control-center/dccmanager.cpp | Updates DCI icon theme search paths to use resource prefix |
| src/dde-control-center/CMakeLists.txt | Removes manual QML file copying in favor of qt_add_qml_module |
| misc/DdeControlCenterPluginMacros.cmake | Refactored dcc_build_plugin to use qt_add_qml_module with resource support |
| CMakeLists.txt | Adds plugin-system and plugin-device subdirectories to build |
| PT_MODULE, // qrc:/org/deepin/dcc/name.qml 形式 | ||
| PT_MAIN, // qrc:/org/deepin/dcc/nameMain.qml 形式 | ||
| PT_DIR = 0x80, // :/org/deepin/dcc 形式 | ||
| PT_QTC_DIR, // qrc:/org/deepin/dcc 形式 |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PathType enum defines PT_QTC_DIR but it is never used in the code. This could indicate either dead code or a missing implementation. Consider removing it if it's not needed, or implementing the corresponding logic if it was intended to be used.
| PT_QTC_DIR, // qrc:/org/deepin/dcc 形式 |
| } else { | ||
| Q_EMIT m_pManager->updatePluginStatus(m_data, MetaDataErr | MetaDataEnd, "File does not exist:" + soPath); | ||
| } | ||
| // 尝试多种路径查找 QML 文件 | ||
| QList<QPair<QString, uint>> qmlPaths{ | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_QML_Lower, PathType::PT_MODULE), PluginQmlPathType::QML_QRC_QML_Lower }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_QML_Capitalize, PathType::PT_MODULE), PluginQmlPathType::QML_QRC_QML_Capitalize }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_Lower, PathType::PT_MODULE), PluginQmlPathType::QML_QRC_Lower }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_Capitalize, PathType::PT_MODULE), PluginQmlPathType::QML_QRC_Capitalize }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_Local_Lower, PathType::PT_MODULE), PluginQmlPathType::QML_Local_Lower }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_Local_Capitalize, PathType::PT_MODULE), PluginQmlPathType::QML_Local_Capitalize }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_QML_Lower, PathType::PT_MAIN), PluginQmlPathType::QML_QRC_QML_Lower }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_QML_Capitalize, PathType::PT_MAIN), PluginQmlPathType::QML_QRC_QML_Capitalize }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_Lower, PathType::PT_MAIN), PluginQmlPathType::QML_QRC_Lower }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_QRC_Capitalize, PathType::PT_MAIN), PluginQmlPathType::QML_QRC_Capitalize }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_Local_Lower, PathType::PT_MAIN), PluginQmlPathType::QML_Local_Lower }, // | ||
| { pluginQmlPath(m_data, PluginQmlPathType::QML_Local_Capitalize, PathType::PT_MAIN), PluginQmlPathType::QML_Local_Capitalize }, // | ||
| }; | ||
|
|
||
| for (const auto &path : qmlPaths) { | ||
| if ((QQmlFile::isLocalFile(path.first) && QFileInfo(QQmlFile::urlToLocalFileOrQrc(path.first)).exists()) || QFileInfo(path.first).exists()) { | ||
| m_data->qmlPathType = path.second; | ||
| break; | ||
| } | ||
| } | ||
| Q_EMIT m_pManager->updatePluginStatus(m_data, MetaDataEnd, ": load qml qrc finished. elasped time :" + QString::number(timer.elapsed())); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the doLoadQrc function, if the .so file does not exist, an error is emitted but the function continues to search for QML paths and eventually emits MetaDataEnd with success status. This could be confusing as it reports both an error and success. Consider returning early after emitting the error, or clarifying the intended behavior when the .so file is optional.
| m_data->soObj->moveToThread(m_pManager->thread()); | ||
| m_data->soObj->setParent(m_pManager->parent()); | ||
| } | ||
| Q_EMIT m_pManager->updatePluginStatus(m_data, DataEnd, ": load plugin finished. elasped time :" + QString::number(timer.elapsed())); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The word "elasped" is misspelled. It should be "elapsed".
| Q_EMIT m_pManager->updatePluginStatus(m_data, DataEnd, ": load plugin finished. elasped time :" + QString::number(timer.elapsed())); | |
| Q_EMIT m_pManager->updatePluginStatus(m_data, DataEnd, ": load plugin finished. elapsed time :" + QString::number(timer.elapsed())); |
| break; | ||
| } | ||
| } | ||
| Q_EMIT m_pManager->updatePluginStatus(m_data, MetaDataEnd, ": load qml qrc finished. elasped time :" + QString::number(timer.elapsed())); |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The word "elasped" is misspelled. It should be "elapsed".
| Q_EMIT m_pManager->updatePluginStatus(m_data, MetaDataEnd, ": load qml qrc finished. elasped time :" + QString::number(timer.elapsed())); | |
| Q_EMIT m_pManager->updatePluginStatus(m_data, MetaDataEnd, ": load qml qrc finished. elapsed time :" + QString::number(timer.elapsed())); |
| if (pathType & PluginQmlPathType::QMLPATH_IsQmlDir) { | ||
| path += "/qml"; | ||
| } | ||
| if (type & PT_DIR) { |
Copilot
AI
Jan 6, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition if (type != PT_DIR && type != PT_MAIN) on line 112 checks exact equality for PT_MAIN but uses bitwise check if (type & PT_DIR) on line 123. This inconsistency could lead to bugs if PT_DIR is combined with other flags. Consider using consistent comparison logic: either always use exact equality or always use bitwise checks for both conditions.
| if (type & PT_DIR) { | |
| if (type == PT_DIR || type == PT_QTC_DIR) { |
d631e7c to
00db5e4
Compare
This commit transitions the control center from file-based QML plugin loading to Qt6's resource system for better performance and deployment. Key changes include: 1. Replaced manual file copying with qt_add_qml_module for proper QML module management 2. Added plugin-system and plugin-device as proper subdirectories 3. Updated plugin loading logic to support both resource-based and file- based plugins 4. Modified DCI icon theme search paths to use resource paths 5. Fixed local file paths in QML by converting them to proper file:// URLs 6. Enhanced plugin discovery with multiple path resolution strategies The migration improves plugin loading performance, simplifies deployment, and provides better integration with Qt6's QML module system. It also maintains backward compatibility with existing file- based plugins. Log: Improved QML plugin loading performance and deployment Influence: 1. Test control center startup and plugin loading 2. Verify all plugin modules load correctly (system, device, accounts, etc.) 3. Check icon display in various modules 4. Test plugin navigation and functionality 5. Verify resource paths work in different deployment scenarios 6. Test backward compatibility with existing plugin configurations feat: 迁移 QML 插件到 Qt6 资源系统 本次提交将控制中心从基于文件的 QML 插件加载迁移到 Qt6 资源系统,以获得更 好的性能和部署体验。主要变更包括: 1. 使用 qt_add_qml_module 替代手动文件复制,实现更好的 QML 模块管理 2. 添加 plugin-system 和 plugin-device 作为正式子目录 3. 更新插件加载逻辑以支持基于资源和基于文件的插件 4. 修改 DCI 图标主题搜索路径以使用资源路径 5. 通过转换为 file:// URL 修复 QML 中的本地文件路径问题 6. 增强插件发现功能,支持多种路径解析策略 此次迁移提高了插件加载性能,简化了部署流程,并提供了与 Qt6 QML 模块系统 的更好集成。同时保持了对现有基于文件的插件的向后兼容性。 Log: 提升 QML 插件加载性能和部署体验 Influence: 1. 测试控制中心启动和插件加载 2. 验证所有插件模块正确加载(系统、设备、账户等) 3. 检查各模块中的图标显示 4. 测试插件导航和功能 5. 验证资源路径在不同部署场景下的工作 6. 测试与现有插件配置的向后兼容性
deepin pr auto review我来对这段代码进行审查,主要从以下几个方面分析:
建议改进:
这些改进使得代码更加模块化、可维护,同时也提高了性能和安全性。整体来说,这是一个很好的重构,采用了 Qt6 的新特性,使代码更加现代化和规范化。 |
|
TAG Bot New tag: 6.1.66 |
| Q_EMIT m_pManager->updatePluginStatus(m_data, DataEnd, ": load plugin finished. elapsed time :" + QString::number(timer.elapsed())); | ||
| } | ||
|
|
||
| void LoadPluginTask::doLoadQrc() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
看能否不自己去实现这种加载资源的方式,使用qt提供的loadFromModule这种
| } | ||
| } | ||
| if (!plugin->qmlModule.isEmpty() || !plugin->qmlMain.isEmpty()) { | ||
| plugin->qmlDir = path.startsWith(":") ? "qrc" + path : path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这种可以使用qtquick提供的接口,qmlfile去转这种类型,
另外,看我们能不能减少这种规则的fallback,
嵌套有点儿深,
| } | ||
| }; | ||
|
|
||
| static bool checkQmlPath(PluginData *plugin) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个不仅仅是check吧,它更主要的功能是设置PluginData的数据,而且返回值我看没地方使用,
| } else { | ||
|
|
||
| QStringList paths = Dtk::Gui::DIconTheme::dciThemeSearchPaths(); | ||
| const QString rcPath = plugin->qmlDir.startsWith("qrc:") ? plugin->qmlDir.mid(3) : plugin->qmlDir; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我看qmlDir这个变量,在checkQmlPath时已经转换了,这里怎么又剪去了?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 16 out of 27 changed files in this pull request and generated 1 comment.
| .pragma library | ||
| // SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd. | ||
| // SPDX-License-Identifier: GPL-3.0-or-later |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pragma directive should come after the SPDX license headers, not before them. While functionally it may work in either position, placing license headers first is the standard convention for consistency and legal clarity. The pragma library directive should be moved to line 4 after the license header.
| .pragma library | |
| // SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd. | |
| // SPDX-License-Identifier: GPL-3.0-or-later | |
| // SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd. | |
| // SPDX-License-Identifier: GPL-3.0-or-later | |
| .pragma library |
|
TAG Bot New tag: 6.1.67 |
This commit transitions the control center from file-based QML plugin loading to Qt6's resource system for better performance and deployment. Key changes include:
The migration improves plugin loading performance, simplifies deployment, and provides better integration with Qt6's QML module system. It also maintains backward compatibility with existing file- based plugins.
Log: Improved QML plugin loading performance and deployment
Influence:
feat: 迁移 QML 插件到 Qt6 资源系统
本次提交将控制中心从基于文件的 QML 插件加载迁移到 Qt6 资源系统,以获得更
好的性能和部署体验。主要变更包括:
此次迁移提高了插件加载性能,简化了部署流程,并提供了与 Qt6 QML 模块系统
的更好集成。同时保持了对现有基于文件的插件的向后兼容性。
Log: 提升 QML 插件加载性能和部署体验
Influence:
Summary by Sourcery
Migrate the control center and its plugins from filesystem-based QML loading to Qt 6’s resource-based QML module system while preserving compatibility with existing plugins.
New Features:
Enhancements:
Build:
Tests: