1
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:
Anmol Gautam 2018-07-25 12:46:28 +05:30
parent 90757e8846
commit cdaf8efbce
20 changed files with 732 additions and 1 deletions

View File

@ -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

View File

@ -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"));

View File

@ -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>

View 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>

View 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>

View 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);
}
})();

View 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>

View File

@ -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;
}

View File

@ -56,6 +56,7 @@ private:
QString speeddialPage();
QString restorePage();
QString configPage();
QString extensionsPage();
bool m_loaded;
QBuffer m_buffer;

View 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;
}
}
}

View 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;
};

View File

@ -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()

View File

@ -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
View 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
View 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;
};

View File

@ -25,6 +25,7 @@
#include "iconprovider.h"
#include "../config.h"
#include "sqldatabase.h"
#include "extensions.h"
#include <QInputDialog>
#include <QMessageBox>

View File

@ -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() {"

View File

@ -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);

View File

@ -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;
}

View File

@ -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