1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 18:56:34 +01:00

Plugins: Implement removing locally installed plugins

This commit is contained in:
David Rosca 2019-04-18 11:28:10 +02:00
parent a3e320fb47
commit 7a562a4847
No known key found for this signature in database
GPG Key ID: EBC3FC294452C6D8
8 changed files with 91 additions and 33 deletions

View File

@ -356,7 +356,7 @@ QString FalkonSchemeReply::configPage()
page.replace(QLatin1String("%USER-AGENT%"), mApp->webProfile()->httpUserAgent()); page.replace(QLatin1String("%USER-AGENT%"), mApp->webProfile()->httpUserAgent());
QString pluginsString; QString pluginsString;
const QList<Plugins::Plugin> &availablePlugins = mApp->plugins()->getAvailablePlugins(); const QList<Plugins::Plugin> &availablePlugins = mApp->plugins()->availablePlugins();
foreach (const Plugins::Plugin &plugin, availablePlugins) { foreach (const Plugins::Plugin &plugin, availablePlugins) {
PluginSpec spec = plugin.pluginSpec; PluginSpec spec = plugin.pluginSpec;

View File

@ -28,10 +28,28 @@
#include "qml/qmlplugin.h" #include "qml/qmlplugin.h"
#include <iostream> #include <iostream>
#include <QPluginLoader> #include <QPluginLoader>
#include <QDir> #include <QDir>
#include <QQmlEngine> #include <QQmlEngine>
#include <QQmlComponent> #include <QQmlComponent>
#include <QFileInfo>
bool Plugins::Plugin::isLoaded() const
{
return instance;
}
bool Plugins::Plugin::isRemovable() const
{
return !pluginPath.isEmpty() && QFileInfo(pluginPath).isWritable();
}
bool Plugins::Plugin::operator==(const Plugin &other) const
{
return type == other.type &&
pluginId == other.pluginId;
}
Plugins::Plugins(QObject* parent) Plugins::Plugins(QObject* parent)
: QObject(parent) : QObject(parent)
@ -45,10 +63,9 @@ Plugins::Plugins(QObject* parent)
} }
} }
QList<Plugins::Plugin> Plugins::getAvailablePlugins() QList<Plugins::Plugin> Plugins::availablePlugins()
{ {
loadAvailablePlugins(); loadAvailablePlugins();
return m_availablePlugins; return m_availablePlugins;
} }
@ -88,24 +105,30 @@ void Plugins::unloadPlugin(Plugins::Plugin* plugin)
void Plugins::removePlugin(Plugins::Plugin *plugin) void Plugins::removePlugin(Plugins::Plugin *plugin)
{ {
if (plugin->type != Plugin::QmlPlugin) { if (!plugin->isRemovable()) {
return; return;
} }
if (plugin->isLoaded()) { if (plugin->isLoaded()) {
unloadPlugin(plugin); unloadPlugin(plugin);
} }
// For QML plugins, pluginId is qml:<plugin-dir-name> bool result = false;
const QString dirName = plugin->pluginId.mid(4);
const QString dirPath = DataPaths::locate(DataPaths::Plugins, QSL("qml/") + dirName); QFileInfo info(plugin->pluginPath);
bool result = QDir(dirPath).removeRecursively(); if (info.isDir()) {
result = QDir(plugin->pluginPath).removeRecursively();
} else if (info.isFile()) {
result = QFile::remove(plugin->pluginPath);
}
if (!result) { if (!result) {
qWarning() << "Unable to remove" << plugin->pluginSpec.name; qWarning() << "Failed to remove" << plugin->pluginSpec.name;
return; return;
} }
m_availablePlugins.removeOne(*plugin); m_availablePlugins.removeOne(*plugin);
refreshedLoadedPlugins(); emit availablePluginsChanged();
} }
void Plugins::loadSettings() void Plugins::loadSettings()
@ -233,7 +256,7 @@ void Plugins::loadAvailablePlugins()
// QmlPlugin // QmlPlugin
for (QString dir : dirs) { for (QString dir : dirs) {
// qml plugins will be loaded from subdirectory qml // Qml plugins will be loaded from subdirectory qml
dir.append(QSL("/qml")); dir.append(QSL("/qml"));
const auto qmlDirs = QDir(dir).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); const auto qmlDirs = QDir(dir).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &info : qmlDirs) { for (const QFileInfo &info : qmlDirs) {
@ -267,7 +290,7 @@ void Plugins::refreshLoadedPlugins()
} }
} }
emit refreshedLoadedPlugins(); emit availablePluginsChanged();
} }
void Plugins::loadPythonSupport() void Plugins::loadPythonSupport()
@ -369,7 +392,7 @@ Plugins::Plugin Plugins::loadSharedLibraryPlugin(const QString &name)
Plugin plugin; Plugin plugin;
plugin.type = Plugin::SharedLibraryPlugin; plugin.type = Plugin::SharedLibraryPlugin;
plugin.pluginId = QSL("lib:%1").arg(QFileInfo(fullPath).fileName()); plugin.pluginId = QSL("lib:%1").arg(QFileInfo(fullPath).fileName());
plugin.libraryPath = fullPath; plugin.pluginPath = fullPath;
plugin.pluginLoader = loader; plugin.pluginLoader = loader;
plugin.pluginSpec = createSpec(iPlugin->metaData()); plugin.pluginSpec = createSpec(iPlugin->metaData());
return plugin; return plugin;

