File indexing completed on 2024-05-19 04:59:01

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "pluginsmanager.h"
0019 #include "ui_pluginslist.h"
0020 #include "pluginproxy.h"
0021 #include "mainapplication.h"
0022 #include "plugininterface.h"
0023 #include "pluginlistdelegate.h"
0024 #include "qztools.h"
0025 #include "settings.h"
0026 #include "iconprovider.h"
0027 #include "../config.h"
0028 
0029 #include <QInputDialog>
0030 #include <QMessageBox>
0031 #include <QTimer>
0032 
0033 PluginsManager::PluginsManager(QWidget* parent)
0034     : QWidget(parent)
0035     , ui(new Ui::PluginsList)
0036     , m_loaded(false)
0037 {
0038     ui->setupUi(this);
0039     ui->list->setLayoutDirection(Qt::LeftToRight);
0040     ui->butSettings->setIcon(IconProvider::settingsIcon());
0041     ui->butRemove->setIcon(QIcon::fromTheme(QSL("edit-delete")));
0042 
0043     //Application Extensions
0044     Settings settings;
0045     settings.beginGroup(QSL("Plugin-Settings"));
0046     bool appPluginsEnabled = settings.value(QSL("EnablePlugins"), true).toBool();
0047     settings.endGroup();
0048 
0049     ui->list->setEnabled(appPluginsEnabled);
0050 
0051     connect(ui->butSettings, &QAbstractButton::clicked, this, &PluginsManager::settingsClicked);
0052     connect(ui->butRemove, &QAbstractButton::clicked, this, &PluginsManager::removeClicked);
0053     connect(ui->list, &QListWidget::currentItemChanged, this, &PluginsManager::currentChanged);
0054     connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
0055     connect(ui->search, &QLineEdit::textChanged, this, &PluginsManager::addFilter);
0056     connect(mApp->plugins(), &Plugins::availablePluginsChanged, this, &PluginsManager::refresh);
0057 
0058     ui->list->setItemDelegate(new PluginListDelegate(ui->list));
0059 }
0060 
0061 void PluginsManager::load()
0062 {
0063     if (!m_loaded) {
0064         refresh();
0065         m_loaded = true;
0066     }
0067 }
0068 
0069 void PluginsManager::save()
0070 {
0071     if (!m_loaded) {
0072         return;
0073     }
0074 
0075     QStringList allowedPlugins;
0076     for (int i = 0; i < ui->list->count(); i++) {
0077         QListWidgetItem* item = ui->list->item(i);
0078 
0079         if (item->checkState() == Qt::Checked) {
0080             const Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
0081             allowedPlugins.append(plugin.pluginId);
0082         }
0083     }
0084 
0085     Settings settings;
0086     settings.beginGroup(QSL("Plugin-Settings"));
0087     settings.setValue(QSL("AllowedPlugins"), allowedPlugins);
0088     settings.endGroup();
0089 }
0090 
0091 void PluginsManager::refresh()
0092 {
0093     if (m_blockRefresh) {
0094         return;
0095     }
0096 
0097     const int oldCurrentRow = ui->list->currentRow();
0098 
0099     ui->list->clear();
0100     ui->butSettings->setEnabled(false);
0101     disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
0102 
0103     const QList<Plugins::Plugin> &allPlugins = mApp->plugins()->availablePlugins();
0104 
0105     for (const Plugins::Plugin &plugin : allPlugins) {
0106         PluginSpec spec = plugin.pluginSpec;
0107 
0108         auto* item = new QListWidgetItem(ui->list);
0109         QIcon icon = QIcon(spec.icon);
0110         if (icon.isNull()) {
0111             icon = QIcon(QSL(":/icons/preferences/extensions.svg"));
0112         }
0113         item->setIcon(icon);
0114 
0115         const QString pluginInfo = QStringLiteral("<b>%1</b> %2<br/><i>%3</i><br/>").arg(spec.name, spec.version, spec.author.toHtmlEscaped());
0116         item->setToolTip(pluginInfo);
0117 
0118         item->setText(spec.name);
0119         item->setData(Qt::UserRole, spec.version);
0120         item->setData(Qt::UserRole + 1, spec.author);
0121         item->setData(Qt::UserRole + 2, spec.description);
0122 
0123         item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
0124         item->setCheckState(plugin.isLoaded() ? Qt::Checked : Qt::Unchecked);
0125         item->setData(Qt::UserRole + 10, QVariant::fromValue(plugin));
0126 
0127         ui->list->addItem(item);
0128     }
0129 
0130     sortItems();
0131 
0132     if (oldCurrentRow >= 0) {
0133         ui->list->setCurrentRow(qMax(0, oldCurrentRow - 1));
0134         ui->list->setFocus();
0135     }
0136 
0137     connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
0138 }
0139 
0140 void PluginsManager::sortItems()
0141 {
0142     ui->list->sortItems();
0143 
0144     bool itemMoved;
0145     do {
0146         itemMoved = false;
0147         for (int i = 0; i < ui->list->count(); ++i) {
0148             QListWidgetItem* topItem = ui->list->item(i);
0149             QListWidgetItem* bottomItem = ui->list->item(i + 1);
0150             if (!topItem || !bottomItem) {
0151                 continue;
0152             }
0153 
0154             if (topItem->checkState() == Qt::Unchecked && bottomItem->checkState() == Qt::Checked) {
0155                 QListWidgetItem* item = ui->list->takeItem(i + 1);
0156                 ui->list->insertItem(i, item);
0157                 itemMoved = true;
0158             }
0159         }
0160     }
0161     while (itemMoved);
0162 }
0163 
0164 void PluginsManager::currentChanged(QListWidgetItem* item)
0165 {
0166     if (!item) {
0167         return;
0168     }
0169 
0170     const Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
0171     ui->butSettings->setEnabled(plugin.isLoaded() && plugin.pluginSpec.hasSettings);
0172     ui->butRemove->setEnabled(plugin.isRemovable());
0173 }
0174 
0175 void PluginsManager::itemChanged(QListWidgetItem* item)
0176 {
0177     if (!item) {
0178         return;
0179     }
0180 
0181     Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
0182 
0183     m_blockRefresh = true;
0184 
0185     if (item->checkState() == Qt::Checked) {
0186         mApp->plugins()->loadPlugin(&plugin);
0187     }
0188     else {
0189         mApp->plugins()->unloadPlugin(&plugin);
0190     }
0191 
0192     m_blockRefresh = false;
0193 
0194     disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
0195 
0196     if (item->checkState() == Qt::Checked && !plugin.isLoaded()) {
0197         item->setCheckState(Qt::Unchecked);
0198         QMessageBox::critical(this, tr("Error!"), tr("Cannot load extension!"));
0199     }
0200 
0201     item->setData(Qt::UserRole + 10, QVariant::fromValue(plugin));
0202 
0203     connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
0204 
0205     currentChanged(ui->list->currentItem());
0206 }
0207 
0208 void PluginsManager::settingsClicked()
0209 {
0210     QListWidgetItem* item = ui->list->currentItem();
0211     if (!item || item->checkState() == Qt::Unchecked) {
0212         return;
0213     }
0214 
0215     Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
0216 
0217     if (!plugin.isLoaded()) {
0218         mApp->plugins()->loadPlugin(&plugin);
0219 
0220         item->setData(Qt::UserRole + 10, QVariant::fromValue(plugin));
0221     }
0222 
0223     if (plugin.isLoaded() && plugin.pluginSpec.hasSettings) {
0224         plugin.instance->showSettings(this);
0225     }
0226 }
0227 
0228 void PluginsManager::removeClicked()
0229 {
0230     QListWidgetItem* item = ui->list->currentItem();
0231     if (!item) {
0232         return;
0233     }
0234 
0235     Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
0236 
0237     const auto button = QMessageBox::warning(this, tr("Confirmation"),
0238                                              tr("Are you sure you want to remove '%1'?").arg(plugin.pluginSpec.name),
0239                                              QMessageBox::Yes | QMessageBox::No);
0240     if (button != QMessageBox::Yes) {
0241         return;
0242     }
0243 
0244     mApp->plugins()->removePlugin(&plugin);
0245 }
0246 
0247 void PluginsManager::addFilter(const QString& filter) {
0248     for (int i = 0; i < ui->list->count(); ++i) {
0249         const QString& pluginName = ui->list->item(i)->text();
0250 
0251         if (pluginName.contains(filter,Qt::CaseInsensitive) || !filter.size()) {
0252             ui->list->item(i)->setHidden(false);
0253         }
0254         else {
0255             ui->list->item(i)->setHidden(true);
0256         }
0257     }
0258 }
0259 
0260 PluginsManager::~PluginsManager()
0261 {
0262     delete ui;
0263 }