Falkon Develop
Cross-platform Qt-based web browser
pluginsmanager.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
18#include "pluginsmanager.h"
19#include "ui_pluginslist.h"
20#include "pluginproxy.h"
21#include "mainapplication.h"
22#include "plugininterface.h"
23#include "pluginlistdelegate.h"
24#include "qztools.h"
25#include "settings.h"
26#include "iconprovider.h"
27#include "../config.h"
28
29#include <QInputDialog>
30#include <QMessageBox>
31#include <QTimer>
32
34 : QWidget(parent)
35 , ui(new Ui::PluginsList)
36 , m_loaded(false)
37{
38 ui->setupUi(this);
39 ui->list->setLayoutDirection(Qt::LeftToRight);
40 ui->butSettings->setIcon(IconProvider::settingsIcon());
41 ui->butRemove->setIcon(QIcon::fromTheme(QSL("edit-delete")));
42
43 //Application Extensions
44 Settings settings;
45 settings.beginGroup(QSL("Plugin-Settings"));
46 bool appPluginsEnabled = settings.value(QSL("EnablePlugins"), true).toBool();
47 settings.endGroup();
48
49 ui->list->setEnabled(appPluginsEnabled);
50
51 connect(ui->butSettings, &QAbstractButton::clicked, this, &PluginsManager::settingsClicked);
52 connect(ui->butRemove, &QAbstractButton::clicked, this, &PluginsManager::removeClicked);
53 connect(ui->list, &QListWidget::currentItemChanged, this, &PluginsManager::currentChanged);
54 connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
55 connect(ui->search, &QLineEdit::textChanged, this, &PluginsManager::addFilter);
56 connect(mApp->plugins(), &Plugins::availablePluginsChanged, this, &PluginsManager::refresh);
57
58 ui->list->setItemDelegate(new PluginListDelegate(ui->list));
59}
60
62{
63 if (!m_loaded) {
64 refresh();
65 m_loaded = true;
66 }
67}
68
70{
71 if (!m_loaded) {
72 return;
73 }
74
75 QStringList allowedPlugins;
76 for (int i = 0; i < ui->list->count(); i++) {
77 QListWidgetItem* item = ui->list->item(i);
78
79 if (item->checkState() == Qt::Checked) {
80 const Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
81 allowedPlugins.append(plugin.pluginId);
82 }
83 }
84
85 Settings settings;
86 settings.beginGroup(QSL("Plugin-Settings"));
87 settings.setValue(QSL("AllowedPlugins"), allowedPlugins);
88 settings.endGroup();
89}
90
91void PluginsManager::refresh()
92{
93 if (m_blockRefresh) {
94 return;
95 }
96
97 const int oldCurrentRow = ui->list->currentRow();
98
99 ui->list->clear();
100 ui->butSettings->setEnabled(false);
101 disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
102
103 const QList<Plugins::Plugin> &allPlugins = mApp->plugins()->availablePlugins();
104
105 for (const Plugins::Plugin &plugin : allPlugins) {
106 PluginSpec spec = plugin.pluginSpec;
107
108 auto* item = new QListWidgetItem(ui->list);
109 QIcon icon = QIcon(spec.icon);
110 if (icon.isNull()) {
111 icon = QIcon(QSL(":/icons/preferences/extensions.svg"));
112 }
113 item->setIcon(icon);
114
115 const QString pluginInfo = QStringLiteral("<b>%1</b> %2<br/><i>%3</i><br/>").arg(spec.name, spec.version, spec.author.toHtmlEscaped());
116 item->setToolTip(pluginInfo);
117
118 item->setText(spec.name);
119 item->setData(Qt::UserRole, spec.version);
120 item->setData(Qt::UserRole + 1, spec.author);
121 item->setData(Qt::UserRole + 2, spec.description);
122
123 item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
124 item->setCheckState(plugin.isLoaded() ? Qt::Checked : Qt::Unchecked);
125 item->setData(Qt::UserRole + 10, QVariant::fromValue(plugin));
126
127 ui->list->addItem(item);
128 }
129
130 sortItems();
131
132 if (oldCurrentRow >= 0) {
133 ui->list->setCurrentRow(qMax(0, oldCurrentRow - 1));
134 ui->list->setFocus();
135 }
136
137 connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
138}
139
140void PluginsManager::sortItems()
141{
142 ui->list->sortItems();
143
144 bool itemMoved;
145 do {
146 itemMoved = false;
147 for (int i = 0; i < ui->list->count(); ++i) {
148 QListWidgetItem* topItem = ui->list->item(i);
149 QListWidgetItem* bottomItem = ui->list->item(i + 1);
150 if (!topItem || !bottomItem) {
151 continue;
152 }
153
154 if (topItem->checkState() == Qt::Unchecked && bottomItem->checkState() == Qt::Checked) {
155 QListWidgetItem* item = ui->list->takeItem(i + 1);
156 ui->list->insertItem(i, item);
157 itemMoved = true;
158 }
159 }
160 }
161 while (itemMoved);
162}
163
164void PluginsManager::currentChanged(QListWidgetItem* item)
165{
166 if (!item) {
167 return;
168 }
169
170 const Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
171 ui->butSettings->setEnabled(plugin.isLoaded() && plugin.pluginSpec.hasSettings);
172 ui->butRemove->setEnabled(plugin.isRemovable());
173}
174
175void PluginsManager::itemChanged(QListWidgetItem* item)
176{
177 if (!item) {
178 return;
179 }
180
181 Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
182
183 m_blockRefresh = true;
184
185 if (item->checkState() == Qt::Checked) {
186 mApp->plugins()->loadPlugin(&plugin);
187 }
188 else {
189 mApp->plugins()->unloadPlugin(&plugin);
190 }
191
192 m_blockRefresh = false;
193
194 disconnect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
195
196 if (item->checkState() == Qt::Checked && !plugin.isLoaded()) {
197 item->setCheckState(Qt::Unchecked);
198 QMessageBox::critical(this, tr("Error!"), tr("Cannot load extension!"));
199 }
200
201 item->setData(Qt::UserRole + 10, QVariant::fromValue(plugin));
202
203 connect(ui->list, &QListWidget::itemChanged, this, &PluginsManager::itemChanged);
204
205 currentChanged(ui->list->currentItem());
206}
207
208void PluginsManager::settingsClicked()
209{
210 QListWidgetItem* item = ui->list->currentItem();
211 if (!item || item->checkState() == Qt::Unchecked) {
212 return;
213 }
214
215 Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
216
217 if (!plugin.isLoaded()) {
218 mApp->plugins()->loadPlugin(&plugin);
219
220 item->setData(Qt::UserRole + 10, QVariant::fromValue(plugin));
221 }
222
223 if (plugin.isLoaded() && plugin.pluginSpec.hasSettings) {
224 plugin.instance->showSettings(this);
225 }
226}
227
228void PluginsManager::removeClicked()
229{
230 QListWidgetItem* item = ui->list->currentItem();
231 if (!item) {
232 return;
233 }
234
235 Plugins::Plugin plugin = item->data(Qt::UserRole + 10).value<Plugins::Plugin>();
236
237 const auto button = QMessageBox::warning(this, tr("Confirmation"),
238 tr("Are you sure you want to remove '%1'?").arg(plugin.pluginSpec.name),
239 QMessageBox::Yes | QMessageBox::No);
240 if (button != QMessageBox::Yes) {
241 return;
242 }
243
244 mApp->plugins()->removePlugin(&plugin);
245}
246
247void PluginsManager::addFilter(const QString& filter) {
248 for (int i = 0; i < ui->list->count(); ++i) {
249 const QString& pluginName = ui->list->item(i)->text();
250
251 if (pluginName.contains(filter,Qt::CaseInsensitive) || !filter.size()) {
252 ui->list->item(i)->setHidden(false);
253 }
254 else {
255 ui->list->item(i)->setHidden(true);
256 }
257 }
258}
259
261{
262 delete ui;
263}
static QIcon settingsIcon()
virtual void showSettings(QWidget *parent=nullptr)
void availablePluginsChanged()
PluginsManager(QWidget *parent=nullptr)
void beginGroup(const QString &prefix)
Definition: settings.cpp:79
void endGroup()
Definition: settings.cpp:84
QVariant value(const QString &key, const QVariant &defaultValue=QVariant())
Definition: settings.cpp:74
void setValue(const QString &key, const QVariant &defaultValue=QVariant())
Definition: settings.cpp:69
#define mApp
i
Definition: i18n.py:23
#define QSL(x)
Definition: qzcommon.h:40
bool hasSettings
Definition: plugins.h:40
QString version
Definition: plugins.h:38
QString name
Definition: plugins.h:35
QPixmap icon
Definition: plugins.h:39
QString description
Definition: plugins.h:36
QString author
Definition: plugins.h:37
QVariant data
Definition: plugins.h:75
bool isLoaded() const
Definition: plugins.cpp:38
QString pluginId
Definition: plugins.h:63
PluginSpec pluginSpec
Definition: plugins.h:65
PluginInterface * instance
Definition: plugins.h:66
bool isRemovable() const
Definition: plugins.cpp:43