View File

@ -60,6 +60,7 @@ public:
}; };
Type type = Invalid; Type type = Invalid;
QString pluginId; QString pluginId;
QString pluginPath;
PluginSpec pluginSpec; PluginSpec pluginSpec;
PluginInterface *instance = nullptr; PluginInterface *instance = nullptr;
@ -67,25 +68,19 @@ public:
PluginInterface *internalInstance = nullptr; PluginInterface *internalInstance = nullptr;
// SharedLibraryPlugin // SharedLibraryPlugin
QString libraryPath;
QPluginLoader *pluginLoader = nullptr; QPluginLoader *pluginLoader = nullptr;
// Other // Other
QVariant data; QVariant data;
bool isLoaded() const { bool isLoaded() const;
return instance; bool isRemovable() const;
} bool operator==(const Plugin &other) const;
bool operator==(const Plugin &other) const {
return this->type == other.type &&
this->pluginId == other.pluginId;
}
}; };
explicit Plugins(QObject* parent = 0); explicit Plugins(QObject* parent = 0);
QList<Plugin> getAvailablePlugins(); QList<Plugin> availablePlugins();
bool loadPlugin(Plugin* plugin); bool loadPlugin(Plugin* plugin);
void unloadPlugin(Plugin* plugin); void unloadPlugin(Plugin* plugin);
@ -108,7 +103,7 @@ protected:
Q_SIGNALS: Q_SIGNALS:
void pluginUnloaded(PluginInterface* plugin); void pluginUnloaded(PluginInterface* plugin);
void refreshedLoadedPlugins(); void availablePluginsChanged();
private: private:
void loadPythonSupport(); void loadPythonSupport();

View File

@ -50,6 +50,7 @@ Plugins::Plugin QmlPlugin::loadPlugin(const QString &name)
Plugins::Plugin plugin; Plugins::Plugin plugin;
plugin.type = Plugins::Plugin::QmlPlugin; plugin.type = Plugins::Plugin::QmlPlugin;
plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName()); plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName());
plugin.pluginPath = fullPath;
DesktopFile desktopFile(fullPath + QSL("/metadata.desktop")); DesktopFile desktopFile(fullPath + QSL("/metadata.desktop"));
plugin.pluginSpec = Plugins::createSpec(desktopFile); plugin.pluginSpec = Plugins::createSpec(desktopFile);
QString entryPoint = desktopFile.value(QSL("X-Falkon-EntryPoint")).toString(); QString entryPoint = desktopFile.value(QSL("X-Falkon-EntryPoint")).toString();

View File

@ -70,6 +70,16 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QPushButton" name="butRemove">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

View File

