5#include <QLoggingCategory>
13#include <QStandardItemModel>
14#include <QWebEngineProfile>
15#include <QJsonDocument>
21#include <QCryptographicHash>
22#include <QDesktopServices>
27#include "FrmExtensionManager.h"
28#include "ParameterWebBrowser.h"
29#include "ui_FrmExtensionManager.h"
31static Q_LOGGING_CATEGORY(log,
"WebBrowser.ExtensionManager")
34 QWebEngineProfile *profile, QWidget *parent)
38 , m_pModelExtensions(
nullptr)
41 , m_pUninstall(
nullptr)
44 , m_pCopyPath(
nullptr)
45 , m_pOpenFolder(
nullptr)
47 qDebug(log) << Q_FUNC_INFO;
50 setWindowTitle(tr(
"Chrome Extension Manager"));
51 setWindowIcon(QIcon::fromTheme(
"extension"));
59CFrmExtensionManager::~CFrmExtensionManager()
61 qDebug(log) << Q_FUNC_INFO;
65void CFrmExtensionManager::InitializeUI()
67 QToolBar* pToolBar = ui->toolBar;
68 m_pInstall = pToolBar->addAction(
69 QIcon::fromTheme(
"system-software-install"), tr(
"Install Extension"),
70 this, &CFrmExtensionManager::on_pbInstall_clicked);
71 m_pLoad = pToolBar->addAction(
72 QIcon::fromTheme(
"system-software-update"), tr(
"Load Extension"),
73 this, &CFrmExtensionManager::on_pbLoad_clicked);
74 m_pUninstall = pToolBar->addAction(
75 QIcon::fromTheme(
"edit-delete"), tr(
"Uninstall"),
76 this, &CFrmExtensionManager::on_pbUninstall_clicked);
77 m_pRefresh = pToolBar->addAction(QIcon::fromTheme(
"view-refresh"), tr(
"Refresh"),
78 this, &CFrmExtensionManager::on_pbRefresh_clicked);
79 m_pCopyUrl = pToolBar->addAction(QIcon::fromTheme(
"edit-copy"), tr(
"Copy popup url to clipboard"),
80 this, &CFrmExtensionManager::slotCopyPopupUrl);
81 m_pCopyPath = pToolBar->addAction(QIcon::fromTheme(
"edit-copy"), tr(
"Copy path to clipboard"),
82 this, &CFrmExtensionManager::slotCopyPath);
83 m_pDetails = pToolBar->addAction(QIcon::fromTheme(
"dialog-information"), tr(
"Details"),
84 this, &CFrmExtensionManager::on_pbDetails_clicked);
85 m_pOpenFolder = pToolBar->addAction(QIcon::fromTheme(
"folder-open"), tr(
"Open Folder"),
86 this, &CFrmExtensionManager::on_pbOpenExtensionPath_clicked);
89 m_pModelExtensions =
new QStandardItemModel(
this);
93 headers << tr(
"Name") << tr(
"Enabled") << tr(
"Description")
94 << tr(
"Popup url") << tr(
"ID") << tr(
"Path");
95 m_pModelExtensions->setHorizontalHeaderLabels(headers);
98 ui->tvExtensions->setModel(m_pModelExtensions);
99 ui->tvExtensions->setSelectionMode(QAbstractItemView::SingleSelection);
100 ui->tvExtensions->setSelectionBehavior(QAbstractItemView::SelectRows);
101 ui->tvExtensions->setEditTriggers(QAbstractItemView::NoEditTriggers);
102 ui->tvExtensions->setContextMenuPolicy(Qt::CustomContextMenu);
103 ui->tvExtensions->setAlternatingRowColors(
true);
106 ui->tvExtensions->horizontalHeader()->setStretchLastSection(
true);
107 ui->tvExtensions->verticalHeader()->setDefaultSectionSize(24);
109 slotSelectionChanged();
110 qDebug(log) <<
"UI initialized";
113void CFrmExtensionManager::SetupConnections()
117 check = connect(m_pModelExtensions, &QStandardItemModel::itemChanged,
118 this, &CFrmExtensionManager::slotExtensionItemChanged);
120 check = connect(ui->tvExtensions->selectionModel(), &QItemSelectionModel::selectionChanged,
121 this, &CFrmExtensionManager::slotSelectionChanged);
123 check = connect(ui->tvExtensions, &QTableView::customContextMenuRequested,
124 this, &CFrmExtensionManager::slotCustomContextMenu);
130 m_pProfile = profile;
132 qWarning(log) <<
"Failed to set profile: profile is null";
137 auto m = m_pProfile->extensionManager();
139 check = connect(m, &QWebEngineExtensionManager::installFinished,
140 this, &CFrmExtensionManager::slotInstallFinished);
142 check = connect(m, &QWebEngineExtensionManager::uninstallFinished,
143 this, &CFrmExtensionManager::slotUninstallFinished);
145 check = connect(m, &QWebEngineExtensionManager::loadFinished,
146 this, &CFrmExtensionManager::slotLoadFinished);
148 check = connect(m, &QWebEngineExtensionManager::unloadFinished,
149 this, &CFrmExtensionManager::slotUnloadFinished);
152 RefreshExtensionList();
161 if(!m_pProfile || !m_pProfile->extensionManager()) {
162 qWarning(log) <<
"Profile is not set";
168 qCritical(log) <<
"The path is not exist" << path;
172 auto m = m_pProfile->extensionManager();
174 m->installExtension(path);
176 m->loadExtension(path);
182 if(!m_pProfile || !m_pProfile->extensionManager()) {
183 qWarning(log) <<
"Profile is not set";
187 auto m = m_pProfile->extensionManager();
188 foreach (
auto e, m->extensions()) {
190 m->uninstallExtension(e);
198 qDebug(log) << Q_FUNC_INFO <<
"ID:" << id;
199 if(
id.isEmpty())
return;
200 if(!m_pProfile || !m_pProfile->extensionManager()) {
201 qWarning(log) <<
"Profile is not set";
205 auto m = m_pProfile->extensionManager();
206 foreach (
auto e, m->extensions()) {
207 if(e.id() ==
id && e.isEnabled() != bEnable)
208 m->setExtensionEnabled(e, bEnable);
214 if(!m_pProfile || !m_pProfile->extensionManager()) {
215 qWarning(log) <<
"Profile is not set";
216 return QList<QWebEngineExtensionInfo>();
219 auto m = m_pProfile->extensionManager();
220 return m->extensions();
225 if(!m_pProfile || !m_pProfile->extensionManager()) {
226 qWarning(log) <<
"Profile is not set";
227 return QWebEngineExtensionInfo();
230 auto m = m_pProfile->extensionManager();
231 foreach(
auto e, m->extensions()) {
235 return QWebEngineExtensionInfo();
238int CFrmExtensionManager::RefreshExtensionList()
240 if(!m_pModelExtensions || !m_pProfile || !m_pProfile->extensionManager())
243 m_pModelExtensions->removeRows(0, m_pModelExtensions->rowCount());
245 qDebug(log) <<
"Refreshing extension list";
247 auto extensions = m_pProfile->extensionManager()->extensions();
248 foreach(
auto e, extensions) {
252 qDebug(log) <<
"Extension list refreshed, total:" << m_pModelExtensions->rowCount();
256int CFrmExtensionManager::AddExtensionItem(
const QWebEngineExtensionInfo &info)
258 if(!m_pModelExtensions)
return -1;
260 int row = m_pModelExtensions->rowCount();
261 m_pModelExtensions->insertRow(row);
263 auto itemId =
new QStandardItem(info.id());
264 itemId->setEditable(
false);
265 m_pModelExtensions->setItem(row, ColumnNo::ID, itemId);
267 auto itemName =
new QStandardItem(info.name());
268 itemName->setEditable(
false);
269 m_pModelExtensions->setItem(row, ColumnNo::Name, itemName);
271 auto itemEnabled =
new QStandardItem();
272 itemEnabled->setEditable(
false);
273 itemEnabled->setCheckable(
true);
274 itemEnabled->setCheckState(info.isEnabled() ? Qt::Checked : Qt::Unchecked);
275 m_pModelExtensions->setItem(row, ColumnNo::Enabled, itemEnabled);
277 auto itemPath =
new QStandardItem(info.path());
278 itemPath->setEditable(
false);
279 m_pModelExtensions->setItem(row, ColumnNo::Path, itemPath);
281 auto itemPopupUrl =
new QStandardItem(info.actionPopupUrl().toString());
282 itemPopupUrl->setEditable(
false);
283 m_pModelExtensions->setItem(row, ColumnNo::PopupUrl, itemPopupUrl);
285 auto itemDesc =
new QStandardItem(info.description());
286 itemDesc->setEditable(
false);
287 m_pModelExtensions->setItem(row, ColumnNo::Description, itemDesc);
289 qDebug(log) <<
"Added extension:" << info.name();
293int CFrmExtensionManager::RemoveExtensionItem(
const QString &extensionId)
295 for(
int i = 0; i < m_pModelExtensions->rowCount(); i++) {
296 auto item = m_pModelExtensions->item(i, ColumnNo::ID);
297 if(item && item->text() == extensionId) {
298 m_pModelExtensions->removeRow(i);
305void CFrmExtensionManager::on_pbInstall_clicked()
307 QString filter = tr(
"Chrome Extension (*.crx);;All Files (*)");
308 QString path = QFileDialog::getOpenFileName(
309 this, tr(
"Install Chrome Extension"),
"", filter);
311 if(!path.isEmpty()) {
316void CFrmExtensionManager::on_pbLoad_clicked()
318 QString path = QFileDialog::getExistingDirectory(
319 this, tr(
"Load Chrome Extension"));
320 if(!path.isEmpty()) {
325void CFrmExtensionManager::on_pbUninstall_clicked()
327 qDebug(log) << Q_FUNC_INFO;
329 auto indexes = ui->tvExtensions->selectionModel()->selectedRows();
330 if(indexes.isEmpty()) {
331 QMessageBox::warning(
this, tr(
"Warning"),
332 tr(
"Please select an extension to uninstall"));
336 int row = indexes.at(0).row();
337 auto idItem = m_pModelExtensions->item(row, ColumnNo::ID);
338 auto nameItem = m_pModelExtensions->item(row, ColumnNo::Name);
340 if(!idItem || !nameItem)
return;
342 int ret = QMessageBox::question(
this, tr(
"Confirm"),
343 tr(
"Do you want to uninstall '%1'?").arg(nameItem->text()),
344 QMessageBox::Yes | QMessageBox::No);
346 if(ret == QMessageBox::Yes) {
351void CFrmExtensionManager::on_pbRefresh_clicked()
353 qDebug(log) << Q_FUNC_INFO;
354 RefreshExtensionList();
357void CFrmExtensionManager::on_pbDetails_clicked()
359 qDebug(log) << Q_FUNC_INFO;
361 auto indexes = ui->tvExtensions->selectionModel()->selectedRows();
362 if(indexes.isEmpty())
return;
364 int row = indexes.at(0).row();
365 auto idItem = m_pModelExtensions->item(row, ColumnNo::ID);
370 QString details = tr(
"Extension Details:") +
"\n";
371 details +=
" - " + tr(
"Name:") +
" " + info.name() +
"\n";
372 details +=
" - " + tr(
"Description:") +
" " + info.description() +
"\n";
373 details +=
" - " + tr(
"Enable:") +
" " + (info.isEnabled() ? tr(
"TRUE") : tr(
"FALSE")) +
"\n";
374 details +=
" - " + tr(
"ID:") +
" " + info.id() +
"\n";
375 details +=
" - " + tr(
"Popup url:") +
" " + info.actionPopupUrl().toString() +
"\n";
376 details +=
" - " + tr(
"Path:") +
" " + info.path() +
"\n";
378 QMessageBox::information(
this, tr(
"Extension Details"), details);
381void CFrmExtensionManager::on_pbOpenDevTools_clicked()
383 qDebug(log) << Q_FUNC_INFO;
385 QMessageBox::information(
this, tr(
"Info"),
386 tr(
"Developer tools for extensions not yet implemented"));
389void CFrmExtensionManager::on_pbOpenExtensionPath_clicked()
391 qDebug(log) << Q_FUNC_INFO;
393 auto indexes = ui->tvExtensions->selectionModel()->selectedRows();
394 if(indexes.isEmpty())
return;
396 int row = indexes.at(0).row();
397 auto pathItem = m_pModelExtensions->item(row, ColumnNo::Path);
398 if(pathItem && !pathItem->text().isEmpty()) {
399 QDesktopServices::openUrl(QUrl::fromLocalFile(pathItem->text()));
403void CFrmExtensionManager::slotExtensionItemChanged(QStandardItem *item)
407 if(!item->index().isValid())
return;
408 if(item->index().column() == ColumnNo::Enabled) {
409 auto idItem = m_pModelExtensions->item(item->index().row(), ColumnNo::ID);
416void CFrmExtensionManager::slotSelectionChanged()
418 auto indexes = ui->tvExtensions->selectionModel()->selectedRows();
419 bool hasSelection = !indexes.isEmpty();
421 m_pUninstall->setEnabled(hasSelection);
422 m_pCopyUrl->setEnabled(hasSelection);
423 m_pDetails->setEnabled(hasSelection);
424 m_pOpenFolder->setEnabled(hasSelection);
427void CFrmExtensionManager::slotCustomContextMenu(
const QPoint &pos)
429 qDebug(log) << Q_FUNC_INFO;
431 auto indexes = ui->tvExtensions->selectionModel()->selectedRows();
432 if(!indexes.isEmpty()) {
433 m.addAction(m_pCopyUrl);
434 m.addAction(m_pCopyPath);
435 m.addAction(m_pDetails);
436 m.addAction(m_pOpenFolder);
438 m.addAction(m_pUninstall);
440 m.addAction(m_pInstall);
441 m.addAction(m_pLoad);
442 m.addAction(m_pRefresh);
443 auto pw = qobject_cast<QWidget*>(sender());
445 m.exec(pw->mapToGlobal(pos));
448void CFrmExtensionManager::slotInstallFinished(
const QWebEngineExtensionInfo &extension)
450 if(extension.isInstalled()) {
451 QMessageBox::information(
452 this, tr(
"Successful"),
453 tr(
"Successfully installed extension") +
" \"" + extension.name() +
"\"\n\n"
454 + tr(
"Path:") +
" " + extension.path());
455 AddExtensionItem(extension);
457 QMessageBox::critical(
459 tr(
"Failed to install extension.") +
"\n\n"
460 + tr(
"Path:") +
" " + extension.path() +
"\n\n"
461 + tr(
"Error:") +
" " + extension.error());
464void CFrmExtensionManager::slotUninstallFinished(
const QWebEngineExtensionInfo &extension)
466 if(!extension.isInstalled()) {
467 QMessageBox::information(
this, tr(
"Successful"),
468 tr(
"Successfully uninstalled extension") +
" \"" + extension.name() +
"\"");
469 RemoveExtensionItem(extension.id());
471 QMessageBox::critical(
473 tr(
"Failed to uninstall extension.") +
"\n\n"
474 + tr(
"Path:") +
" " + extension.path() +
"\n\n"
475 + tr(
"Error:") +
" " + extension.error());
478void CFrmExtensionManager::slotLoadFinished(
const QWebEngineExtensionInfo &extension)
480 if(extension.isLoaded()) {
481 QMessageBox::information(
482 this, tr(
"Successful"),
483 tr(
"Successfully loaded extension") +
" \"" + extension.name() +
"\"\n\n"
484 + tr(
"Path:") +
" " + extension.path());
485 AddExtensionItem(extension);
487 QMessageBox::critical(
489 tr(
"Failed to load extension.") +
"\n\n"
490 + tr(
"Path:") +
" " + extension.path() +
"\n\n"
491 + tr(
"Error:") +
" " + extension.error());
494void CFrmExtensionManager::slotUnloadFinished(
const QWebEngineExtensionInfo &extension)
496 if(!extension.isLoaded()) {
497 QMessageBox::information(
this, tr(
"Successful"),
498 tr(
"Successfully unloaded extension") +
" \"" + extension.name() +
"\"");
499 RemoveExtensionItem(extension.id());
501 QMessageBox::critical(
503 tr(
"Failed to unload extension.") +
"\n\n"
504 + tr(
"Path:") +
" " + extension.path() +
"\n\n"
505 + tr(
"Error:") +
" " + extension.error());
508void CFrmExtensionManager::slotCopyPopupUrl()
510 if(!m_pModelExtensions)
return;
511 auto indexes = ui->tvExtensions->selectionModel()->selectedRows();
512 if(indexes.isEmpty())
return;
514 int row = indexes.at(0).row();
515 auto item = m_pModelExtensions->item(row, ColumnNo::PopupUrl);
517 QClipboard* clipboard = QApplication::clipboard();
518 if(clipboard && item && !item->text().isEmpty()) {
519 clipboard->setText(item->text());
523void CFrmExtensionManager::slotCopyPath()
525 if(!m_pModelExtensions)
return;
526 auto indexes = ui->tvExtensions->selectionModel()->selectedRows();
527 if(indexes.isEmpty())
return;
529 int row = indexes.at(0).row();
530 auto item = m_pModelExtensions->item(row, ColumnNo::Path);
532 QClipboard* clipboard = QApplication::clipboard();
533 if(clipboard && item && !item->text().isEmpty()) {
534 clipboard->setText(item->text());
void EnableExtension(const QString &id, bool bEnable)
启用扩展
QWebEngineExtensionInfo GetExtensionInfo(const QString &id) const
获取扩展详细信息
void UninstallExtension(const QString &id)
卸载扩展
QList< QWebEngineExtensionInfo > GetInstalledExtensions() const
获取已安装的扩展列表
void InstallExtension(const QString &path)
安装或加载 Chrome 扩展
int SetProfile(QWebEngineProfile *profile)
设置 WebEngine Profile