From b198afb705da3ac5f69c269a1c3ead877d0dcb96 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 23 Apr 2024 10:12:48 +0700 Subject: [PATCH 1/3] Implement plugin uninstall mechanism --- src/core/pluginmanager.cpp | 13 +++++++ src/core/pluginmanager.h | 1 + src/qml/PluginManagerSettings.qml | 60 +++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/core/pluginmanager.cpp b/src/core/pluginmanager.cpp index 0a8dad6eca..61c6368f9e 100644 --- a/src/core/pluginmanager.cpp +++ b/src/core/pluginmanager.cpp @@ -408,6 +408,19 @@ void PluginManager::installFromUrl( const QString &url ) } ); } +void PluginManager::uninstall( const QString &uuid ) +{ + if ( mAvailableAppPlugins.contains( uuid ) ) + { + disableAppPlugin( uuid ); + + QFileInfo fi( mAvailableAppPlugins[uuid].path() ); + fi.absoluteDir().removeRecursively(); + + refreshAppPlugins(); + } +} + QString PluginManager::findProjectPlugin( const QString &projectPath ) { const QFileInfo fi( projectPath ); diff --git a/src/core/pluginmanager.h b/src/core/pluginmanager.h index 0ac661a221..1c2183b7bd 100644 --- a/src/core/pluginmanager.h +++ b/src/core/pluginmanager.h @@ -89,6 +89,7 @@ class PluginManager : public QObject void restoreAppPlugins(); Q_INVOKABLE void installFromUrl( const QString &url ); + Q_INVOKABLE void uninstall( const QString &uuid ); static QString findProjectPlugin( const QString &projectPath ); diff --git a/src/qml/PluginManagerSettings.qml b/src/qml/PluginManagerSettings.qml index fd9c19141e..a622285d69 100644 --- a/src/qml/PluginManagerSettings.qml +++ b/src/qml/PluginManagerSettings.qml @@ -101,8 +101,11 @@ Popup { MouseArea { anchors.fill: parent onClicked: { - toggleEnabledPlugin.checked = !toggleEnabledPlugin.checked - toggleEnabledPlugin.clicked() + if (!Enabled) { + pluginManager.enableAppPlugin(Uuid) + } else { + pluginManager.disableAppPlugin(Uuid) + } } } } @@ -115,7 +118,7 @@ Popup { onClicked: { Enabled = checked == true - if (checked) { + if (Enabled) { pluginManager.enableAppPlugin(Uuid) } else { pluginManager.disableAppPlugin(Uuid) @@ -141,6 +144,20 @@ Popup { color: Theme.secondaryTextColor wrapMode: Text.WordWrap } + + Label { + Layout.fillWidth: true + text: "" + qsTr("Uninstall") + "" + font: Theme.tipFont + color: Theme.secondaryTextColor + wrapMode: Text.WordWrap + + onLinkActivated: (link) => { + uninstallConfirmation.pluginName = Name + uninstallConfirmation.pluginUuid = Uuid + uninstallConfirmation.open() + } + } } } } @@ -216,6 +233,43 @@ Popup { } } + Dialog { + id: uninstallConfirmation + title: "Uninstall Plugin" + parent: mainWindow.contentItem + x: ( mainWindow.width - width ) / 2 + y: ( mainWindow.height - height - 80 ) / 2 + + property string pluginName: "" + property string pluginUuid: "" + + Column { + width: childrenRect.width + height: childrenRect.height + spacing: 10 + + TextMetrics { + id: uninstallLabelMetrics + font: uninstallLabel.font + text: uninstallLabel.text + } + + Label { + id: uninstallLabel + width: mainWindow.width - 60 < uninstallLabelMetrics.width ? mainWindow.width - 60 : uninstallLabelMetrics.width + text: qsTr("Are you sure you want to uninstall `%1`?").arg(uninstallConfirmation.pluginName) + wrapMode: Text.WordWrap + font: Theme.defaultFont + color: Theme.mainTextColor + } + } + + standardButtons: Dialog.Ok | Dialog.Cancel + onAccepted: { + pluginManager.uninstall(pluginUuid) + } + } + Connections { target: pluginManager From f14df8aace8e692ce4df34affedccd7169a5de94 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 23 Apr 2024 10:25:22 +0700 Subject: [PATCH 2/3] Add plugin version metadata to help users and authors communicate with each other on issues --- src/core/pluginmanager.cpp | 4 +++- src/core/pluginmanager.h | 6 +++++- src/qml/PluginManagerSettings.qml | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/core/pluginmanager.cpp b/src/core/pluginmanager.cpp index 61c6368f9e..14baf1c40c 100644 --- a/src/core/pluginmanager.cpp +++ b/src/core/pluginmanager.cpp @@ -229,6 +229,7 @@ void PluginManager::refreshAppPlugins() QString description; QString author; QString icon; + QString version; const QString metadataPath = QStringLiteral( "%1/metadata.txt" ).arg( candidate.absoluteFilePath() ); if ( QFileInfo::exists( metadataPath ) ) @@ -241,8 +242,9 @@ void PluginManager::refreshAppPlugins() { icon = QStringLiteral( "%1/%2" ).arg( candidate.absoluteFilePath(), metadata.value( "icon" ).toString() ); } + version = metadata.value( "version" ).toString(); } - mAvailableAppPlugins.insert( candidate.fileName(), PluginInformation( candidate.fileName(), name, description, author, icon, path ) ); + mAvailableAppPlugins.insert( candidate.fileName(), PluginInformation( candidate.fileName(), name, description, author, icon, version, path ) ); } } } diff --git a/src/core/pluginmanager.h b/src/core/pluginmanager.h index 1c2183b7bd..06c9053195 100644 --- a/src/core/pluginmanager.h +++ b/src/core/pluginmanager.h @@ -29,14 +29,16 @@ class PluginInformation Q_PROPERTY( QString description READ description ) Q_PROPERTY( QString author READ author ) Q_PROPERTY( QString icon READ icon ) + Q_PROPERTY( QString version READ version ) public: - PluginInformation( const QString &uuid = QString(), const QString &name = QString(), const QString &description = QString(), const QString &author = QString(), const QString &icon = QString(), const QString &path = QString() ) + PluginInformation( const QString &uuid = QString(), const QString &name = QString(), const QString &description = QString(), const QString &author = QString(), const QString &icon = QString(), const QString &version = QString(), const QString &path = QString() ) : mUuid( uuid ) , mName( name ) , mDescription( description ) , mAuthor( author ) , mIcon( icon ) + , mVersion( version ) , mPath( path ) {} ~PluginInformation() = default; @@ -46,6 +48,7 @@ class PluginInformation QString description() const { return mDescription; } QString author() const { return mAuthor; } QString icon() const { return mIcon; } + QString version() const { return mVersion; } QString path() const { return mPath; } private: @@ -54,6 +57,7 @@ class PluginInformation QString mDescription; QString mAuthor; QString mIcon; + QString mVersion; QString mPath; }; diff --git a/src/qml/PluginManagerSettings.qml b/src/qml/PluginManagerSettings.qml index a622285d69..3400608e1c 100644 --- a/src/qml/PluginManagerSettings.qml +++ b/src/qml/PluginManagerSettings.qml @@ -131,7 +131,7 @@ Popup { Label { Layout.fillWidth: true - text: qsTr('Authored by %1').arg(Author) + text: qsTr('Authored by %1').arg(Author) + (Version != "" ? ' (' + Version + ')' : '') font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap @@ -147,7 +147,7 @@ Popup { Label { Layout.fillWidth: true - text: "" + qsTr("Uninstall") + "" + text: "" + qsTr("Uninstall this plugin") + "" font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap @@ -319,7 +319,7 @@ Popup { pluginsList.model.clear() for (const plugin of pluginManager.availableAppPlugins) { - pluginsList.model.append({"Uuid":plugin.uuid, "Enabled":pluginManager.isAppPluginEnabled(plugin.uuid), "Name":plugin.name, "Description":plugin.description, "Author":plugin.author, "Icon": plugin.icon}) + pluginsList.model.append({"Uuid":plugin.uuid, "Enabled":pluginManager.isAppPluginEnabled(plugin.uuid), "Name":plugin.name, "Description":plugin.description, "Author":plugin.author, "Icon": plugin.icon, "Version": plugin.version}) } } From f8886b48c5905df80a88d0f3ba9b5a6cc3c7fca5 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 23 Apr 2024 10:38:46 +0700 Subject: [PATCH 3/3] Add plugin/author homepage metadata --- src/core/pluginmanager.cpp | 13 ++++++++++++- src/core/pluginmanager.h | 6 +++++- src/qml/PluginManagerSettings.qml | 7 +++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/core/pluginmanager.cpp b/src/core/pluginmanager.cpp index 14baf1c40c..b68a122a9a 100644 --- a/src/core/pluginmanager.cpp +++ b/src/core/pluginmanager.cpp @@ -228,6 +228,7 @@ void PluginManager::refreshAppPlugins() QString name = candidate.fileName(); QString description; QString author; + QString homepage; QString icon; QString version; @@ -238,13 +239,23 @@ void PluginManager::refreshAppPlugins() name = metadata.value( "name", candidate.fileName() ).toString(); description = metadata.value( "description" ).toString(); author = metadata.value( "author" ).toString(); + homepage = metadata.value( "homepage" ).toString(); + if ( !homepage.isEmpty() ) + { + // Only tolerate http(s) URLs + const QUrl url( homepage ); + if ( !url.scheme().startsWith( QStringLiteral( "http" ) ) ) + { + homepage.clear(); + } + } if ( !metadata.value( "icon" ).toString().isEmpty() ) { icon = QStringLiteral( "%1/%2" ).arg( candidate.absoluteFilePath(), metadata.value( "icon" ).toString() ); } version = metadata.value( "version" ).toString(); } - mAvailableAppPlugins.insert( candidate.fileName(), PluginInformation( candidate.fileName(), name, description, author, icon, version, path ) ); + mAvailableAppPlugins.insert( candidate.fileName(), PluginInformation( candidate.fileName(), name, description, author, homepage, icon, version, path ) ); } } } diff --git a/src/core/pluginmanager.h b/src/core/pluginmanager.h index 06c9053195..7be7e30b0d 100644 --- a/src/core/pluginmanager.h +++ b/src/core/pluginmanager.h @@ -28,15 +28,17 @@ class PluginInformation Q_PROPERTY( QString name READ name ) Q_PROPERTY( QString description READ description ) Q_PROPERTY( QString author READ author ) + Q_PROPERTY( QString homepage READ homepage ) Q_PROPERTY( QString icon READ icon ) Q_PROPERTY( QString version READ version ) public: - PluginInformation( const QString &uuid = QString(), const QString &name = QString(), const QString &description = QString(), const QString &author = QString(), const QString &icon = QString(), const QString &version = QString(), const QString &path = QString() ) + PluginInformation( const QString &uuid = QString(), const QString &name = QString(), const QString &description = QString(), const QString &author = QString(), const QString &homepage = QString(), const QString &icon = QString(), const QString &version = QString(), const QString &path = QString() ) : mUuid( uuid ) , mName( name ) , mDescription( description ) , mAuthor( author ) + , mHomepage( homepage ) , mIcon( icon ) , mVersion( version ) , mPath( path ) @@ -47,6 +49,7 @@ class PluginInformation QString name() const { return mName; } QString description() const { return mDescription; } QString author() const { return mAuthor; } + QString homepage() const { return mHomepage; } QString icon() const { return mIcon; } QString version() const { return mVersion; } QString path() const { return mPath; } @@ -56,6 +59,7 @@ class PluginInformation QString mName; QString mDescription; QString mAuthor; + QString mHomepage; QString mIcon; QString mVersion; QString mPath; diff --git a/src/qml/PluginManagerSettings.qml b/src/qml/PluginManagerSettings.qml index 3400608e1c..ba86826b3e 100644 --- a/src/qml/PluginManagerSettings.qml +++ b/src/qml/PluginManagerSettings.qml @@ -131,10 +131,13 @@ Popup { Label { Layout.fillWidth: true - text: qsTr('Authored by %1').arg(Author) + (Version != "" ? ' (' + Version + ')' : '') + text: (Homepage != '' + ? qsTr('Authored by %1%2%3').arg('').arg(Author).arg('') + : qsTr('Authored by %1').arg(Author)) + (Version != "" ? ' (' + Version + ')' : '') font: Theme.tipFont color: Theme.secondaryTextColor wrapMode: Text.WordWrap + onLinkActivated: Qt.openUrlExternally(link) } Label { @@ -319,7 +322,7 @@ Popup { pluginsList.model.clear() for (const plugin of pluginManager.availableAppPlugins) { - pluginsList.model.append({"Uuid":plugin.uuid, "Enabled":pluginManager.isAppPluginEnabled(plugin.uuid), "Name":plugin.name, "Description":plugin.description, "Author":plugin.author, "Icon": plugin.icon, "Version": plugin.version}) + pluginsList.model.append({"Uuid":plugin.uuid, "Enabled":pluginManager.isAppPluginEnabled(plugin.uuid), "Name":plugin.name, "Description":plugin.description, "Author":plugin.author, "Homepage":plugin.homepage, "Icon": plugin.icon, "Version": plugin.version}) } }