@ -38,6 +38,7 @@ PluginsManager::PluginsManager(QWidget* parent)
ui->setupUi(this); ui->setupUi(this);
ui->list->setLayoutDirection(Qt::LeftToRight); ui->list->setLayoutDirection(Qt::LeftToRight);
ui->butSettings->setIcon(IconProvider::settingsIcon()); ui->butSettings->setIcon(IconProvider::settingsIcon());
ui->butRemove->setIcon(QIcon::fromTheme(QSL("edit-delete")));
//Application Extensions //Application Extensions
Settings settings; Settings settings;
@ -48,8 +49,10 @@ PluginsManager::PluginsManager(QWidget* parent)
ui->list->setEnabled(appPluginsEnabled); ui->list->setEnabled(appPluginsEnabled);
connect(ui->butSettings, &QAbstractButton::clicked, this, &PluginsManager::settingsClicked); connect(ui->butSettings, &QAbstractButton::clicked, this, &PluginsManager::settingsClicked);
connect(ui->butRemove, &QAbstractButton::clicked, this, &PluginsManager::removeClicked);
connect(ui->list, &QListWidget::currentItemChanged, this, &PluginsManager::currentChanged); connect(ui->list, &QListWidget::currentItemChanged, this, &PluginsManager::currentChanged);
connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged); connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
connect(mApp->plugins(), &Plugins::availablePluginsChanged, this, &PluginsManager::refresh);
ui->list->setItemDelegate(new PluginListDelegate(ui->list)); ui->list->setItemDelegate(new PluginListDelegate(ui->list));
} }
@ -86,11 +89,17 @@ void PluginsManager::save()
void PluginsManager::refresh() void PluginsManager::refresh()
{ {
if (m_blockRefresh) {
return;
}
const int oldCurrentRow = ui->list->currentRow();
ui->list->clear(); ui->list->clear();
ui->butSettings->setEnabled(false); ui->butSettings->setEnabled(false);
disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged); disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
const QList<Plugins::Plugin> &allPlugins = mApp->plugins()->getAvailablePlugins(); const QList<Plugins::Plugin> &allPlugins = mApp->plugins()->availablePlugins();
foreach (const Plugins::Plugin &plugin, allPlugins) { foreach (const Plugins::Plugin &plugin, allPlugins) {
PluginSpec spec = plugin.pluginSpec; PluginSpec spec = plugin.pluginSpec;
@ -119,6 +128,11 @@ void PluginsManager::refresh()
sortItems(); sortItems();
if (oldCurrentRow >= 0) {
ui->list->setCurrentRow(qMax(0, oldCurrentRow - 1));
ui->list->setFocus();
}
connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged); connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
} }
@ -153,13 +167,8 @@ void PluginsManager::currentChanged(QListWidgetItem* item)
} }
const Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>(); const Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
bool showSettings = plugin.pluginSpec.hasSettings; ui->butSettings->setEnabled(plugin.isLoaded() && plugin.pluginSpec.hasSettings);
ui->butRemove->setEnabled(plugin.isRemovable());
if (!plugin.isLoaded()) {
showSettings = false;
}
ui->butSettings->setEnabled(showSettings);
} }
void PluginsManager::itemChanged(QListWidgetItem* item) void PluginsManager::itemChanged(QListWidgetItem* item)
@ -170,6 +179,8 @@ void PluginsManager::itemChanged(QListWidgetItem* item)
Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>(); Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
m_blockRefresh = true;
if (item->checkState() == Qt::Checked) { if (item->checkState() == Qt::Checked) {
mApp->plugins()->loadPlugin(&plugin); mApp->plugins()->loadPlugin(&plugin);
} }
@ -177,6 +188,8 @@ void PluginsManager::itemChanged(QListWidgetItem* item)
mApp->plugins()->unloadPlugin(&plugin); mApp->plugins()->unloadPlugin(&plugin);
} }
m_blockRefresh = false;
disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged); disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
if (item->checkState() == Qt::Checked && !plugin.isLoaded()) { if (item->checkState() == Qt::Checked && !plugin.isLoaded()) {
@ -188,7 +201,6 @@ void PluginsManager::itemChanged(QListWidgetItem* item)
connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged); connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
currentChanged(ui->list->currentItem()); currentChanged(ui->list->currentItem());
} }
@ -212,6 +224,20 @@ void PluginsManager::settingsClicked()
} }
} }
void PluginsManager::removeClicked()
{
QListWidgetItem* item = ui->list->currentItem();
if (!item) {
return;
}
Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
if (plugin.isRemovable()) {
mApp->plugins()->removePlugin(&plugin);
}
}
PluginsManager::~PluginsManager() PluginsManager::~PluginsManager()
{ {
delete ui; delete ui;

View File

@ -42,6 +42,7 @@ public:
private Q_SLOTS: private Q_SLOTS:
void settingsClicked(); void settingsClicked();
void removeClicked();
void currentChanged(QListWidgetItem* item); void currentChanged(QListWidgetItem* item);
void itemChanged(QListWidgetItem* item); void itemChanged(QListWidgetItem* item);
@ -52,6 +53,7 @@ private:
Ui::PluginsList* ui; Ui::PluginsList* ui;
bool m_loaded; bool m_loaded;
bool m_blockRefresh = false;
}; };
#endif // PLUGINSMANAGER_H #endif // PLUGINSMANAGER_H

View File

@ -107,6 +107,7 @@ Plugins::Plugin pyfalkon_load_plugin(const QString &name)
Plugins::Plugin plugin; Plugins::Plugin plugin;
plugin.type = Plugins::Plugin::PythonPlugin; plugin.type = Plugins::Plugin::PythonPlugin;
plugin.pluginId = QSL("python:%1").arg(QFileInfo(name).fileName()); plugin.pluginId = QSL("python:%1").arg(QFileInfo(name).fileName());
plugin.pluginPath = fullPath;
plugin.pluginSpec = Plugins::createSpec(DesktopFile(fullPath + QSL("/metadata.desktop"))); plugin.pluginSpec = Plugins::createSpec(DesktopFile(fullPath + QSL("/metadata.desktop")));
return plugin; return plugin;
} }