mirror of
https://invent.kde.org/network/falkon.git
synced 2024-12-20 02:36:34 +01:00
Created falkon:extensions page
This commit is contained in:
parent
90757e8846
commit
cdaf8efbce
@ -189,6 +189,8 @@ set(SRCS ${SRCS}
|
||||
plugins/qml/api/extensionscheme/qmlextensionscheme.cpp
|
||||
plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.cpp
|
||||
plugins/qml/api/fileutils/qmlfileutils.cpp
|
||||
plugins/extensions.cpp
|
||||
plugins/themes.cpp
|
||||
popupwindow/popuplocationbar.cpp
|
||||
popupwindow/popupstatusbarmessage.cpp
|
||||
popupwindow/popupwebview.cpp
|
||||
|
@ -1107,6 +1107,12 @@ void MainApplication::setupUserScripts()
|
||||
falkonSpeedDial.setSourceCode(Scripts::setupSpeedDial());
|
||||
m_webProfile->scripts()->insert(falkonSpeedDial);
|
||||
|
||||
// falkon:extensions
|
||||
QWebEngineScript falkonExtensions;
|
||||
falkonExtensions.setWorldId(WebPage::SafeJsWorld);
|
||||
falkonExtensions.setSourceCode(Scripts::setupExtensions());
|
||||
m_webProfile->scripts()->insert(falkonExtensions);
|
||||
|
||||
// document.window object addons
|
||||
QWebEngineScript documentWindowAddons;
|
||||
documentWindowAddons.setName(QSL("_falkon_window_object"));
|
||||
|
@ -22,5 +22,9 @@
|
||||
<file>html/edit_active.svg</file>
|
||||
<file>html/sd_bg.svg</file>
|
||||
<file>html/broken-page.svg</file>
|
||||
<file>html/extensions.html</file>
|
||||
<file>html/extensions.user.js</file>
|
||||
<file>html/extensions.list.html</file>
|
||||
<file>html/themes.list.html</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
65
src/lib/data/html/extensions.html
Normal file
65
src/lib/data/html/extensions.html
Normal file
@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>%TITLE%</title>
|
||||
<style>
|
||||
html, body { width: 100%; height: 100%; margin: 0; }
|
||||
body { direction: %DIRECTION%; }
|
||||
h1 { color: #1a4ba4; font-size: 160%; margin-bottom: 0;}
|
||||
section { display: none; }
|
||||
div { margin: 0; }
|
||||
#sidebar { display: inline-block; float: left; width: %SIDEBAR-WIDTH%; margin: 0; }
|
||||
#content-box { display: inline-block; float: right; width: calc(100% - %SIDEBAR-WIDTH%); margin: 0; }
|
||||
.sidebar-menu { margin: 0; padding: 10px; cursor: pointer; font-size: 20px; }
|
||||
.sidebar-menu.active { color: #1a4ba4; }
|
||||
.sidebar-menu:hover { background-color: #dbdbdb; }
|
||||
.extension-list-item, .theme-list-item { padding: 20px; border-bottom: 1px solid #d0d0d0; }
|
||||
.extension-list-image, .theme-list-image { display: inline-block; width: 30px; vertical-align: top; }
|
||||
.extension-list-data, .theme-list-data { display: inline-block; width: calc(100% - 30px - 5px); margin-left: 5px; }
|
||||
.extension-name, .theme-name { font-size: 25px; line-height: 25px; display: inline-block; height: 25px; }
|
||||
.extension-description-short, .theme-description-short { display: none; }
|
||||
.extension-description, .theme-description { display: none; }
|
||||
.visible { display: inline-block; }
|
||||
.invisible { display: none; }
|
||||
.extension-description-state-button, .theme-description-state-button { color: blue; cursor: pointer; }
|
||||
.extension-description-state-button:hover, .theme-description-state-button:hover { text-decoration: underline; }
|
||||
.extension-control-buttons, .theme-control-buttons { display: inline-block; float: right; }
|
||||
.extension-control-button, .theme-control-button { display: inline-block; padding: 3px 6px; outline: none; }
|
||||
@media only screen and (max-width: 600px) {
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="sidebar">
|
||||
<div class="sidebar-menu active" id="extensions-button">Extensions</div>
|
||||
<div class="sidebar-menu" id="themes-button">Themes</div>
|
||||
</div>
|
||||
<div id="content-box">
|
||||
<div id="content">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="extensions">
|
||||
%EXTENSIONS-LIST%
|
||||
</section>
|
||||
|
||||
<section id="themes">
|
||||
%THEMES-LIST%
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function initDisplay() {
|
||||
// Extensions is default selection for page
|
||||
var content = document.getElementById("extensions").innerHTML;
|
||||
document.getElementById("content").innerHTML = content;
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
initDisplay();
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
24
src/lib/data/html/extensions.list.html
Normal file
24
src/lib/data/html/extensions.list.html
Normal file
@ -0,0 +1,24 @@
|
||||
<div class="extension-list-item">
|
||||
<img class="extension-list-image" src="data:image/png;base64, %EXTENSION-ICON%"><div class="extension-list-data">
|
||||
<div class="extension-name">%EXTENSION-NAME%</div>
|
||||
<div>
|
||||
<div class="extension-description-short visible" id="%EXTENSION-DESCRIPTION-SHORT-ID%">
|
||||
%EXTENSION-DESCRIPTION-SHORT%
|
||||
<span class="extension-description-state-button" id="%EXTENSION-DESCRIPTION-STATE-BUTTON-ID%">more</span>
|
||||
</div>
|
||||
<div class="extension-description" id="%EXTENSION-DESCRIPTION-ID%">
|
||||
%EXTENSION-DESCRIPTION%
|
||||
<table>
|
||||
<tr><td><b>Author</b></td><td>%EXTENSION-AUTHOR%</td></tr>
|
||||
<tr><td><b>Version</b></td><td>%EXTENSION-VERSION%</td></tr>
|
||||
</table>
|
||||
<label class="allow-in-incognito-button"><input class="allow-in-incognito-button-checkbox" id="%EXTENSION-ALLOW-IN-INCOGNITO-ID%" type="checkbox" autocomplete="off" %DISABLE-ALLOW-IN-INCOGNITO% %EXTENSION-ALLOWED-IN-INCOGNITO%>Allow in Incognito</label>
|
||||
</div>
|
||||
<div class="extension-control-buttons">
|
||||
<button class="extension-control-button enable" id="%EXTENSION-ENABLE-BUTTON-ID%">%EXTENSION-STATE%</button>
|
||||
<button class="extension-control-button settings" id="%EXTENSION-SETTINGS-BUTTON-ID%" %DISABLE-SETTINGS%>Settings</button>
|
||||
<button class="extension-control-button remove" id="%EXTENSION-REMOVE-BUTTON-ID%" %DISABLE-REMOVE%>Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
103
src/lib/data/html/extensions.user.js
Normal file
103
src/lib/data/html/extensions.user.js
Normal file
@ -0,0 +1,103 @@
|
||||
// ==UserScript==
|
||||
// @name _falkon_extensions
|
||||
// @run-at document-end
|
||||
// @include falkon:extensions
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
|
||||
function createNavigation() {
|
||||
|
||||
$("#extensions-button").click(function() {
|
||||
display("extensions", this);
|
||||
});
|
||||
|
||||
$("#themes-button").click(function() {
|
||||
display("themes", this);
|
||||
});
|
||||
|
||||
function display(id, button) {
|
||||
var content = $("#" + id).html();
|
||||
$("#content").html(content);
|
||||
$(".sidebar-menu").removeClass("active");
|
||||
$("#" + button.id).addClass("active");
|
||||
}
|
||||
}
|
||||
|
||||
function initToggleDescription() {
|
||||
$(document).on("click", ".extension-description-state-button", function() {
|
||||
$(".extension-description-short").addClass("visible");
|
||||
$(".extension-description").removeClass("visible");
|
||||
var extensionId = this.id.substring(0, this.id.length - "-description-state-button-id".length);
|
||||
document.getElementById(extensionId + "-description-short-id").className = document.getElementById(extensionId + "-description-short-id").className.replace("visible", "");
|
||||
document.getElementById(extensionId + "-description-id").className += " visible";
|
||||
});
|
||||
|
||||
$(document).on("click", ".theme-description-state-button", function() {
|
||||
$(".theme-description-short").addClass("visible");
|
||||
$(".theme-description").removeClass("visible");
|
||||
var themeId = this.id.substring(0, this.id.length - "-description-state-button-id".length);
|
||||
document.getElementById(themeId + "-description-short-id").className = document.getElementById(themeId + "-description-short-id").className.replace("visible", "");
|
||||
document.getElementById(themeId + "-description-id").className += " visible";
|
||||
});
|
||||
}
|
||||
|
||||
function initControlButtonsAndCheckbox() {
|
||||
$(document).on("click", ".extension-control-button.enable", function() {
|
||||
var extensionId = this.id.substring(0, this.id.length - "-enable-button-id".length);
|
||||
external.extensions.pluginStateChanged(extensionId);
|
||||
if (this.html() == "Enable") {
|
||||
document.getElementById(extensionId + "-settings-button-id").disabled = true;
|
||||
this.html("Disable");
|
||||
} else {
|
||||
document.getElementById(extensionId + "-settings-button-id").disabled = false;
|
||||
this.html("Enable");
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", ".extension-control-button.settings", function() {
|
||||
var extensionId = this.id.substring(0, this.id.length - "-settings-button-id".length);
|
||||
external.extensions.showSettings(extensionId);
|
||||
});
|
||||
|
||||
$(document).on("click", ".extension-control-button.remove", function() {
|
||||
var extensionId = this.id.substring(0, this.id.length - "-remove-button-id".length);
|
||||
external.extensions.removeExtension(extensionId);
|
||||
});
|
||||
|
||||
$(document).on("click", ".allow-in-incognito-button-checkbox", function() {
|
||||
var extensionId = this.id.substring(0, this.id.length - "-allow-in-incognito-id".length);
|
||||
external.extensions.allowInIncognito(extensionId, this.checked);
|
||||
});
|
||||
|
||||
$(document).on("click", ".theme-control-button.enable", function() {
|
||||
$(".theme-control-button.enable").prop('disabled', false);
|
||||
this.disabled = true;
|
||||
var themeId = this.id.substring(0, this.id.length - "-enable-button-id".length);
|
||||
external.themes.makeCurrent(themeId);
|
||||
});
|
||||
|
||||
$(document).on("click", ".theme-control-button.license", function() {
|
||||
var themeId = this.id.substring(0, this.id.length - "-license-button-id".length);
|
||||
external.themes.showLicense(themeId);
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
createNavigation();
|
||||
initToggleDescription();
|
||||
initControlButtonsAndCheckbox();
|
||||
|
||||
external.extensions.requestSync();
|
||||
external.extensions.reload.connect(function() { location.reload() });
|
||||
}
|
||||
|
||||
%JQUERY%
|
||||
%JQUERY-UI%
|
||||
|
||||
if (window._falkon_external) {
|
||||
init();
|
||||
} else {
|
||||
document.addEventListener("_falkon_external_created", init);
|
||||
}
|
||||
})();
|
21
src/lib/data/html/themes.list.html
Normal file
21
src/lib/data/html/themes.list.html
Normal file
@ -0,0 +1,21 @@
|
||||
<div class="theme-list-item">
|
||||
<img class="theme-list-image" src="data:image/png;base64, %THEME-ICON%"><div class="theme-list-data">
|
||||
<div class="theme-name">%THEME-NAME%</div>
|
||||
<div>
|
||||
<div class="theme-description-short visible" id="%THEME-DESCRIPTION-SHORT-ID%">
|
||||
%THEME-DESCRIPTION-SHORT%
|
||||
<span class="theme-description-state-button" id="%THEME-DESCRIPTION-STATE-BUTTON-ID%">more</span>
|
||||
</div>
|
||||
<div class="theme-description" id="%THEME-DESCRIPTION-ID%">
|
||||
%THEME-DESCRIPTION%
|
||||
<table>
|
||||
<tr><td><b>Author</b></td><td>%THEME-AUTHOR%</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="theme-control-buttons">
|
||||
<button class="theme-control-button enable" id="%THEME-ENABLE-BUTTON-ID%" %DISABLE-ENABLE%>Enable</button>
|
||||
<button class="theme-control-button license" id="%THEME-LICENSE-BUTTON-ID%" %DISABLE-LICENSE%>License</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -28,6 +28,8 @@
|
||||
#include "sessionmanager.h"
|
||||
#include "restoremanager.h"
|
||||
#include "../config.h"
|
||||
#include "sqldatabase.h"
|
||||
#include "themes.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QSettings>
|
||||
@ -52,7 +54,12 @@ void FalkonSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job)
|
||||
}
|
||||
|
||||
QStringList knownPages;
|
||||
knownPages << "about" << "start" << "speeddial" << "config" << "restore";
|
||||
knownPages << "about" << "start" << "speeddial" << "config" << "restore" << "extensions";
|
||||
|
||||
if (job->requestUrl().path().contains("config") ||
|
||||
job->requestUrl().path().contains("extensions")) {
|
||||
mApp->plugins()->getAvailablePlugins();
|
||||
}
|
||||
|
||||
if (knownPages.contains(job->requestUrl().path()))
|
||||
job->reply(QByteArrayLiteral("text/html"), new FalkonSchemeReply(job));
|
||||
@ -109,6 +116,8 @@ void FalkonSchemeReply::loadPage()
|
||||
contents = configPage();
|
||||
} else if (m_pageName == QLatin1String("restore")) {
|
||||
contents = restorePage();
|
||||
} else if (m_pageName == QLatin1String("extensions")) {
|
||||
contents = extensionsPage();
|
||||
}
|
||||
|
||||
QMutexLocker lock(&m_mutex);
|
||||
@ -416,3 +425,91 @@ QString FalkonSchemeReply::configPage()
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
QString FalkonSchemeReply::extensionsPage()
|
||||
{
|
||||
static QString ePage;
|
||||
|
||||
if (ePage.isEmpty()) {
|
||||
ePage.append(QzTools::readAllFileContents(":html/extensions.html"));
|
||||
ePage.replace(QLatin1String("%TITLE%"), tr("Falkon Extensions"));
|
||||
ePage.replace(QLatin1String("%SIDEBAR-WIDTH%"), "200px");
|
||||
ePage = QzTools::applyDirectionToPage(ePage);
|
||||
}
|
||||
|
||||
QString page = ePage;
|
||||
|
||||
// Plugins
|
||||
QSet<QString> allowedPluginsInPrivateMode;
|
||||
QSqlQuery query(SqlDatabase::instance()->database());
|
||||
query.exec(QSL("SELECT * FROM allowed_plugins WHERE allowInPrivateMode=1"));
|
||||
while (query.next()) {
|
||||
allowedPluginsInPrivateMode.insert(query.value(0).toString());
|
||||
}
|
||||
|
||||
QString pluginsString;
|
||||
QString pluginsList = QzTools::readAllFileByteContents(":html/extensions.list.html");
|
||||
const QList<Plugins::Plugin> &availablePlugins = mApp->plugins()->getAvailablePlugins();
|
||||
int charsInShortDescription = 75;
|
||||
foreach (const Plugins::Plugin &plugin, availablePlugins) {
|
||||
QString pluginListItem = pluginsList;
|
||||
PluginSpec spec = plugin.pluginSpec;
|
||||
QImage extensionImage = spec.icon.toImage();
|
||||
QByteArray byteArray;
|
||||
QBuffer buffer(&byteArray);
|
||||
extensionImage.save(&buffer, "PNG");
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-ICON%"), QString::fromLatin1(byteArray.toBase64().data()));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-NAME%"), spec.name);
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-DESCRIPTION-SHORT%"), QString("%1%2").arg(spec.description.left(charsInShortDescription), spec.description.length() > charsInShortDescription ? "..." : ""));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-DESCRIPTION%"), spec.description);
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-DESCRIPTION-SHORT-ID%"), QString("%1-description-short-id").arg(plugin.pluginId));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-DESCRIPTION-ID%"), QString("%1-description-id").arg(plugin.pluginId));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-DESCRIPTION-STATE-BUTTON-ID%"), QString("%1-description-state-button-id").arg(plugin.pluginId));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-AUTHOR%"), spec.author);
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-VERSION%"), spec.version);
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-ENABLE-BUTTON-ID%"), QString("%1-enable-button-id").arg(plugin.pluginId));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-SETTINGS-BUTTON-ID%"), QString("%1-settings-button-id").arg(plugin.pluginId));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-REMOVE-BUTTON-ID%"), QString("%1-remove-button-id").arg(plugin.pluginId));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-STATE%"), plugin.isLoaded() ? tr("Disable") : tr("Enable"));
|
||||
pluginListItem.replace(QLatin1String("%DISABLE-SETTINGS%"), plugin.isLoaded() && spec.hasSettings ? tr("") : tr("disabled"));
|
||||
pluginListItem.replace(QLatin1String("%DISABLE-REMOVE%"), plugin.type == Plugins::Plugin::QmlPlugin ? tr("") : tr("disabled"));
|
||||
pluginListItem.replace(QLatin1String("%DISABLE-ALLOW-IN-INCOGNITO%"), plugin.isLoaded() ? tr("") : tr("disabled"));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-ALLOW-IN-INCOGNITO-ID%"), QString("%1-allow-in-incognito-id").arg(plugin.pluginId));
|
||||
pluginListItem.replace(QLatin1String("%EXTENSION-ALLOWED-IN-INCOGNITO%"), allowedPluginsInPrivateMode.contains(plugin.pluginId) ? "checked" : "");
|
||||
pluginsString.append(pluginListItem);
|
||||
}
|
||||
page.replace(QLatin1String("%EXTENSIONS-LIST%"), pluginsString);
|
||||
|
||||
// Themes
|
||||
const QString activeTheme = Themes::getActiveTheme();
|
||||
const QList<Themes::Theme> &availableThemes = Themes::getAvailableThemes();
|
||||
QString themesString;
|
||||
QString themesList = QzTools::readAllFileByteContents(":html/themes.list.html");
|
||||
foreach (const Themes::Theme &theme, availableThemes) {
|
||||
QString themeListItem = themesList;
|
||||
QImage themeImage = theme.icon.pixmap(32, 32).toImage();
|
||||
QByteArray byteArray;
|
||||
QBuffer buffer(&byteArray);
|
||||
themeImage.save(&buffer, "PNG");
|
||||
themeListItem.replace(QLatin1String("%THEME-ICON%"), QString::fromLatin1(byteArray.toBase64().data()));
|
||||
themeListItem.replace(QLatin1String("%THEME-NAME%"), theme.name);
|
||||
themeListItem.replace(QLatin1String("%THEME-DESCRIPTION-SHORT%"), QString("%1%2").arg(theme.description.left(charsInShortDescription), theme.description.length() > charsInShortDescription ? "..." : ""));
|
||||
themeListItem.replace(QLatin1String("%THEME-DESCRIPTION%"), theme.description);
|
||||
themeListItem.replace(QLatin1String("%THEME-DESCRIPTION-SHORT-ID%"), QString("%1-description-short-id").arg(theme.name));
|
||||
themeListItem.replace(QLatin1String("%THEME-DESCRIPTION-ID%"), QString("%1-description-id").arg(theme.name));
|
||||
themeListItem.replace(QLatin1String("%THEME-DESCRIPTION-STATE-BUTTON-ID%"), QString("%1-description-state-button-id").arg(theme.name));
|
||||
themeListItem.replace(QLatin1String("%THEME-AUTHOR%"), theme.author);
|
||||
themeListItem.replace(QLatin1String("%THEME-ENABLE-BUTTON-ID%"), QString("%1-enable-button-id").arg(theme.name));
|
||||
themeListItem.replace(QLatin1String("%THEME-LICENSE-BUTTON-ID%"), QString("%1-license-button-id").arg(theme.name));
|
||||
themeListItem.replace(QLatin1String("%THEME-REMOVE-BUTTON-ID%"), QString("%1-remove-button-id").arg(theme.name));
|
||||
themeListItem.replace(QLatin1String("%DISABLE-LICENSE%"), theme.license.isEmpty() ? "disabled" : "");
|
||||
if (activeTheme == theme.dirName) {
|
||||
themeListItem.replace(QLatin1String("%DISABLE-ENABLE%"), QLatin1String("disabled"));
|
||||
} else {
|
||||
themeListItem.replace(QLatin1String("%DISABLE-ENABLE%"), QLatin1String(""));
|
||||
}
|
||||
themesString.append(themeListItem);
|
||||
}
|
||||
page.replace(QLatin1String("%THEMES-LIST%"), themesString);
|
||||
return page;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ private:
|
||||
QString speeddialPage();
|
||||
QString restorePage();
|
||||
QString configPage();
|
||||
QString extensionsPage();
|
||||
|
||||
bool m_loaded;
|
||||
QBuffer m_buffer;
|
||||
|
105
src/lib/plugins/extensions.cpp
Normal file
105
src/lib/plugins/extensions.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/* ============================================================
|
||||
* Falkon - Qt web browser
|
||||
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#include "extensions.h"
|
||||
#include "mainapplication.h"
|
||||
#include "pluginproxy.h"
|
||||
#include "sqldatabase.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
|
||||
Extensions::Extensions(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void Extensions::requestSync()
|
||||
{
|
||||
m_availablePlugins = mApp->plugins()->getAvailablePlugins();
|
||||
}
|
||||
|
||||
void Extensions::requestReload()
|
||||
{
|
||||
emit reload();
|
||||
}
|
||||
|
||||
void Extensions::pluginStateChanged(const QString &pluginId)
|
||||
{
|
||||
foreach (Plugins::Plugin plugin, m_availablePlugins) {
|
||||
if (plugin.pluginId == pluginId) {
|
||||
if (plugin.isLoaded()) {
|
||||
mApp->plugins()->unloadPlugin(&plugin);
|
||||
auto job = new SqlQueryJob(QSL("DELETE FROM allowed_plugins WHERE pluginId = ?"), this);
|
||||
job->addBindValue(plugin.pluginId);
|
||||
job->start();
|
||||
} else {
|
||||
mApp->plugins()->loadPlugin(&plugin);
|
||||
auto job = new SqlQueryJob(QSL("INSERT OR REPLACE INTO allowed_plugins (pluginId, allowInPrivateMode) VALUES (?, ?)"), this);
|
||||
job->addBindValue(plugin.pluginId);
|
||||
job->addBindValue(0);
|
||||
job->start();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Extensions::showSettings(const QString &pluginId)
|
||||
{
|
||||
foreach (const Plugins::Plugin &plugin, m_availablePlugins) {
|
||||
if (plugin.pluginId == pluginId && plugin.pluginSpec.hasSettings) {
|
||||
plugin.instance->showSettings();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Extensions::removeExtension(const QString &pluginId)
|
||||
{
|
||||
Plugins::Plugin requiredPlugin;
|
||||
foreach (const Plugins::Plugin &plugin, m_availablePlugins) {
|
||||
if (plugin.pluginId == pluginId) {
|
||||
requiredPlugin = plugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (requiredPlugin.type == Plugins::Plugin::Invalid) {
|
||||
return;
|
||||
}
|
||||
QMessageBox dialog;
|
||||
dialog.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
dialog.setText(QString(tr("Are you sure to permanently remove %1 plugin").arg(requiredPlugin.pluginSpec.name)));
|
||||
dialog.setIcon(QMessageBox::Question);
|
||||
if (dialog.exec() != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
mApp->plugins()->removePlugin(&requiredPlugin);
|
||||
}
|
||||
|
||||
void Extensions::allowInIncognito(const QString &pluginId, bool allowed)
|
||||
{
|
||||
foreach (const Plugins::Plugin &plugin, m_availablePlugins) {
|
||||
if (plugin.pluginId == pluginId && plugin.isLoaded()) {
|
||||
auto job = new SqlQueryJob(QSL("UPDATE allowed_plugins SET allowInPrivateMode=? WHERE pluginId=?"), this);
|
||||
job->addBindValue(allowed ? 1 : 0);
|
||||
job->addBindValue(plugin.pluginId);
|
||||
job->start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
41
src/lib/plugins/extensions.h
Normal file
41
src/lib/plugins/extensions.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* ============================================================
|
||||
* Falkon - Qt web browser
|
||||
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
#include "plugins.h"
|
||||
#include "mainapplication.h"
|
||||
#include "pluginproxy.h"
|
||||
#include "qzcommon.h"
|
||||
|
||||
class FALKON_EXPORT Extensions : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Extensions(QObject *parent = nullptr);
|
||||
Q_SIGNALS:
|
||||
void reload();
|
||||
public Q_SLOTS:
|
||||
void requestSync();
|
||||
void requestReload();
|
||||
void pluginStateChanged(const QString &pluginId);
|
||||
void showSettings(const QString &pluginId);
|
||||
void removeExtension(const QString &pluginId);
|
||||
void allowInIncognito(const QString &pluginId, bool allowed);
|
||||
private:
|
||||
QList<Plugins::Plugin> m_availablePlugins;
|
||||
};
|
@ -19,6 +19,7 @@
|
||||
#include "plugininterface.h"
|
||||
#include "mainapplication.h"
|
||||
#include "speeddial.h"
|
||||
#include "extensions.h"
|
||||
#include "settings.h"
|
||||
#include "datapaths.h"
|
||||
#include "adblock/adblockplugin.h"
|
||||
@ -37,6 +38,7 @@ Plugins::Plugins(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_pluginsLoaded(false)
|
||||
, m_speedDial(new SpeedDial(this))
|
||||
, m_extensions(new Extensions(this))
|
||||
{
|
||||
loadSettings();
|
||||
|
||||
@ -45,6 +47,8 @@ Plugins::Plugins(QObject* parent)
|
||||
}
|
||||
|
||||
loadQmlSupport();
|
||||
|
||||
connect(this, &Plugins::refreshedLoadedPlugins, m_extensions, &Extensions::requestReload);
|
||||
}
|
||||
|
||||
QList<Plugins::Plugin> Plugins::getAvailablePlugins()
|
||||
@ -88,6 +92,28 @@ void Plugins::unloadPlugin(Plugins::Plugin* plugin)
|
||||
refreshLoadedPlugins();
|
||||
}
|
||||
|
||||
void Plugins::removePlugin(Plugins::Plugin *plugin)
|
||||
{
|
||||
if (plugin->type != Plugin::QmlPlugin) {
|
||||
return;
|
||||
}
|
||||
if (plugin->isLoaded()) {
|
||||
unloadPlugin(plugin);
|
||||
}
|
||||
|
||||
// For QML plugins, pluginId is qml:<plugin-dir-name>
|
||||
const QString dirName = plugin->pluginId.remove(0, QLatin1String("qml:").size());
|
||||
const QString dirPath = DataPaths::locate(DataPaths::Plugins, QSL("qml/") + dirName);
|
||||
bool result = QDir(dirPath).removeRecursively();
|
||||
if (!result) {
|
||||
qWarning() << "Unable to remove" << plugin->pluginSpec.name;
|
||||
return;
|
||||
}
|
||||
|
||||
m_availablePlugins.removeOne(*plugin);
|
||||
refreshedLoadedPlugins();
|
||||
}
|
||||
|
||||
void Plugins::loadSettings()
|
||||
{
|
||||
QSqlQuery query(SqlDatabase::instance()->database());
|
||||
@ -243,6 +269,8 @@ void Plugins::refreshLoadedPlugins()
|
||||
m_loadedPlugins.append(plugin.instance);
|
||||
}
|
||||
}
|
||||
|
||||
emit refreshedLoadedPlugins();
|
||||
}
|
||||
|
||||
void Plugins::loadPythonSupport()
|
||||
|
@ -30,6 +30,7 @@ class QLibrary;
|
||||
class QPluginLoader;
|
||||
|
||||
class SpeedDial;
|
||||
class Extensions;
|
||||
class QmlPluginLoader;
|
||||
|
||||
struct PluginSpec {
|
||||
@ -95,12 +96,16 @@ public:
|
||||
|
||||
bool loadPlugin(Plugin* plugin);
|
||||
void unloadPlugin(Plugin* plugin);
|
||||
void removePlugin(Plugin *plugin);
|
||||
|
||||
void shutdown();
|
||||
|
||||
// SpeedDial
|
||||
SpeedDial* speedDial() { return m_speedDial; }
|
||||
|
||||
// Extensions
|
||||
Extensions *extensions() { return m_extensions; }
|
||||
|
||||
static PluginSpec createSpec(const DesktopFile &metaData);
|
||||
|
||||
static QStringList getDefaultAllowedPlugins();
|
||||
@ -115,6 +120,7 @@ protected:
|
||||
|
||||
Q_SIGNALS:
|
||||
void pluginUnloaded(PluginInterface* plugin);
|
||||
void refreshedLoadedPlugins();
|
||||
|
||||
private:
|
||||
void loadPythonSupport();
|
||||
@ -141,6 +147,7 @@ private:
|
||||
bool m_pluginsLoaded;
|
||||
|
||||
SpeedDial* m_speedDial;
|
||||
Extensions *m_extensions;
|
||||
QList<PluginInterface*> m_internalPlugins;
|
||||
|
||||
QLibrary *m_pythonPlugin = nullptr;
|
||||
|
145
src/lib/plugins/themes.cpp
Normal file
145
src/lib/plugins/themes.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
/* ============================================================
|
||||
* Falkon - Qt web browser
|
||||
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
|
||||
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#include "themes.h"
|
||||
#include "datapaths.h"
|
||||
#include "desktopfile.h"
|
||||
#include "qztools.h"
|
||||
#include "settings.h"
|
||||
#include "licenseviewer.h"
|
||||
#include "mainapplication.h"
|
||||
#include <QDir>
|
||||
|
||||
Themes::Themes(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
QList<Themes::Theme> Themes::getAvailableThemes()
|
||||
{
|
||||
QList<Theme> availableThemes;
|
||||
const QStringList themePaths = DataPaths::allPaths(DataPaths::Themes);
|
||||
foreach (const QString &path, themePaths) {
|
||||
QDir dir(path);
|
||||
QStringList list = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
|
||||
foreach (const QString &name, list) {
|
||||
Theme themeInfo = parseTheme(dir.absoluteFilePath(name) + QLatin1Char('/'), name);
|
||||
if (!themeInfo.isValid) {
|
||||
continue;
|
||||
}
|
||||
availableThemes.append(themeInfo);
|
||||
}
|
||||
}
|
||||
return availableThemes;
|
||||
}
|
||||
|
||||
QString Themes::getActiveTheme()
|
||||
{
|
||||
Settings settings;
|
||||
settings.beginGroup("Themes");
|
||||
const QString activeTheme = settings.value("activeTheme", DEFAULT_THEME_NAME).toString();
|
||||
settings.endGroup();
|
||||
return activeTheme;
|
||||
}
|
||||
|
||||
void Themes::showLicense(const QString &themeName)
|
||||
{
|
||||
Theme theme = getThemeByName(themeName);
|
||||
if (!theme.isValid) {
|
||||
return;
|
||||
}
|
||||
LicenseViewer *licenseViewer = new LicenseViewer;
|
||||
licenseViewer->setText(theme.license);
|
||||
licenseViewer->show();
|
||||
QzTools::centerWidgetOnScreen(licenseViewer);
|
||||
}
|
||||
|
||||
void Themes::makeCurrent(const QString &themeName)
|
||||
{
|
||||
Theme theme = getThemeByName(themeName);
|
||||
if (!theme.isValid) {
|
||||
return;
|
||||
}
|
||||
Settings settings;
|
||||
settings.beginGroup("Themes");
|
||||
settings.setValue("activeTheme", theme.dirName);
|
||||
settings.endGroup();
|
||||
|
||||
mApp->reloadSettings();
|
||||
}
|
||||
|
||||
// static
|
||||
Themes::Theme Themes::parseTheme(const QString &path, const QString &name)
|
||||
{
|
||||
Theme info;
|
||||
info.isValid = false;
|
||||
|
||||
if (!QFile(path + "main.css").exists() || !QFile(path + "metadata.desktop").exists()) {
|
||||
info.isValid = false;
|
||||
return info;
|
||||
}
|
||||
|
||||
DesktopFile metadata(path + QSL("metadata.desktop"));
|
||||
info.name = metadata.name();
|
||||
info.dirName = name;
|
||||
info.description = metadata.comment();
|
||||
info.author = metadata.value(QSL("X-Falkon-Author")).toString();
|
||||
|
||||
const QString iconName = metadata.icon();
|
||||
if (!iconName.isEmpty()) {
|
||||
if (QFileInfo::exists(path + iconName)) {
|
||||
info.icon = QIcon(path + iconName);
|
||||
} else {
|
||||
info.icon = QIcon::fromTheme(iconName);
|
||||
}
|
||||
}
|
||||
|
||||
const QString licensePath = metadata.value(QSL("X-Falkon-License")).toString();
|
||||
if (!licensePath.isEmpty() && QFileInfo::exists(path + licensePath)) {
|
||||
info.license = QzTools::readAllFileContents(path + licensePath);
|
||||
}
|
||||
|
||||
if (info.name.isEmpty()) {
|
||||
return info;
|
||||
}
|
||||
|
||||
info.isValid = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
Themes::Theme Themes::getThemeByName(const QString &themeName) const
|
||||
{
|
||||
const QStringList themePaths = DataPaths::allPaths(DataPaths::Themes);
|
||||
foreach (const QString &path, themePaths) {
|
||||
QDir dir(path);
|
||||
QStringList list = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
|
||||
foreach (const QString &name, list) {
|
||||
Theme themeInfo = parseTheme(dir.absoluteFilePath(name) + QLatin1Char('/'), name);
|
||||
if (!themeInfo.isValid) {
|
||||
continue;
|
||||
}
|
||||
if (themeInfo.name == themeName) {
|
||||
return themeInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
Theme info;
|
||||
info.isValid = false;
|
||||
return info;
|
||||
}
|
47
src/lib/plugins/themes.h
Normal file
47
src/lib/plugins/themes.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* ============================================================
|
||||
* Falkon - Qt web browser
|
||||
* Copyright (C) 2010-2014 David Rosca <nowrep@gmail.com>
|
||||
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
#include <QIcon>
|
||||
#include "qzcommon.h"
|
||||
|
||||
class FALKON_EXPORT Themes : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct Theme {
|
||||
bool isValid;
|
||||
QIcon icon;
|
||||
QString name;
|
||||
QString dirName;
|
||||
QString author;
|
||||
QString description;
|
||||
QString license;
|
||||
};
|
||||
explicit Themes(QObject *parent = nullptr);
|
||||
|
||||
static QList<Theme> getAvailableThemes();
|
||||
static QString getActiveTheme();
|
||||
public Q_SLOTS:
|
||||
void showLicense(const QString &themeName);
|
||||
void makeCurrent(const QString &themeName);
|
||||
private:
|
||||
static Theme parseTheme(const QString &path, const QString &name);
|
||||
Theme getThemeByName(const QString &themeName) const;
|
||||
};
|
@ -25,6 +25,7 @@
|
||||
#include "iconprovider.h"
|
||||
#include "../config.h"
|
||||
#include "sqldatabase.h"
|
||||
#include "extensions.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
@ -162,6 +162,14 @@ QString Scripts::setupSpeedDial()
|
||||
return source;
|
||||
}
|
||||
|
||||
QString Scripts::setupExtensions()
|
||||
{
|
||||
QString source = QzTools::readAllFileContents(QSL(":html/extensions.user.js"));
|
||||
source.replace(QL1S("%JQUERY%"), QzTools::readAllFileContents(QSL(":html/jquery.js")));
|
||||
source.replace(QL1S("%JQUERY-UI%"), QzTools::readAllFileContents(QSL(":html/jquery-ui.js")));
|
||||
return source;
|
||||
}
|
||||
|
||||
QString Scripts::setCss(const QString &css)
|
||||
{
|
||||
QString source = QL1S("(function() {"
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
static QString setupFormObserver();
|
||||
static QString setupWindowObject();
|
||||
static QString setupSpeedDial();
|
||||
static QString setupExtensions();
|
||||
|
||||
static QString setCss(const QString &css);
|
||||
static QString sendPostData(const QUrl &url, const QByteArray &data);
|
||||
|
@ -19,9 +19,11 @@
|
||||
#include "mainapplication.h"
|
||||
#include "pluginproxy.h"
|
||||
#include "speeddial.h"
|
||||
#include "extensions.h"
|
||||
#include "webpage.h"
|
||||
#include "autofilljsobject.h"
|
||||
#include "restoremanager.h"
|
||||
#include "themes.h"
|
||||
|
||||
#include <QWebChannel>
|
||||
|
||||
@ -31,6 +33,7 @@ ExternalJsObject::ExternalJsObject(WebPage *page)
|
||||
: QObject(page)
|
||||
, m_page(page)
|
||||
, m_autoFill(new AutoFillJsObject(this))
|
||||
, m_themes(new Themes(this))
|
||||
{
|
||||
}
|
||||
|
||||
@ -81,3 +84,19 @@ QObject *ExternalJsObject::recovery() const
|
||||
|
||||
return mApp->restoreManager()->recoveryObject(m_page);
|
||||
}
|
||||
|
||||
QObject *ExternalJsObject::extensions() const
|
||||
{
|
||||
if (m_page->url().toString() != QL1S("falkon:extensions"))
|
||||
return Q_NULLPTR;
|
||||
|
||||
return mApp->plugins()->extensions();
|
||||
}
|
||||
|
||||
QObject *ExternalJsObject::themes() const
|
||||
{
|
||||
if (m_page->url().toString() != QL1S("falkon:extensions"))
|
||||
return Q_NULLPTR;
|
||||
|
||||
return m_themes;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
class WebPage;
|
||||
class AutoFillJsObject;
|
||||
class Themes;
|
||||
|
||||
class QWebChannel;
|
||||
|
||||
@ -33,6 +34,8 @@ class FALKON_EXPORT ExternalJsObject : public QObject
|
||||
Q_PROPERTY(QObject* speedDial READ speedDial CONSTANT)
|
||||
Q_PROPERTY(QObject* autoFill READ autoFill CONSTANT)
|
||||
Q_PROPERTY(QObject* recovery READ recovery CONSTANT)
|
||||
Q_PROPERTY(QObject* extensions READ extensions CONSTANT)
|
||||
Q_PROPERTY(QObject* themes READ themes CONSTANT)
|
||||
|
||||
public:
|
||||
explicit ExternalJsObject(WebPage *page);
|
||||
@ -48,9 +51,12 @@ private:
|
||||
QObject *speedDial() const;
|
||||
QObject *autoFill() const;
|
||||
QObject *recovery() const;
|
||||
QObject *extensions() const;
|
||||
QObject *themes() const;
|
||||
|
||||
WebPage *m_page;
|
||||
AutoFillJsObject *m_autoFill;
|
||||
Themes *m_themes;
|
||||
};
|
||||
|
||||
#endif // EXTERNALJSOBJECT_H
|
||||
|
Loading…
Reference in New Issue
Block a user