diff --git a/CMakeLists.txt b/CMakeLists.txt index cb35545d3..e5c383718 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,11 @@ if (PySide2_FOUND AND Shiboken2_FOUND AND PythonLibs_FOUND) set(ENABLE_PYTHON_PLUGINS TRUE) endif() +find_package(LibIntl) +if (LibIntl_FOUND) + set(HAVE_LIBINTL TRUE) +endif() + # Git revision if (EXISTS "${CMAKE_SOURCE_DIR}/.git") find_package(Git QUIET) diff --git a/cmake/FindLibIntl.cmake b/cmake/FindLibIntl.cmake new file mode 100644 index 000000000..cc045da5a --- /dev/null +++ b/cmake/FindLibIntl.cmake @@ -0,0 +1,9 @@ +find_path(LibIntl_INCLUDE_DIRS NAMES libintl.h) +find_library(LibIntl_LIBRARIES NAMES intl libintl) +include(CheckCXXSymbolExists) +check_cxx_symbol_exists(gettext libintl.h LibIntl_SYMBOL_FOUND) +if (LibIntl_SYMBOL_FOUND) + set(LibIntl_FOUND TRUE) +else() + set(LibIntl_FOUND FALSE) +endif() diff --git a/config.h.cmake b/config.h.cmake index d35648e5b..e07edb56e 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -9,3 +9,5 @@ /* Disable DBus support */ #cmakedefine DISABLE_DBUS + +#cmakedefine HAVE_LIBINTL diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ee82c94e2..635a58602 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -154,6 +154,44 @@ set(SRCS ${SRCS} plugins/pluginproxy.cpp plugins/plugins.cpp plugins/speeddial.cpp + plugins/qml/qmlpluginloader.cpp + plugins/qml/qmlplugin.cpp + plugins/qml/qmlplugins.cpp + plugins/qml/qmlplugininterface.cpp + plugins/qml/qmlengine.cpp + plugins/qml/qmlstaticdata.cpp + plugins/qml/api/bookmarks/qmlbookmarktreenode.cpp + plugins/qml/api/bookmarks/qmlbookmarks.cpp + plugins/qml/api/topsites/qmlmostvisitedurl.cpp + plugins/qml/api/topsites/qmltopsites.cpp + plugins/qml/api/history/qmlhistoryitem.cpp + plugins/qml/api/history/qmlhistory.cpp + plugins/qml/api/cookies/qmlcookie.cpp + plugins/qml/api/cookies/qmlcookies.cpp + plugins/qml/api/tabs/qmltab.cpp + plugins/qml/api/tabs/qmltabs.cpp + plugins/qml/api/notifications/qmlnotifications.cpp + plugins/qml/api/clipboard/qmlclipboard.cpp + plugins/qml/api/windows/qmlwindow.cpp + plugins/qml/api/windows/qmlwindows.cpp + plugins/qml/api/windows/qmlwindowstate.cpp + plugins/qml/api/windows/qmlwindowtype.cpp + plugins/qml/api/browseraction/qmlbrowseraction.cpp + plugins/qml/api/sidebar/qmlsidebar.cpp + plugins/qml/api/menus/qmlmenu.cpp + plugins/qml/api/menus/qmlaction.cpp + plugins/qml/api/menus/qmlwebhittestresult.cpp + plugins/qml/api/settings/qmlsettings.cpp + plugins/qml/api/events/qmlqzobjects.cpp + plugins/qml/api/events/qmlmouseevent.cpp + plugins/qml/api/events/qmlwheelevent.cpp + plugins/qml/api/events/qmlkeyevent.cpp + plugins/qml/api/userscript/qmluserscript.cpp + plugins/qml/api/userscript/qmluserscripts.cpp + plugins/qml/api/userscript/qmlexternaljsobject.cpp + plugins/qml/api/extensionscheme/qmlextensionscheme.cpp + plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.cpp + plugins/qml/api/fileutils/qmlfileutils.cpp popupwindow/popuplocationbar.cpp popupwindow/popupstatusbarmessage.cpp popupwindow/popupwebview.cpp @@ -228,6 +266,10 @@ set(SRCS ${SRCS} webtab/webtab.cpp ) +if (LibIntl_FOUND) + set(SRCS ${SRCS} plugins/qml/api/i18n/qmli18n.cpp) +endif() + if (WIN32) set(SRCS ${SRCS} other/registerqappassociation.cpp) endif() diff --git a/src/lib/app/profilemanager.cpp b/src/lib/app/profilemanager.cpp index 4c86c6162..c3aeae8d0 100644 --- a/src/lib/app/profilemanager.cpp +++ b/src/lib/app/profilemanager.cpp @@ -21,6 +21,7 @@ #include "updater.h" #include "qztools.h" #include "sqldatabase.h" +#include "plugins.h" #include #include @@ -303,6 +304,18 @@ void ProfileManager::connectDatabase() qCritical() << "Error creating database schema" << query.lastError().text(); } } + + // Insert default allowed plugins to allowed_plugins table + QStringList defaultAllowedPlugins = Plugins::getDefaultAllowedPlugins(); + QSqlQuery query(SqlDatabase::instance()->database()); + for (const QString &defaultPlugin : defaultAllowedPlugins) { + query.prepare("INSERT INTO allowed_plugins VALUES (?, ?)"); + query.addBindValue(defaultPlugin); + query.addBindValue(1); + if (!query.exec()) { + qWarning() << "Unable to insert" << defaultPlugin << "into database"; + } + } } SqlDatabase::instance()->setDatabase(db); diff --git a/src/lib/data/data/browsedata.sql b/src/lib/data/data/browsedata.sql index 570756a50..334c05eba 100644 --- a/src/lib/data/data/browsedata.sql +++ b/src/lib/data/data/browsedata.sql @@ -55,4 +55,9 @@ CREATE TABLE icons ( ); CREATE UNIQUE INDEX icons_urluniqueindex ON icons (url); +CREATE TABLE allowed_plugins ( + pluginId TEXT NOT NULL UNIQUE, + allowInPrivateMode INTEGER DEFAULT 0 NOT NULL +); + -- Data diff --git a/src/lib/history/history.cpp b/src/lib/history/history.cpp index 3bda5897c..af08098f3 100644 --- a/src/lib/history/history.cpp +++ b/src/lib/history/history.cpp @@ -180,6 +180,18 @@ void History::deleteHistoryEntry(const QList &list) db.commit(); } +void History::deleteHistoryEntry(const QString &url) +{ + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare("SELECT id FROM history WHERE url=?"); + query.bindValue(0, url); + query.exec(); + if (query.next()) { + int id = query.value(0).toInt(); + deleteHistoryEntry(id); + } +} + void History::deleteHistoryEntry(const QString &url, const QString &title) { QSqlQuery query(SqlDatabase::instance()->database()); @@ -285,3 +297,41 @@ QString History::titleCaseLocalizedMonth(int month) return QString(); } } + +QList History::searchHistoryEntry(const QString &text) +{ + QList list; + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare("SELECT count, date, id, title, url FROM history WHERE title LIKE ? OR url LIKE ?"); + query.bindValue(0, QString("%%1%").arg(text)); + query.bindValue(1, QString("%%1%").arg(text)); + query.exec(); + while (query.next()) { + HistoryEntry *entry = new HistoryEntry; + entry->count = query.value(0).toInt(); + entry->date = query.value(1).toDateTime(); + entry->id = query.value(2).toInt(); + entry->title = query.value(3).toString(); + entry->url = query.value(4).toUrl(); + list.append(entry); + } + return list; +} + +HistoryEntry *History::getHistoryEntry(const QString &text) +{ + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare("SELECT count, date, id, title, url FROM history WHERE url = ?"); + query.bindValue(0, text); + query.exec(); + + HistoryEntry *entry = new HistoryEntry; + if (query.next()) { + entry->count = query.value(0).toInt(); + entry->date = query.value(1).toDateTime(); + entry->id = query.value(2).toInt(); + entry->title = query.value(3).toString(); + entry->url = query.value(4).toUrl(); + } + return entry; +} diff --git a/src/lib/history/history.h b/src/lib/history/history.h index ad634d2ee..60c6ef4ef 100644 --- a/src/lib/history/history.h +++ b/src/lib/history/history.h @@ -54,6 +54,7 @@ public: void deleteHistoryEntry(int index); void deleteHistoryEntry(const QList &list); + void deleteHistoryEntry(const QString &url); void deleteHistoryEntry(const QString &url, const QString &title); QList indexesFromTimeRange(qint64 start, qint64 end); @@ -66,6 +67,9 @@ public: void loadSettings(); + QList searchHistoryEntry(const QString &text); + HistoryEntry *getHistoryEntry(const QString &text); + Q_SIGNALS: void historyEntryAdded(const HistoryEntry &entry); void historyEntryDeleted(const HistoryEntry &entry); diff --git a/src/lib/plugins/plugins.cpp b/src/lib/plugins/plugins.cpp index 7a360bcc3..ec7b2d40b 100644 --- a/src/lib/plugins/plugins.cpp +++ b/src/lib/plugins/plugins.cpp @@ -24,10 +24,15 @@ #include "adblock/adblockplugin.h" #include "../config.h" #include "desktopfile.h" +#include "qml/qmlplugins.h" +#include "sqldatabase.h" +#include "qml/qmlplugin.h" #include #include #include +#include +#include Plugins::Plugins(QObject* parent) : QObject(parent) @@ -82,21 +87,39 @@ void Plugins::unloadPlugin(Plugins::Plugin* plugin) refreshLoadedPlugins(); } -void Plugins::loadSettings() +void Plugins::removePlugin(Plugins::Plugin *plugin) { - QStringList defaultAllowedPlugins = { - QSL("internal:adblock") - }; - - // Enable KDE Frameworks Integration when running inside KDE session - if (qgetenv("KDE_FULL_SESSION") == QByteArray("true")) { - defaultAllowedPlugins.append(QSL("lib:KDEFrameworksIntegration.so")); + if (plugin->type != Plugin::QmlPlugin) { + return; + } + if (plugin->isLoaded()) { + unloadPlugin(plugin); } - Settings settings; - settings.beginGroup("Plugin-Settings"); - m_allowedPlugins = settings.value("AllowedPlugins", defaultAllowedPlugins).toStringList(); - settings.endGroup(); + // For QML plugins, pluginId is qml: + 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()); + if (mApp->isPrivate()) { + query.exec(QSL("SELECT * FROM allowed_plugins WHERE allowInPrivateMode=1")); + } else { + query.exec(QSL("SELECT * FROM allowed_plugins")); + } + while (query.next()) { + m_allowedPlugins.append(query.value(0).toString()); + } } void Plugins::shutdown() @@ -204,6 +227,24 @@ void Plugins::loadAvailablePlugins() } } } + + // QmlPlugin + for (QString dir : dirs) { + // qml plugins will be loaded from subdirectory qml + dir.append(QSL("/qml")); + const auto qmlDirs = QDir(dir).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QFileInfo &info : qmlDirs) { + Plugin plugin = QmlPlugin::loadPlugin(info.absoluteFilePath()); + if (plugin.type == Plugin::Invalid) { + continue; + } + if (plugin.pluginSpec.name.isEmpty()) { + qWarning() << "Invalid plugin spec of" << info.absoluteFilePath() << "plugin"; + continue; + } + registerAvailablePlugin(plugin); + } + } } void Plugins::registerAvailablePlugin(const Plugin &plugin) @@ -222,6 +263,8 @@ void Plugins::refreshLoadedPlugins() m_loadedPlugins.append(plugin.instance); } } + + emit refreshedLoadedPlugins(); } void Plugins::loadPythonSupport() @@ -258,6 +301,8 @@ Plugins::Plugin Plugins::loadPlugin(const QString &id) type = Plugin::SharedLibraryPlugin; } else if (t == QL1S("python")) { type = Plugin::PythonPlugin; + } else if (t == QL1S("qml")) { + type = Plugin::QmlPlugin; } name = id.mid(colon + 1); } else { @@ -275,6 +320,9 @@ Plugins::Plugin Plugins::loadPlugin(const QString &id) case Plugin::PythonPlugin: return loadPythonPlugin(name); + case Plugin::QmlPlugin: + return QmlPlugin::loadPlugin(name); + default: return Plugin(); } @@ -359,6 +407,10 @@ bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin) initPythonPlugin(plugin); break; + case Plugin::QmlPlugin: + QmlPlugin::initPlugin(plugin); + break; + default: return false; } @@ -367,6 +419,8 @@ bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin) return false; } + // DataPaths::currentProfilePath() + QL1S("/extensions") is duplicated in qmlsettings.cpp + // If you change this, please change it there too. plugin->instance->init(state, DataPaths::currentProfilePath() + QL1S("/extensions")); if (!plugin->instance->testPlugin()) { @@ -409,3 +463,18 @@ void Plugins::initPythonPlugin(Plugin *plugin) f(plugin); } + +// static +QStringList Plugins::getDefaultAllowedPlugins() +{ + QStringList defaultAllowedPlugins = { + QSL("internal:adblock") + }; + + // Enable KDE Frameworks Integration when running inside KDE session + if (qgetenv("KDE_FULL_SESSION") == QByteArray("true")) { + defaultAllowedPlugins.append(QSL("lib:KDEFrameworksIntegration.so")); + } + + return defaultAllowedPlugins; +} diff --git a/src/lib/plugins/plugins.h b/src/lib/plugins/plugins.h index bfd77b5f6..d6e237180 100644 --- a/src/lib/plugins/plugins.h +++ b/src/lib/plugins/plugins.h @@ -24,6 +24,7 @@ #include "qzcommon.h" #include "plugininterface.h" +#include "qml/qmlpluginloader.h" class QLibrary; class QPluginLoader; @@ -55,7 +56,8 @@ public: Invalid = 0, InternalPlugin, SharedLibraryPlugin, - PythonPlugin + PythonPlugin, + QmlPlugin }; Type type = Invalid; QString pluginId; @@ -88,6 +90,7 @@ public: bool loadPlugin(Plugin* plugin); void unloadPlugin(Plugin* plugin); + void removePlugin(Plugin *plugin); void shutdown(); @@ -96,6 +99,8 @@ public: static PluginSpec createSpec(const DesktopFile &metaData); + static QStringList getDefaultAllowedPlugins(); + public Q_SLOTS: void loadSettings(); @@ -106,6 +111,7 @@ protected: Q_SIGNALS: void pluginUnloaded(PluginInterface* plugin); + void refreshedLoadedPlugins(); private: void loadPythonSupport(); diff --git a/src/lib/plugins/qml/api/bookmarks/qmlbookmarks.cpp b/src/lib/plugins/qml/api/bookmarks/qmlbookmarks.cpp new file mode 100644 index 000000000..c0981e495 --- /dev/null +++ b/src/lib/plugins/qml/api/bookmarks/qmlbookmarks.cpp @@ -0,0 +1,257 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlbookmarks.h" +#include "bookmarks.h" +#include "qml/qmlstaticdata.h" +#include +#include + +QmlBookmarks::QmlBookmarks(QObject *parent) + : QObject(parent) +{ + connect(mApp->bookmarks(), &Bookmarks::bookmarkAdded, this, [this](BookmarkItem *item){ + auto treeNode = QmlStaticData::instance().getBookmarkTreeNode(item); + emit created(treeNode); + }); + + connect(mApp->bookmarks(), &Bookmarks::bookmarkChanged, this, [this](BookmarkItem *item){ + auto treeNode = QmlStaticData::instance().getBookmarkTreeNode(item); + emit changed(treeNode); + }); + + connect(mApp->bookmarks(), &Bookmarks::bookmarkRemoved, this, [this](BookmarkItem *item){ + auto treeNode = QmlStaticData::instance().getBookmarkTreeNode(item); + emit removed(treeNode); + }); +} + +BookmarkItem *QmlBookmarks::getBookmarkItem(QmlBookmarkTreeNode *treeNode) const +{ + auto bookmarks = mApp->bookmarks(); + QList items; + + if (treeNode->url().isEmpty()) { + if (treeNode->item() == bookmarks->rootItem()) { + return bookmarks->rootItem(); + + } else if (treeNode->item() == bookmarks->toolbarFolder()) { + return bookmarks->toolbarFolder(); + + } else if (treeNode->item() == bookmarks->menuFolder()) { + return bookmarks->menuFolder(); + + } else if (treeNode->item() == bookmarks->unsortedFolder()) { + return bookmarks->unsortedFolder(); + } + + items = bookmarks->searchBookmarks(treeNode->title()); + } else { + items = bookmarks->searchBookmarks(QUrl::fromEncoded(treeNode->url().toUtf8())); + } + + for (BookmarkItem *item : qAsConst(items)) { + if (treeNode->item() == item) { + return item; + } + } + + return nullptr; +} + +BookmarkItem *QmlBookmarks::getBookmarkItem(QObject *object) const +{ + auto treeNode = qobject_cast(object); + if (!treeNode) { + return nullptr; + } + + auto item = getBookmarkItem(treeNode); + if (!item || item->urlString() != treeNode->url()) { + return nullptr; + } + + return item; +} + +bool QmlBookmarks::isBookmarked(const QString &url) const +{ + return mApp->bookmarks()->isBookmarked(QUrl::fromEncoded(url.toUtf8())); +} + +QmlBookmarkTreeNode *QmlBookmarks::rootItem() const +{ + return QmlStaticData::instance().getBookmarkTreeNode(mApp->bookmarks()->rootItem()); +} + +QmlBookmarkTreeNode *QmlBookmarks::toolbarFolder() const +{ + return QmlStaticData::instance().getBookmarkTreeNode(mApp->bookmarks()->toolbarFolder()); +} + +QmlBookmarkTreeNode *QmlBookmarks::menuFolder() const +{ + return QmlStaticData::instance().getBookmarkTreeNode(mApp->bookmarks()->menuFolder()); +} + +QmlBookmarkTreeNode *QmlBookmarks::unsortedFolder() const +{ + return QmlStaticData::instance().getBookmarkTreeNode(mApp->bookmarks()->unsortedFolder()); +} + +QmlBookmarkTreeNode *QmlBookmarks::lastUsedFolder() const +{ + return QmlStaticData::instance().getBookmarkTreeNode(mApp->bookmarks()->lastUsedFolder()); +} + +bool QmlBookmarks::create(const QVariantMap &map) const +{ + if (!map.contains(QSL("parent"))) { + qWarning() << "Unable to create new bookmark:" << "parent not found"; + return false; + } + const QString title = map.value(QSL("title")).toString(); + const QString urlString = map.value(QSL("url")).toString(); + const QString description = map.value(QSL("description")).toString(); + + BookmarkItem::Type type; + if (map.contains(QSL("type"))) { + type = BookmarkItem::Type(map.value(QSL("type")).toInt()); + } else if (urlString.isEmpty()){ + if (!title.isEmpty()) { + type = BookmarkItem::Folder; + } else { + type = BookmarkItem::Invalid; + } + } else { + type = BookmarkItem::Url; + } + + auto object = map.value(QSL("parent")).value(); + auto parent = getBookmarkItem(object); + if (!parent) { + qWarning() << "Unable to create new bookmark:" << "parent not found"; + return false; + } + auto item = new BookmarkItem(type); + item->setTitle(title); + item->setUrl(QUrl::fromEncoded(urlString.toUtf8())); + item->setDescription(description); + mApp->bookmarks()->addBookmark(parent, item); + return true; +} + +bool QmlBookmarks::remove(QmlBookmarkTreeNode *treeNode) const +{ + auto item = getBookmarkItem(treeNode); + if (!item) { + qWarning() << "Unable to remove bookmark:" <<"BookmarkItem not found"; + return false; + } + return mApp->bookmarks()->removeBookmark(item); +} + +QList QmlBookmarks::search(const QVariantMap &map) const +{ + if (!map.contains(QSL("query")) && !map.contains(QSL("url"))) { + qWarning() << "Unable to search bookmarks"; + return QList(); + } + + const QString query = map.value(QSL("query")).toString(); + const QString urlString = map.value(QSL("url")).toString(); + QList items; + if (urlString.isEmpty()) { + items = mApp->bookmarks()->searchBookmarks(query); + } else { + items = mApp->bookmarks()->searchBookmarks(QUrl::fromEncoded(urlString.toUtf8())); + } + QList ret; + ret.reserve(items.size()); + for (auto item : qAsConst(items)) { + ret.append(QmlStaticData::instance().getBookmarkTreeNode(item)); + } + return ret; +} + +bool QmlBookmarks::update(QObject *object, const QVariantMap &changes) const +{ + auto treeNode = qobject_cast(object); + if (!treeNode) { + qWarning() << "Unable to update bookmark:" << "unable to cast QVariant to QmlBookmarkTreeNode"; + return false; + } + + auto item = getBookmarkItem(treeNode); + if (!item) { + qWarning() << "Unable to update bookmark:" << "bookmark not found"; + return false; + } + + if (!mApp->bookmarks()->canBeModified(item)) { + qWarning() << "Unable to update bookmark:" << "bookmark can not be modified"; + } + + QString newTitle = treeNode->title(); + if (changes.contains(QSL("title"))) { + newTitle = changes.value(QSL("title")).toString(); + } + QString newDescription = treeNode->description(); + if (changes.contains(QSL("description"))) { + newDescription = changes.value(QSL("description")).toString(); + } + QString newKeyword = treeNode->keyword(); + if (changes.contains(QSL("keyword"))) { + newKeyword = changes.value(QSL("keyword")).toString(); + } + + item->setTitle(newTitle); + item->setDescription(newDescription); + item->setKeyword(newKeyword); + mApp->bookmarks()->changeBookmark(item); + return true; +} + +QmlBookmarkTreeNode *QmlBookmarks::get(const QString &string) const +{ + const QList items = mApp->bookmarks()->searchBookmarks(QUrl(string)); + for (BookmarkItem *item : items) { + if (item->urlString() == string) { + return QmlStaticData::instance().getBookmarkTreeNode(item); + } + } + + return nullptr; +} + +QList QmlBookmarks::getChildren(QObject *object) const +{ + QList ret; + + auto bookmarkItem = getBookmarkItem(object); + if (!bookmarkItem) { + qWarning() << "Unable to get children:" << "parent not found"; + return ret; + } + + const QList items = bookmarkItem->children(); + for (BookmarkItem *item : items) { + ret.append(QmlStaticData::instance().getBookmarkTreeNode(item)); + } + + return ret; +} diff --git a/src/lib/plugins/qml/api/bookmarks/qmlbookmarks.h b/src/lib/plugins/qml/api/bookmarks/qmlbookmarks.h new file mode 100644 index 000000000..fd86cac0a --- /dev/null +++ b/src/lib/plugins/qml/api/bookmarks/qmlbookmarks.h @@ -0,0 +1,155 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "qmlbookmarktreenode.h" +#include "mainapplication.h" + +#include + +/** + * @brief The class exposing the Bookmarks API to QML + */ +class QmlBookmarks : public QObject +{ + Q_OBJECT + +public: + explicit QmlBookmarks(QObject *parent = nullptr); + + /** + * @brief Checks if the url is bookmarked + * @param String representing the url to check + * @return true if bookmarked, else false + */ + Q_INVOKABLE bool isBookmarked(const QString &url) const; + /** + * @brief Get the root bookmark item + * @return Root boomkark item + */ + Q_INVOKABLE QmlBookmarkTreeNode *rootItem() const; + /** + * @brief Get the bookmarks toolbar + * @return Bookmarks toolbar + */ + Q_INVOKABLE QmlBookmarkTreeNode *toolbarFolder() const; + /** + * @brief Get the bookmarks menu folder + * @return Bookmarks menu folder + */ + Q_INVOKABLE QmlBookmarkTreeNode *menuFolder() const; + /** + * @brief Get the unsorted bookmarks folder + * @return Unsorted bookmarks folder + */ + Q_INVOKABLE QmlBookmarkTreeNode *unsortedFolder() const; + /** + * @brief Get the last used bookmarks folder + * @return Last used bookmarks folder + */ + Q_INVOKABLE QmlBookmarkTreeNode *lastUsedFolder() const; + /** + * @brief Creates a bookmark item + * @param A JavaScript object containing + * - parent: + * Object of type [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode), representing + * the parent of the new bookmark item. This is required field. + * - title: + * String representing the title of the new bookmark item. Defaults to empty string + * - url: + * String representing the url of the new bookmark item. Defaults to empty string + * - description + * String representing the description of the new bookmark item. Defaults to empty string + * - type: + * [Type](@ref QmlBookmarkTreeNode::Type) representing the type of the new bookmark item. + * Defaults to [Url](@ref QmlBookmarkTreeNode::Url) if url is provided, else + * [Folder](@ref QmlBookmarkTreeNode::Folder) if title is provided, else + * [Invalid](@ref QmlBookmarkTreeNode::Invalid) + * @return true if the bookmark it created, else false + */ + Q_INVOKABLE bool create(const QVariantMap &map) const; + /** + * @brief Removes a bookmark item + * @param treeNode: + * Object of type [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode) to be removed + * @return true if the bookmark is removed, else false + */ + Q_INVOKABLE bool remove(QmlBookmarkTreeNode *treeNode) const; + /** + * @brief QmlBookmarks::search + * @param A JavaScript object containing + * - query: + * String containing search query + * - url: + * String representing url to be search + * @return List containing [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode). If both + * query and url are not supplied then empty list is returned. + */ + Q_INVOKABLE QList search(const QVariantMap &map) const; + /** + * @brief Updates a bookmark item + * @param Object of type [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode), representing the bookmark + * to update + * @param JavaScript object containing the values to be updated + * - title: + * String representing the new title of the bookmark item + * - description: + * String representing the new description of the bookmark item + * - keyword: + * String representing the new keyword of the bookmark item + * @return true if the bookmark is updated, else false + */ + Q_INVOKABLE bool update(QObject *object, const QVariantMap &changes) const; + /** + * @brief Get the first matched bookmark item + * @param String representing the query + * @return Object of type [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode) if + * the query is matched with a bookmark, else null + */ + Q_INVOKABLE QmlBookmarkTreeNode *get(const QString &string) const; + /** + * @brief Get children of the bookmark item + * @param Object of type [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode), representing + * the parent whose children are requested. + * @return List containing the children, of type [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode) + */ + Q_INVOKABLE QList getChildren(QObject *object) const; + +Q_SIGNALS: + /** + * @brief This signal is emitted when a new bookmark item is created + * @param bookmark item, exposed to QML as [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode) + */ + void created(QmlBookmarkTreeNode *treeNode); + + /** + * @brief This signal is emitted when a bookmark item is edited + * @param bookmark item, exposed to QML as [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode) + */ + void changed(QmlBookmarkTreeNode *treeNode); + + /** + * @brief This signal is emitted when a bookmark item is removed + * @param bookmark item, exposed to QML as [QmlBookmarkTreeNode](@ref QmlBookmarkTreeNode) + */ + void removed(QmlBookmarkTreeNode *treeNode); + +private: + BookmarkItem *getBookmarkItem(QmlBookmarkTreeNode *treeNode) const; + BookmarkItem *getBookmarkItem(QObject *object) const; +}; diff --git a/src/lib/plugins/qml/api/bookmarks/qmlbookmarktreenode.cpp b/src/lib/plugins/qml/api/bookmarks/qmlbookmarktreenode.cpp new file mode 100644 index 000000000..52cde3227 --- /dev/null +++ b/src/lib/plugins/qml/api/bookmarks/qmlbookmarktreenode.cpp @@ -0,0 +1,128 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlbookmarktreenode.h" +#include "mainapplication.h" +#include "bookmarks.h" +#include "qml/qmlstaticdata.h" +#include + +QmlBookmarkTreeNode::QmlBookmarkTreeNode(BookmarkItem *item) + : m_item(item) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +BookmarkItem *QmlBookmarkTreeNode::item() +{ + return m_item; +} + +QmlBookmarkTreeNode::Type QmlBookmarkTreeNode::type() const +{ + if (!m_item) { + return Invalid; + } + + switch (m_item->type()) { + case BookmarkItem::Root: + return Root; + + case BookmarkItem::Url: + return Url; + + case BookmarkItem::Folder: + return Folder; + + case BookmarkItem::Separator: + return Separator; + + case BookmarkItem::Invalid: + default: + return Invalid; + } +} + +QString QmlBookmarkTreeNode::title() const +{ + if (!m_item) { + return QString(); + } + + return m_item->title(); +} + +QString QmlBookmarkTreeNode::url() const +{ + if (!m_item) { + return QString(); + } + + return m_item->urlString(); +} + +QString QmlBookmarkTreeNode::description() const +{ + if (!m_item) { + return QString(); + } + + return m_item->description(); +} + +QString QmlBookmarkTreeNode::keyword() const +{ + if (!m_item) { + return QString(); + } + + return m_item->keyword(); +} + +int QmlBookmarkTreeNode::visitCount() const +{ + if (!m_item) { + return 0; + } + + return m_item->visitCount(); +} + +QmlBookmarkTreeNode *QmlBookmarkTreeNode::parent() const +{ + if (!m_item) { + return nullptr; + } + + return QmlStaticData::instance().getBookmarkTreeNode(m_item->parent()); +} + +bool QmlBookmarkTreeNode::unmodifiable() const +{ + return !mApp->bookmarks()->canBeModified(m_item); +} + +QList QmlBookmarkTreeNode::children() const +{ + const QList items = m_item->children(); + QList ret; + ret.reserve(items.size()); + for (BookmarkItem *item : items) { + ret.append(QmlStaticData::instance().getBookmarkTreeNode(item)); + } + return ret; +} diff --git a/src/lib/plugins/qml/api/bookmarks/qmlbookmarktreenode.h b/src/lib/plugins/qml/api/bookmarks/qmlbookmarktreenode.h new file mode 100644 index 000000000..4bc2532c8 --- /dev/null +++ b/src/lib/plugins/qml/api/bookmarks/qmlbookmarktreenode.h @@ -0,0 +1,104 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once +#include "bookmarkitem.h" + +/** + * @brief The class exposing the bookmark item to QML + */ +class QmlBookmarkTreeNode : public QObject +{ + Q_OBJECT + + /** + * @brief type of bookmark tree node. + */ + Q_PROPERTY(Type type READ type CONSTANT) + + /** + * @brief title of bookmark tree node. + */ + Q_PROPERTY(QString title READ title CONSTANT) + + /** + * @brief url of bookmark tree node. + */ + Q_PROPERTY(QString url READ url CONSTANT) + + /** + * @brief description of bookmark tree node. + */ + Q_PROPERTY(QString description READ description CONSTANT) + + /** + * @brief keyword of bookmark tree node. + */ + Q_PROPERTY(QString keyword READ keyword CONSTANT) + + /** + * @brief visit count of bookmark tree node. + */ + Q_PROPERTY(int visitCount READ visitCount CONSTANT) + + /** + * @brief parent of bookmark tree node. + */ + Q_PROPERTY(QmlBookmarkTreeNode* parent READ parent CONSTANT) + + /** + * @brief checks if bookmark tree node is unmodifiable. + */ + Q_PROPERTY(bool unmodifiable READ unmodifiable CONSTANT) + + /** + * @brief gets children of bookmark tree node. + */ + Q_PROPERTY(QList children READ children CONSTANT) + +public: + /** + * @brief The Type enum + * + * Contains the information of the type of the bookmark item, + */ + enum Type { + Root = BookmarkItem::Root, //!< Represents the root bookmark item + Url = BookmarkItem::Url, //!< Represents the single bookmark item of type url + Folder = BookmarkItem::Folder, //!< Represents the bookmark folder + Separator = BookmarkItem::Separator, //!< Represents the bookmark seperator + Invalid = BookmarkItem::Invalid //!< Represents invalid bookmark item + }; + Q_ENUM(Type) + + explicit QmlBookmarkTreeNode(BookmarkItem *item = nullptr); + + BookmarkItem *item(); + Type type() const; + QString title() const; + QString url() const; + QString description() const; + QString keyword() const; + +private: + BookmarkItem *m_item = nullptr; + + int visitCount() const; + QmlBookmarkTreeNode *parent() const; + bool unmodifiable() const; + QList children() const; +}; diff --git a/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp b/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp new file mode 100644 index 000000000..d9d1b2311 --- /dev/null +++ b/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp @@ -0,0 +1,263 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlbrowseraction.h" +#include "qztools.h" +#include "navigationbar.h" +#include "statusbar.h" +#include "pluginproxy.h" +#include "qml/api/fileutils/qmlfileutils.h" +#include "qml/qmlengine.h" +#include "qml/qmlstaticdata.h" +#include +#include + +QmlBrowserAction::QmlBrowserAction(QObject *parent) + : QObject(parent) +{ + m_button = new QmlBrowserActionButton(); + + connect(this, &QmlBrowserAction::identityChanged, m_button, &QmlBrowserActionButton::setId); + connect(this, &QmlBrowserAction::nameChanged, m_button, &QmlBrowserActionButton::setName); + connect(this, &QmlBrowserAction::titleChanged, m_button, &QmlBrowserActionButton::setTitle); + connect(this, &QmlBrowserAction::toolTipChanged, m_button, &QmlBrowserActionButton::setToolTip); + connect(this, &QmlBrowserAction::iconChanged, m_button, &QmlBrowserActionButton::setIcon); + connect(this, &QmlBrowserAction::badgeTextChanged, m_button, &QmlBrowserActionButton::setBadgeText); + connect(this, &QmlBrowserAction::popupChanged, m_button, &QmlBrowserActionButton::setPopup); + + connect(m_button, &QmlBrowserActionButton::clicked, this, &QmlBrowserAction::clicked); + + connect(mApp->plugins(), &PluginProxy::mainWindowCreated, this, &QmlBrowserAction::addButton); +} + +void QmlBrowserAction::componentComplete() +{ + const QList windows = mApp->windows(); + for (BrowserWindow *window : windows) { + addButton(window); + } +} + +QmlBrowserAction::~QmlBrowserAction() +{ + const QList windows = mApp->windows(); + for (BrowserWindow *window : windows) { + removeButton(window); + } +} + +QmlBrowserActionButton *QmlBrowserAction::button() const +{ + return m_button; +} + +QmlBrowserAction::Locations QmlBrowserAction::location() const +{ + return m_locations; +} + +QString QmlBrowserAction::identity() const +{ + return m_identity; +} + +void QmlBrowserAction::setIdentity(const QString &identity) +{ + m_identity = identity; + emit identityChanged(m_identity); +} + +QString QmlBrowserAction::name() const +{ + return m_name; +} + +void QmlBrowserAction::setName(const QString &name) +{ + m_name = name; + emit nameChanged(m_name); +} + +QString QmlBrowserAction::title() const +{ + return m_title; +} + +void QmlBrowserAction::setTitle(const QString &title) +{ + m_title = title; + emit titleChanged(m_title); +} + +QString QmlBrowserAction::toolTip() const +{ + return m_toolTip; +} + +void QmlBrowserAction::setToolTip(const QString &toolTip) +{ + m_toolTip = toolTip; + emit toolTipChanged(m_toolTip); +} + +QString QmlBrowserAction::icon() const +{ + return m_icon; +} + +void QmlBrowserAction::setIcon(const QString &icon) +{ + m_icon = icon; + emit iconChanged(m_icon); +} + +QString QmlBrowserAction::badgeText() const +{ + return m_badgeText; +} + +void QmlBrowserAction::setBadgeText(const QString &badgeText) +{ + m_badgeText = badgeText; + emit badgeTextChanged(m_badgeText); +} + +QQmlComponent* QmlBrowserAction::popup() const +{ + return m_popup; +} + +void QmlBrowserAction::setPopup(QQmlComponent* popup) +{ + m_popup = popup; + emit popupChanged(m_popup); +} + +void QmlBrowserAction::setLocation(const Locations &locations) +{ + m_locations = locations; + emit locationChanged(m_locations); +} + +void QmlBrowserAction::addButton(BrowserWindow *window) +{ + if (location().testFlag(NavigationToolBar)) { + window->navigationBar()->addToolButton(button()); + } + + if (location().testFlag(StatusBar)) { + window->statusBar()->addButton(button()); + } +} + +void QmlBrowserAction::removeButton(BrowserWindow *window) +{ + if (location().testFlag(NavigationToolBar)) { + window->navigationBar()->removeToolButton(button()); + } + + if (location().testFlag(StatusBar)) { + window->statusBar()->removeButton(button()); + } +} + +QmlBrowserActionButton::QmlBrowserActionButton(QObject *parent) + : AbstractButtonInterface(parent) +{ + connect(this, &AbstractButtonInterface::clicked, this, &QmlBrowserActionButton::positionPopup); +} + +QString QmlBrowserActionButton::id() const +{ + return m_id; +} + +void QmlBrowserActionButton::setId(const QString &id) +{ + m_id = id; +} + +QString QmlBrowserActionButton::name() const +{ + return m_name; +} + +void QmlBrowserActionButton::setName(const QString &name) +{ + m_name = name; +} + +void QmlBrowserActionButton::setTitle(const QString &title) +{ + AbstractButtonInterface::setTitle(title); +} + +void QmlBrowserActionButton::setToolTip(const QString &toolTip) +{ + AbstractButtonInterface::setToolTip(toolTip); +} + +void QmlBrowserActionButton::setIcon(const QString &icon) +{ + m_iconUrl = icon; + if (!m_popup) { + return; + } + auto qmlEngine = qobject_cast(m_popup->creationContext()->engine()); + if (!qmlEngine) { + return; + } + const QString pluginPath = qmlEngine->extensionPath(); + QIcon qicon = QmlStaticData::instance().getIcon(m_iconUrl, pluginPath); + AbstractButtonInterface::setIcon(qicon); +} + +void QmlBrowserActionButton::setBadgeText(const QString &badgeText) +{ + AbstractButtonInterface::setBadgeText(badgeText); +} + +void QmlBrowserActionButton::setPopup(QQmlComponent *popup) +{ + m_popup = popup; +} + +void QmlBrowserActionButton::positionPopup(ClickController *clickController) +{ + if (!m_popup) { + qWarning() << "No popup to show"; + return; + } + + QQuickWindow *quickWindow = qobject_cast(m_popup->create(m_popup->creationContext())); + if (!quickWindow) { + qWarning() << "Cannot create QQuickWindow from popup"; + return; + } + quickWindow->setFlags(Qt::Popup); + quickWindow->setPosition(clickController->callPopupPosition(quickWindow->size())); + + connect(quickWindow, &QQuickWindow::activeChanged, this, [quickWindow, clickController]{ + if (!quickWindow->isActive()) { + quickWindow->destroy(); + clickController->callPopupClosed(); + } + }); + + quickWindow->show(); + quickWindow->requestActivate(); +} diff --git a/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.h b/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.h new file mode 100644 index 000000000..c9084a0ef --- /dev/null +++ b/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.h @@ -0,0 +1,211 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once +#include "abstractbuttoninterface.h" +#include "mainapplication.h" +#include +#include + +class QmlBrowserActionButton; + +/** + * @brief The class exposing BrowserAction API to QML + */ +class QmlBrowserAction : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + /** + * @brief identity for the button. This is a required property. + */ + Q_PROPERTY(QString identity READ identity WRITE setIdentity NOTIFY identityChanged) + + /** + * @brief name of the button. This is a required property. + */ + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + + /** + * @brief title of the button. + */ + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + + /** + * @brief tool tip of the button. + */ + Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged) + + /** + * @brief icon path of button + * + * The icon path will be search in the following order + * - Theme icon: if the icon is found as a theme icon, then it will + * be used even if the icon file with same name is present + * in the plugin directory + * - Falkon resource: for the icons starting with ":", they are searched in + * falkon resource file + * - Files in plugin directory: All other paths will be resolved relative to + * the plugin directory. If the icon path is outside the + * plugin directory, then it will be resolved as empty path. + */ + Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged) + + /** + * @brief badge text of the button + */ + Q_PROPERTY(QString badgeText READ badgeText WRITE setBadgeText NOTIFY badgeTextChanged) + + /** + * @brief the popup shown when the button is clicked. This must be a QML Window. + */ + Q_PROPERTY(QQmlComponent* popup READ popup WRITE setPopup NOTIFY popupChanged) + + /** + * @brief represents locations where the button is to be added. + */ + Q_PROPERTY(Locations location READ location WRITE setLocation NOTIFY locationChanged) + +public: + /** + * @brief The Location enum + */ + enum Location { + NavigationToolBar = 0x1, //!< to add the button in navigation tool bar + StatusBar = 0x2 //!< to add the button in status bar + }; + Q_DECLARE_FLAGS(Locations, Location) + Q_ENUM(Locations) + + explicit QmlBrowserAction(QObject *parent = nullptr); + ~QmlBrowserAction(); + void classBegin() {} + void componentComplete(); + QmlBrowserActionButton *button() const; + Locations location() const; + +Q_SIGNALS: + /** + * @brief This signal is emitted when identity property is changed + * @param QString representing identity + */ + void identityChanged(const QString &identity); + + /** + * @brief This signal is emitted when name property is changed + * @param QString representing name + */ + void nameChanged(const QString &name); + + /** + * @brief This signal is emitted when title property is changed + * @param QString representing title + */ + void titleChanged(const QString &title); + + /** + * @brief This signal is emitted when the toolTip property is changed + * @param QString representing toolTip + */ + void toolTipChanged(const QString &toolTip); + + /** + * @brief This signal is emitted when the icon property is changed + * @param QString representing icon + */ + void iconChanged(const QString &icon); + + /** + * @brief This signal is emitted when the badgeText property is changed + * @param QString representing badgeText + */ + void badgeTextChanged(const QString &badgeText); + + /** + * @brief This signal is emitted when the popup property is changed + * @param QQmComponent representing popup + */ + void popupChanged(QQmlComponent *popup); + + /** + * @brief This signal is emitted when the locations property is changed + * @param locations + */ + void locationChanged(const Locations &locations); + + /** + * @brief This signal is emitted when the button is clicked + */ + void clicked(); + +private: + QString m_identity; + QString m_name; + QString m_title; + QString m_toolTip; + QString m_icon; + QString m_badgeText; + QQmlComponent* m_popup = nullptr; + Locations m_locations = NavigationToolBar; + QmlBrowserActionButton *m_button = nullptr; + + QString identity() const; + void setIdentity(const QString &identity); + QString name() const; + void setName(const QString &name); + QString title() const; + void setTitle(const QString &title); + QString toolTip() const; + void setToolTip(const QString &toolTip); + QString icon() const; + void setIcon(const QString &icon); + QString badgeText() const; + void setBadgeText(const QString &badgeText); + QQmlComponent* popup() const; + void setPopup(QQmlComponent* popup); + void setLocation(const Locations &locations); + + void addButton(BrowserWindow *window); + void removeButton(BrowserWindow *window); +}; + +class QmlBrowserActionButton : public AbstractButtonInterface +{ + Q_OBJECT +public: + explicit QmlBrowserActionButton(QObject *parent = nullptr); + QString id() const; + void setId(const QString &id); + QString name() const; + void setName(const QString &name); + void setTitle(const QString &title); + void setToolTip(const QString &toolTip); + void setIcon(const QString &icon); + void setBadgeText(const QString &badgeText); + void setPopup(QQmlComponent *popup); + + void positionPopup(ClickController *clickController); + +private: + QString m_id; + QString m_name; + QString m_iconUrl; + QQmlComponent *m_popup = nullptr; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlBrowserAction::Locations) diff --git a/src/lib/plugins/qml/api/clipboard/qmlclipboard.cpp b/src/lib/plugins/qml/api/clipboard/qmlclipboard.cpp new file mode 100644 index 000000000..ffe6314d8 --- /dev/null +++ b/src/lib/plugins/qml/api/clipboard/qmlclipboard.cpp @@ -0,0 +1,31 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlclipboard.h" +#include "mainapplication.h" +#include +#include + +QmlClipboard::QmlClipboard(QObject *parent) + : QObject(parent) +{ +} + +void QmlClipboard::copy(const QString &text) +{ + mApp->clipboard()->setText(text); +} diff --git a/src/lib/plugins/qml/api/clipboard/qmlclipboard.h b/src/lib/plugins/qml/api/clipboard/qmlclipboard.h new file mode 100644 index 000000000..5e2cbbccf --- /dev/null +++ b/src/lib/plugins/qml/api/clipboard/qmlclipboard.h @@ -0,0 +1,36 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +/** + * @brief The class exposing application + * clipboard to QML + */ +class QmlClipboard : public QObject +{ + Q_OBJECT +public: + explicit QmlClipboard(QObject *parent = nullptr); + /** + * @brief Copy the string to clipboard + * @param String representing the text to be copied + */ + Q_INVOKABLE void copy(const QString &text); +}; diff --git a/src/lib/plugins/qml/api/cookies/qmlcookie.cpp b/src/lib/plugins/qml/api/cookies/qmlcookie.cpp new file mode 100644 index 000000000..d653824fa --- /dev/null +++ b/src/lib/plugins/qml/api/cookies/qmlcookie.cpp @@ -0,0 +1,82 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlcookie.h" +#include + +QmlCookie::QmlCookie(QNetworkCookie *cookie, QObject *parent) + : QObject(parent) + , m_cookie(cookie) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +QString QmlCookie::domain() const +{ + if (!m_cookie) { + return QString(); + } + return m_cookie->domain(); +} + +QDateTime QmlCookie::expirationDate() const +{ + if (!m_cookie) { + return QDateTime(); + } + return m_cookie->expirationDate(); +} + +QString QmlCookie::name() const +{ + if (!m_cookie) { + return QString(); + } + return QString(m_cookie->name()); +} + +QString QmlCookie::path() const +{ + if (!m_cookie) { + return QString(); + } + return m_cookie->path(); +} + +bool QmlCookie::secure() const +{ + if (!m_cookie) { + return false; + } + return m_cookie->isSecure(); +} + +bool QmlCookie::session() const +{ + if (!m_cookie) { + return false; + } + return m_cookie->isSessionCookie(); +} + +QString QmlCookie::value() const +{ + if (!m_cookie) { + return QString(); + } + return QString(m_cookie->value()); +} diff --git a/src/lib/plugins/qml/api/cookies/qmlcookie.h b/src/lib/plugins/qml/api/cookies/qmlcookie.h new file mode 100644 index 000000000..6b3e18dfd --- /dev/null +++ b/src/lib/plugins/qml/api/cookies/qmlcookie.h @@ -0,0 +1,80 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include +#include + +/** + * @brief The class exposing QNetworkCookie to QML + */ +class QmlCookie : public QObject +{ + Q_OBJECT + + /** + * @brief domain of the cookie + */ + Q_PROPERTY(QString domain READ domain CONSTANT) + + /** + * @brief expiration date of the cookie + */ + Q_PROPERTY(QDateTime expirationDate READ expirationDate CONSTANT) + + /** + * @brief name of the cookie + */ + Q_PROPERTY(QString name READ name CONSTANT) + + /** + * @brief path of the cookie + */ + Q_PROPERTY(QString path READ path CONSTANT) + + /** + * @brief checks if cookie is secure + */ + Q_PROPERTY(bool secure READ secure CONSTANT) + + /** + * @brief checks if cookie is a session cookie + */ + Q_PROPERTY(bool session READ session CONSTANT) + + /** + * @brief value of the cookie + */ + Q_PROPERTY(QString value READ value CONSTANT) +public: + explicit QmlCookie(QNetworkCookie *cookie, QObject *parent = nullptr); + +private: + QNetworkCookie *m_cookie = nullptr; + + QString domain() const; + QDateTime expirationDate() const; + QString name() const; + QString path() const; + bool secure() const; + bool session() const; + QString value() const; +}; + +Q_DECLARE_METATYPE(QmlCookie*) diff --git a/src/lib/plugins/qml/api/cookies/qmlcookies.cpp b/src/lib/plugins/qml/api/cookies/qmlcookies.cpp new file mode 100644 index 000000000..79e1621a0 --- /dev/null +++ b/src/lib/plugins/qml/api/cookies/qmlcookies.cpp @@ -0,0 +1,114 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlcookies.h" +#include "mainapplication.h" +#include "cookiejar.h" +#include "qwebengineprofile.h" +#include "qml/qmlstaticdata.h" +#include + +QmlCookies::QmlCookies(QObject *parent) + : QObject(parent) +{ + connect(mApp->cookieJar(), &CookieJar::cookieAdded, this, [this](const QNetworkCookie &network_cookie){ + QmlCookie *cookie = QmlStaticData::instance().getCookie(network_cookie); + QVariantMap map; + map.insert(QSL("cookie"), QVariant::fromValue(cookie)); + map.insert(QSL("removed"), false); + emit changed(map); + }); + + connect(mApp->cookieJar(), &CookieJar::cookieRemoved, this, [this](QNetworkCookie network_cookie){ + QmlCookie *cookie = QmlStaticData::instance().getCookie(network_cookie); + QVariantMap map; + map.insert(QSL("cookie"), QVariant::fromValue(cookie)); + map.insert(QSL("removed"), true); + emit changed(map); + }); +} + +QNetworkCookie QmlCookies::getNetworkCookie(const QVariantMap &map) +{ + if (!map.contains(QSL("name")) || !map.contains(QSL("url"))) { + qWarning() << "Error:" << "Wrong arguments passed to" << __FUNCTION__; + return QNetworkCookie(); + } + const QString name = map.value(QSL("name")).toString(); + const QString url = map.value(QSL("url")).toString(); + QVector cookies = mApp->cookieJar()->getAllCookies(); + for (const QNetworkCookie &cookie : qAsConst(cookies)) { + if (cookie.name() == name && cookie.domain() == url) { + return cookie; + } + } + return QNetworkCookie(); +} + +QmlCookie *QmlCookies::get(const QVariantMap &map) +{ + QNetworkCookie netCookie = getNetworkCookie(map); + return QmlStaticData::instance().getCookie(netCookie); +} + +QList QmlCookies::getAll(const QVariantMap &map) +{ + QList qmlCookies; + const QString name = map.value(QSL("name")).toString(); + const QString url = map.value(QSL("url")).toString(); + const QString path = map.value(QSL("path")).toString(); + const bool secure = map.value(QSL("secure")).toBool(); + const bool session = map.value(QSL("session")).toBool(); + QVector cookies = mApp->cookieJar()->getAllCookies(); + for (QNetworkCookie cookie : qAsConst(cookies)) { + if ((!map.contains(QSL("name")) || cookie.name() == name) + && (!map.contains(QSL("url")) || cookie.domain() == url) + && (!map.contains(QSL("path")) || cookie.path() == path) + && (!map.contains(QSL("secure")) || cookie.isSecure() == secure) + && (!map.contains(QSL("session")) || cookie.isSessionCookie() == session)) { + QmlCookie *qmlCookie = QmlStaticData::instance().getCookie(cookie); + qmlCookies.append(qmlCookie); + } + } + return qmlCookies; +} + +void QmlCookies::set(const QVariantMap &map) +{ + const QString name = map.value(QSL("name")).toString(); + const QString url = map.value(QSL("url")).toString(); + const QString path = map.value(QSL("path")).toString(); + const bool secure = map.value(QSL("secure")).toBool(); + const QDateTime expirationDate = QDateTime::fromMSecsSinceEpoch(map.value(QSL("expirationDate")).toDouble()); + const bool httpOnly = map.value(QSL("httpOnly")).toBool(); + const QString value = map.value(QSL("value")).toString(); + QNetworkCookie cookie; + cookie.setName(name.toUtf8()); + cookie.setDomain(url); + cookie.setPath(path); + cookie.setSecure(secure); + cookie.setExpirationDate(expirationDate); + cookie.setHttpOnly(httpOnly); + cookie.setValue(value.toUtf8()); + mApp->webProfile()->cookieStore()->setCookie(cookie); +} + +void QmlCookies::remove(const QVariantMap &map) +{ + QNetworkCookie netCookie = getNetworkCookie(map); + mApp->webProfile()->cookieStore()->deleteCookie(netCookie); +} diff --git a/src/lib/plugins/qml/api/cookies/qmlcookies.h b/src/lib/plugins/qml/api/cookies/qmlcookies.h new file mode 100644 index 000000000..7c3dff678 --- /dev/null +++ b/src/lib/plugins/qml/api/cookies/qmlcookies.h @@ -0,0 +1,98 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "qmlcookie.h" + +/** + * @brief The class exposing Cookies API to QML + */ +class QmlCookies : public QObject +{ + Q_OBJECT +public: + explicit QmlCookies(QObject *parent = nullptr); + /** + * @brief Get a cookie + * @param A JavaScript object containing + * - name: + * String representing the name of the cookie + * - url: + * String representing the url of the cookie + * @return Cookie of type [QmlCookie](@ref QmlCookie) + * if such cookie exists, else null + */ + Q_INVOKABLE QmlCookie *get(const QVariantMap &map); + /** + * @brief Get all cookies matching a criteria + * @param A JavaScript object containing + * - name: + * String representing the name of the cookie + * - url: + * String representing the url of the cookie + * - path: + * String representing the path of the cookie + * - secure: + * Bool representing if the cookie is secure + * - session: + * Bool representing if the cookie is a session cookie + * @return List containing cookies, each of type [QmlCookie](@ref QmlCookie) + */ + Q_INVOKABLE QList getAll(const QVariantMap &map); + /** + * @brief Set a cookie + * @param A JavaScript object containing + * - name: + * String representing the name of the cookie + * - url: + * String representing the name of the cookie + * - path: + * String representing the path of the cookie + * - secure: + * Bool representing if the cookie is secure + * - expirationDate: + * A JavaScript Date object, representing the expiration date of the cookie + * - httpOnly: + * Bool representing if the cookie is httpOnly + * - value: + * String representing the value of the cookie + */ + Q_INVOKABLE void set(const QVariantMap &map); + /** + * @brief Remove a cookie + * @param A JavaScript object containing + * - name: + * String representing the name of the cookie + * - url: + * String representing the url of the cookie + */ + Q_INVOKABLE void remove(const QVariantMap &map); +Q_SIGNALS: + /** + * @brief The signal emitted when a cookie is added or removed + * @param A JavaScript object containing + * - cookie: + * Object of type [QmlCookie](@ref QmlCookie), which is added or removed + * - removed: + * Bool representing if the cookie is removed + */ + void changed(const QVariantMap &map); +private: + QNetworkCookie getNetworkCookie(const QVariantMap &map); +}; diff --git a/src/lib/plugins/qml/api/events/qmlkeyevent.cpp b/src/lib/plugins/qml/api/events/qmlkeyevent.cpp new file mode 100644 index 000000000..e89fa51aa --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlkeyevent.cpp @@ -0,0 +1,94 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlkeyevent.h" +#include + +QmlKeyEvent::QmlKeyEvent(QKeyEvent *keyEvent, QObject *parent) + : QObject(parent) + , m_keyEvent(keyEvent) +{ +} + +int QmlKeyEvent::count() const +{ + if (!m_keyEvent) { + return -1; + } + return m_keyEvent->count(); +} + +bool QmlKeyEvent::isAutoRepeat() const +{ + if (!m_keyEvent) { + return false; + } + return m_keyEvent->isAutoRepeat(); +} + +int QmlKeyEvent::key() const +{ + if (!m_keyEvent) { + return -1; + } + return m_keyEvent->key(); +} + +int QmlKeyEvent::modifiers() const +{ + if (!m_keyEvent) { + return -1; + } + return static_cast(m_keyEvent->modifiers()); +} + +quint32 QmlKeyEvent::nativeModifiers() const +{ + if (!m_keyEvent) { + return -1; + } + return m_keyEvent->nativeModifiers(); +} + +quint32 QmlKeyEvent::nativeScanCode() const +{ + if (!m_keyEvent) { + return -1; + } + return m_keyEvent->nativeScanCode(); +} + +quint32 QmlKeyEvent::nativeVirtualKey() const +{ + if (!m_keyEvent) { + return -1; + } + return m_keyEvent->nativeVirtualKey(); +} + +QString QmlKeyEvent::text() const +{ + if (!m_keyEvent) { + return QString(); + } + return m_keyEvent->text(); +} + +void QmlKeyEvent::clear() +{ + m_keyEvent = nullptr; +} diff --git a/src/lib/plugins/qml/api/events/qmlkeyevent.h b/src/lib/plugins/qml/api/events/qmlkeyevent.h new file mode 100644 index 000000000..dd41b6a4d --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlkeyevent.h @@ -0,0 +1,76 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include + +/** + * @brief The class exposing KeyEvent to QML + */ +class QmlKeyEvent : public QObject +{ + Q_OBJECT + /** + * @brief number of keys involved in this event + */ + Q_PROPERTY(int count READ count CONSTANT) + /** + * @brief checks if the event comes from an auto-repeating key + */ + Q_PROPERTY(bool autoRepeat READ isAutoRepeat CONSTANT) + /** + * @brief key code which is pressed/released + */ + Q_PROPERTY(int key READ key CONSTANT) + /** + * @brief modifiers associated with the event + */ + Q_PROPERTY(int modifiers READ modifiers CONSTANT) + /** + * @brief native modifiers of the event + */ + Q_PROPERTY(quint32 nativeModifiers READ nativeModifiers CONSTANT) + /** + * @brief native scan code of the event + */ + Q_PROPERTY(quint32 nativeScanCode READ nativeScanCode CONSTANT) + /** + * @brief native virtual key, or key sum of the event + */ + Q_PROPERTY(quint32 nativeVirtualKey READ nativeVirtualKey CONSTANT) + /** + * @brief Returns the Unicode text that this key generated + */ + Q_PROPERTY(QString text READ text CONSTANT) +public: + explicit QmlKeyEvent(QKeyEvent *keyEvent = nullptr, QObject *parent = nullptr); + int count() const; + bool isAutoRepeat() const; + int key() const; + int modifiers() const; + quint32 nativeModifiers() const; + quint32 nativeScanCode() const; + quint32 nativeVirtualKey() const; + QString text() const; + + void clear(); + +private: + QKeyEvent *m_keyEvent = nullptr; +}; diff --git a/src/lib/plugins/qml/api/events/qmlmouseevent.cpp b/src/lib/plugins/qml/api/events/qmlmouseevent.cpp new file mode 100644 index 000000000..5c96b62a9 --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlmouseevent.cpp @@ -0,0 +1,126 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlmouseevent.h" +#include + +QmlMouseEvent::QmlMouseEvent(QMouseEvent *mouseEvent, QObject *parent) + : QObject(parent) + , m_mouseEvent(mouseEvent) +{ +} + +int QmlMouseEvent::button() const +{ + if (!m_mouseEvent) { + return -1; + } + return static_cast(m_mouseEvent->button()); +} + +int QmlMouseEvent::buttons() const +{ + if (!m_mouseEvent) { + return -1; + } + return static_cast(m_mouseEvent->buttons()); +} + +QPoint QmlMouseEvent::globalPos() const +{ + if (!m_mouseEvent) { + return QPoint(-1, -1); + } + return m_mouseEvent->globalPos(); +} + +int QmlMouseEvent::globalX() const +{ + if (!m_mouseEvent) { + return -1; + } + return m_mouseEvent->globalX(); +} + +int QmlMouseEvent::globalY() const +{ + if (!m_mouseEvent) { + return -1; + } + return m_mouseEvent->globalY(); +} + +QPointF QmlMouseEvent::localPos() const +{ + if (!m_mouseEvent) { + return QPointF(-1, -1); + } + return m_mouseEvent->localPos(); +} + +QPoint QmlMouseEvent::pos() const +{ + if (!m_mouseEvent) { + return QPoint(-1, -1); + } + return m_mouseEvent->pos(); +} + +QPointF QmlMouseEvent::screenPos() const +{ + if (!m_mouseEvent) { + return QPointF(-1, -1); + } + return m_mouseEvent->screenPos(); +} + +int QmlMouseEvent::source() const +{ + if (!m_mouseEvent) { + return -1; + } + return static_cast(m_mouseEvent->source()); +} + +QPointF QmlMouseEvent::windowPos() const +{ + if (!m_mouseEvent) { + return QPointF(-1, -1); + } + return m_mouseEvent->windowPos(); +} + +int QmlMouseEvent::x() const +{ + if (!m_mouseEvent) { + return -1; + } + return m_mouseEvent->x(); +} + +int QmlMouseEvent::y() const +{ + if (!m_mouseEvent) { + return -1; + } + return m_mouseEvent->y(); +} + +void QmlMouseEvent::clear() +{ + m_mouseEvent = nullptr; +} diff --git a/src/lib/plugins/qml/api/events/qmlmouseevent.h b/src/lib/plugins/qml/api/events/qmlmouseevent.h new file mode 100644 index 000000000..f504a384f --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlmouseevent.h @@ -0,0 +1,95 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +/** + * @brief The class exposing MouseEvent to QML + */ +class QmlMouseEvent : public QObject +{ + Q_OBJECT + /** + * @brief button associated with the event + */ + Q_PROPERTY(int button READ button CONSTANT) + /** + * @brief button state associated with the event + */ + Q_PROPERTY(int buttons READ buttons CONSTANT) + /** + * @brief global position of mouse cursor at the time of event + */ + Q_PROPERTY(QPoint globalPos READ globalPos CONSTANT) + /** + * @brief global x position of mouse cursor at the time of event + */ + Q_PROPERTY(int globalX READ globalX CONSTANT) + /** + * @brief global y position of mouse cursor at the time of event + */ + Q_PROPERTY(int globalY READ globalY CONSTANT) + /** + * @brief local position of mouse cursor at the time of event + */ + Q_PROPERTY(QPointF localPos READ localPos CONSTANT) + /** + * @brief position of mouse cursor at the time of event + */ + Q_PROPERTY(QPoint pos READ pos CONSTANT) + /** + * @brief screen position of mouse cursor at the time of event + */ + Q_PROPERTY(QPointF screenPos READ screenPos CONSTANT) + /** + * @brief source of the event + */ + Q_PROPERTY(int source READ source CONSTANT) + /** + * @brief window position of mouse cursor at the time of event + */ + Q_PROPERTY(QPointF windowPos READ windowPos CONSTANT) + /** + * @brief x position of mouse cursor at the time of event + */ + Q_PROPERTY(int x READ x CONSTANT) + /** + * @brief y position of mouse cursor at the time of event + */ + Q_PROPERTY(int y READ y CONSTANT) +public: + explicit QmlMouseEvent(QMouseEvent *mouseEvent = nullptr, QObject *parent = nullptr); + int button() const; + int buttons() const; + QPoint globalPos() const; + int globalX() const; + int globalY() const; + QPointF localPos() const; + QPoint pos() const; + QPointF screenPos() const; + int source() const; + QPointF windowPos() const; + int x() const; + int y() const; + + void clear(); + +private: + QMouseEvent *m_mouseEvent = nullptr; +}; diff --git a/src/lib/plugins/qml/api/events/qmlqzobjects.cpp b/src/lib/plugins/qml/api/events/qmlqzobjects.cpp new file mode 100644 index 000000000..196854ca2 --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlqzobjects.cpp @@ -0,0 +1,23 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlqzobjects.h" + +QmlQzObjects::QmlQzObjects(QObject *parent) + : QObject(parent) +{ +} diff --git a/src/lib/plugins/qml/api/events/qmlqzobjects.h b/src/lib/plugins/qml/api/events/qmlqzobjects.h new file mode 100644 index 000000000..b3f390602 --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlqzobjects.h @@ -0,0 +1,42 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "qzcommon.h" +#include + +/** + * @brief The class exposing Qz ObjectName to QML + */ +class QmlQzObjects : public QObject +{ + Q_OBJECT +public: + /** + * @brief The ObjectName enum + */ + enum ObjectName { + ON_WebView = Qz::ON_WebView, //!< Represents object is webview + ON_TabBar = Qz::ON_TabBar, //!< Represents object is tabbar + ON_TabWidget = Qz::ON_TabWidget, //!< Represents object is tabwidget + ON_BrowserWindow = Qz::ON_BrowserWindow //!< Represents object is browser window + }; + Q_ENUM(ObjectName) + + explicit QmlQzObjects(QObject *parent = nullptr); +}; diff --git a/src/lib/plugins/qml/api/events/qmlwheelevent.cpp b/src/lib/plugins/qml/api/events/qmlwheelevent.cpp new file mode 100644 index 000000000..0390bf384 --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlwheelevent.cpp @@ -0,0 +1,142 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlwheelevent.h" +#include + +QmlWheelEvent::QmlWheelEvent(QWheelEvent *wheelEvent, QObject *parent) + : QObject(parent) + , m_wheelEvent(wheelEvent) +{ +} + +QPoint QmlWheelEvent::angleDelta() const +{ + if (!m_wheelEvent) { + return QPoint(-1, -1); + } + return m_wheelEvent->angleDelta(); +} + +int QmlWheelEvent::buttons() const +{ + if (!m_wheelEvent) { + return -1; + } + return static_cast(m_wheelEvent->buttons()); +} + +QPoint QmlWheelEvent::globalPos() const +{ + if (!m_wheelEvent) { + return QPoint(-1, -1); + } + return m_wheelEvent->globalPos(); +} + +QPointF QmlWheelEvent::globalPosF() const +{ + if (!m_wheelEvent) { + return QPointF(-1, -1); + } + return m_wheelEvent->globalPosF(); +} + +int QmlWheelEvent::globalX() const +{ + if (!m_wheelEvent) { + return -1; + } + return m_wheelEvent->globalX(); +} + +int QmlWheelEvent::globalY() const +{ + if (!m_wheelEvent) { + return -1; + } + return m_wheelEvent->globalY(); +} + +bool QmlWheelEvent::inverted() const +{ + if (!m_wheelEvent) { + return false; + } + return m_wheelEvent->inverted(); +} + +int QmlWheelEvent::phase() const +{ + if (!m_wheelEvent) { + return -1; + } + return static_cast(m_wheelEvent->phase()); +} + +QPoint QmlWheelEvent::pixelDelta() const +{ + if (!m_wheelEvent) { + return QPoint(-1, -1); + } + return m_wheelEvent->pixelDelta(); +} + +QPoint QmlWheelEvent::pos() const +{ + if (!m_wheelEvent) { + return QPoint(-1, -1); + } + return m_wheelEvent->pos(); +} + +QPointF QmlWheelEvent::posF() const +{ + if (!m_wheelEvent) { + return QPointF(-1, -1); + } + return m_wheelEvent->posF(); +} + +int QmlWheelEvent::source() const +{ + if (!m_wheelEvent) { + return -1; + } + return static_cast(m_wheelEvent->source()); +} + +int QmlWheelEvent::x() const +{ + if (!m_wheelEvent) { + return -1; + } + return m_wheelEvent->x(); +} + +int QmlWheelEvent::y() const +{ + if (!m_wheelEvent) { + return -1; + } + return m_wheelEvent->y(); +} + +void QmlWheelEvent::clear() +{ + m_wheelEvent = nullptr; +} diff --git a/src/lib/plugins/qml/api/events/qmlwheelevent.h b/src/lib/plugins/qml/api/events/qmlwheelevent.h new file mode 100644 index 000000000..5c6b16a5b --- /dev/null +++ b/src/lib/plugins/qml/api/events/qmlwheelevent.h @@ -0,0 +1,105 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include + +/** + * @brief The class exposing WheelEvent to QML + */ +class QmlWheelEvent : public QObject +{ + Q_OBJECT + /** + * @brief the distance that the wheel is rotated, in eighths of a degree + */ + Q_PROPERTY(QPoint angleDelta READ angleDelta CONSTANT) + /** + * @brief mouse state at the time of event + */ + Q_PROPERTY(int buttons READ buttons CONSTANT) + /** + * @brief global position of mouse cursor at the time of event + */ + Q_PROPERTY(QPoint globalPos READ globalPos CONSTANT) + /** + * @brief global position of mouse cursor at the time of event + */ + Q_PROPERTY(QPointF globalPosF READ globalPosF CONSTANT) + /** + * @brief global x position of mouse cursor at the time of event + */ + Q_PROPERTY(int globalX READ globalX CONSTANT) + /** + * @brief global y position of mouse cursor at the time of event + */ + Q_PROPERTY(int globalY READ globalY CONSTANT) + /** + * @brief checks if the delta values delivered with the event are inverted + */ + Q_PROPERTY(bool inverted READ inverted CONSTANT) + /** + * @brief scrolling phase of this wheel event + */ + Q_PROPERTY(int phase READ phase CONSTANT) + /** + * @brief scrolling distance in pixels on screen + */ + Q_PROPERTY(QPoint pixelDelta READ pixelDelta CONSTANT) + /** + * @brief position of mouse cursor at the time of event + */ + Q_PROPERTY(QPoint pos READ pos CONSTANT) + /** + * @brief position of mouse cursor at the time of event + */ + Q_PROPERTY(QPointF posF READ posF CONSTANT) + /** + * @brief source of the event + */ + Q_PROPERTY(int source READ source CONSTANT) + /** + * @brief x position of mouse cursor at the time of event + */ + Q_PROPERTY(int x READ x CONSTANT) + /** + * @brief y position of mouse cursor at the time of event + */ + Q_PROPERTY(int y READ y CONSTANT) +public: + explicit QmlWheelEvent(QWheelEvent *wheelEvent = nullptr, QObject *parent = nullptr); + QPoint angleDelta() const; + int buttons() const; + QPoint globalPos() const; + QPointF globalPosF() const; + int globalX() const; + int globalY() const; + bool inverted() const; + int phase() const; + QPoint pixelDelta() const; + QPoint pos() const; + QPointF posF() const; + int source() const; + int x() const; + int y() const; + + void clear(); +private: + QWheelEvent *m_wheelEvent = nullptr; +}; diff --git a/src/lib/plugins/qml/api/extensionscheme/qmlextensionscheme.cpp b/src/lib/plugins/qml/api/extensionscheme/qmlextensionscheme.cpp new file mode 100644 index 000000000..a4a91e5fd --- /dev/null +++ b/src/lib/plugins/qml/api/extensionscheme/qmlextensionscheme.cpp @@ -0,0 +1,60 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlextensionscheme.h" +#include "mainapplication.h" +#include "networkmanager.h" +#include +#include +#include + +QmlExtensionScheme::QmlExtensionScheme(QObject *parent) + : QObject(parent) +{ + m_schemeHandler = new QmlExtensionSchemeHandler; + connect(m_schemeHandler, &QmlExtensionSchemeHandler::_requestStarted, this, [this](QWebEngineUrlRequestJob *job) { + QmlWebEngineUrlRequestJob *request = new QmlWebEngineUrlRequestJob(job); + qmlEngine(this)->newQObject(request); + emit requestStarted(request); + }); +} + +QmlExtensionScheme::~QmlExtensionScheme() +{ + mApp->networkManager()->unregisterExtensionSchemeHandler(m_schemeHandler); + m_schemeHandler->deleteLater(); +} + +void QmlExtensionScheme::componentComplete() +{ + mApp->networkManager()->registerExtensionSchemeHandler(m_name, m_schemeHandler); +} + +QString QmlExtensionScheme::name() const +{ + return m_name; +} + +void QmlExtensionScheme::setName(const QString &name) +{ + m_name = name; +} + +void QmlExtensionSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job) +{ + emit _requestStarted(job); +} diff --git a/src/lib/plugins/qml/api/extensionscheme/qmlextensionscheme.h b/src/lib/plugins/qml/api/extensionscheme/qmlextensionscheme.h new file mode 100644 index 000000000..47496a208 --- /dev/null +++ b/src/lib/plugins/qml/api/extensionscheme/qmlextensionscheme.h @@ -0,0 +1,63 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "schemehandlers/extensionschemehandler.h" +#include "qmlwebengineurlrequestjob.h" +#include +#include + +class QmlExtensionSchemeHandler; + +/** + * @brief The QmlExtensionScheme class, exposed to QML as ExtensionScheme + */ +class QmlExtensionScheme : public QObject, public QQmlParserStatus +{ + Q_OBJECT + /** + * @brief extension scheme handle name + */ + Q_PROPERTY(QString name READ name WRITE setName) +public: + explicit QmlExtensionScheme(QObject *parent = nullptr); + ~QmlExtensionScheme(); + void classBegin() {} + void componentComplete(); +Q_SIGNALS: + /** + * @brief The signal emitted when the request to the scheme handle is started + * @param request of the type [QmlWebEngineUrlRequestJob](@ref QmlWebEngineUrlRequestJob) + */ + void requestStarted(QmlWebEngineUrlRequestJob *request); +private: + QString m_name; + QmlExtensionSchemeHandler *m_schemeHandler = nullptr; + + QString name() const; + void setName(const QString &name); +}; + +class QmlExtensionSchemeHandler : public ExtensionSchemeHandler +{ + Q_OBJECT +public: + void requestStarted(QWebEngineUrlRequestJob *job); +Q_SIGNALS: + void _requestStarted(QWebEngineUrlRequestJob *job); +}; diff --git a/src/lib/plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.cpp b/src/lib/plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.cpp new file mode 100644 index 000000000..f379628d9 --- /dev/null +++ b/src/lib/plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.cpp @@ -0,0 +1,85 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlwebengineurlrequestjob.h" +#include +#include +#include + +QmlWebEngineUrlRequestJob::QmlWebEngineUrlRequestJob(QWebEngineUrlRequestJob *job, QObject *parent) + : QObject(parent) + , m_job(job) +{ +} + +void QmlWebEngineUrlRequestJob::fail(QmlWebEngineUrlRequestJob::Error error) +{ + if (!m_job) { + return; + } + m_job->fail(QWebEngineUrlRequestJob::Error(error)); +} + +void QmlWebEngineUrlRequestJob::redirect(const QString &urlString) +{ + if (!m_job) { + return; + } + return m_job->redirect(QUrl::fromEncoded(urlString.toUtf8())); +} + +void QmlWebEngineUrlRequestJob::reply(const QVariantMap &map) +{ + if (!m_job) { + return; + } + if (!map.contains(QSL("content")) || !map.contains(QSL("contentType"))) { + qWarning() << "Unable to call" << __FUNCTION__ << ": invalid parameters"; + return; + } + QByteArray content = map.value(QSL("content")).toString().toUtf8(); + QByteArray contentType = map.value(QSL("contentType")).toString().toUtf8(); + QBuffer *buffer = new QBuffer(); + buffer->open(QIODevice::ReadWrite); + buffer->write(content); + buffer->seek(0); + m_job->reply(contentType, buffer); +} + +QString QmlWebEngineUrlRequestJob::initiator() const +{ + if (!m_job) { + return QString(); + } + return QString::fromUtf8(m_job->initiator().toEncoded()); +} + +QString QmlWebEngineUrlRequestJob::requestUrl() const +{ + if (!m_job) { + return QString(); + } + return QString::fromUtf8(m_job->requestUrl().toEncoded()); +} + +QString QmlWebEngineUrlRequestJob::requestMethod() const +{ + if (!m_job) { + return QString(); + } + return QString::fromUtf8(m_job->requestMethod()); +} diff --git a/src/lib/plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.h b/src/lib/plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.h new file mode 100644 index 000000000..1da0331b2 --- /dev/null +++ b/src/lib/plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.h @@ -0,0 +1,77 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +/** + * @brief The QmlWebEngineUrlRequestJob class + */ +class QmlWebEngineUrlRequestJob : public QObject +{ + Q_OBJECT + /** + * @brief initiator of the QWebEngineUrlRequestJob + */ + Q_PROPERTY(QString initiator READ initiator CONSTANT) + /** + * @brief request url of the QWebEngineUrlRequestJob + */ + Q_PROPERTY(QString requestUrl READ requestUrl CONSTANT) + /** + * @brief request method of the QWebEngineUrlRequestJob + */ + Q_PROPERTY(QString requestMethod READ requestMethod CONSTANT) +public: + /** + * @brief The Error enum, exposes QWebEngineUrlRequestJob::Error to QML + */ + enum Error { + NoError = QWebEngineUrlRequestJob::NoError, //! No error + UrlNotFound = QWebEngineUrlRequestJob::UrlNotFound, //! Url not found error + UrlInvaild = QWebEngineUrlRequestJob::UrlInvalid, //! Url invalid error + RequestAborted = QWebEngineUrlRequestJob::RequestAborted, //! Request aborted + RequestDenied = QWebEngineUrlRequestJob::RequestDenied, //! Request denied + RequestFailed = QWebEngineUrlRequestJob::RequestFailed //! Request failed + }; + Q_ENUM(Error) + explicit QmlWebEngineUrlRequestJob(QWebEngineUrlRequestJob *job = nullptr, QObject *parent = nullptr); + /** + * @brief Fails the request with the error + * @param error + */ + Q_INVOKABLE void fail(Error error); + /** + * @brief Redirects the request to the url + * @param urlString, represents the url to which the request is to be redirected + */ + Q_INVOKABLE void redirect(const QString &urlString); + /** + * @brief Replies to the request + * @param A JavaScript object containing + * - content: String representing the reply data + * - contentType: String representing the contentType of reply data + */ + Q_INVOKABLE void reply(const QVariantMap &map); +private: + QWebEngineUrlRequestJob *m_job = nullptr; + + QString initiator() const; + QString requestUrl() const; + QString requestMethod() const; +}; diff --git a/src/lib/plugins/qml/api/fileutils/qmlfileutils.cpp b/src/lib/plugins/qml/api/fileutils/qmlfileutils.cpp new file mode 100644 index 000000000..f1e59c463 --- /dev/null +++ b/src/lib/plugins/qml/api/fileutils/qmlfileutils.cpp @@ -0,0 +1,51 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlfileutils.h" +#include "datapaths.h" +#include "qztools.h" +#include +#include +#include + +QmlFileUtils::QmlFileUtils(QString filePath, QObject *parent) + : QObject(parent) +{ + m_path = filePath; +} + +QString QmlFileUtils::resolve(const QString &filePath) +{ + QString resolvedPath = m_path + QL1C('/') + filePath; + resolvedPath = QDir::cleanPath(resolvedPath); + if (resolvedPath.contains(m_path)) { + return resolvedPath; + } + return QString(); +} + +QByteArray QmlFileUtils::readAllFileContents(const QString &fileName) +{ + const QString path = resolve(fileName); + return QzTools::readAllFileByteContents(path); +} + +bool QmlFileUtils::exists(const QString &filePath) +{ + const QString path = resolve(filePath); + return QFile(path).exists(); +} diff --git a/src/lib/plugins/qml/api/fileutils/qmlfileutils.h b/src/lib/plugins/qml/api/fileutils/qmlfileutils.h new file mode 100644 index 000000000..eb7969e90 --- /dev/null +++ b/src/lib/plugins/qml/api/fileutils/qmlfileutils.h @@ -0,0 +1,52 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +/** + * @brief The QmlFileUtils class, exposed to QML as FileUtils + */ +class QmlFileUtils : public QObject +{ + Q_OBJECT +public: + explicit QmlFileUtils(QString filePath, QObject *parent = nullptr); + /** + * @brief Get the path of the file within the plugin directory. + * If the filePath provided is resolved to be outside the plugin + * directory then empty string is returned + * @param file path within the plugin directory + * @return resolved path + */ + Q_INVOKABLE QString resolve(const QString &filePath); + /** + * @brief Read the contents of the file within the plugin directory + * @param file path within the plugin directory + * @return contents of the file + */ + Q_INVOKABLE QByteArray readAllFileContents(const QString &fileName); + /** + * @brief Checks if the file exists within the plugin directory + * @param file path within the plugin directory + * @return true if file exists, otherwise false + */ + Q_INVOKABLE bool exists(const QString &filePath); +private: + QString m_path; +}; diff --git a/src/lib/plugins/qml/api/history/qmlhistory.cpp b/src/lib/plugins/qml/api/history/qmlhistory.cpp new file mode 100644 index 000000000..a1e03ee84 --- /dev/null +++ b/src/lib/plugins/qml/api/history/qmlhistory.cpp @@ -0,0 +1,94 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlhistory.h" +#include "mainapplication.h" +#include "history.h" +#include "sqldatabase.h" +#include "qml/qmlstaticdata.h" +#include + +QmlHistory::QmlHistory(QObject *parent) + : QObject(parent) +{ + connect(mApp->history(), &History::historyEntryAdded, this, [this](HistoryEntry entry){ + QmlHistoryItem *historyItem = QmlStaticData::instance().getHistoryItem(&entry); + emit visited(historyItem); + }); + + connect(mApp->history(), &History::historyEntryDeleted, this, [this](HistoryEntry entry){ + QmlHistoryItem *historyItem = QmlStaticData::instance().getHistoryItem(&entry); + emit visitRemoved(historyItem); + }); +} + +QList QmlHistory::search(const QString &text) +{ + QList list; + const QList result = mApp->history()->searchHistoryEntry(text); + list.reserve(result.size()); + for (HistoryEntry *entry : result) { + auto item = QmlStaticData::instance().getHistoryItem(entry); + list.append(item); + } + return list; +} + +int QmlHistory::getVisits(const QString &url) +{ + HistoryEntry *entry = mApp->history()->getHistoryEntry(url); + return entry->count; +} + +void QmlHistory::addUrl(const QVariantMap &map) +{ + if (!map.contains(QSL("title")) || !map.contains(QSL("url"))) { + qWarning() << "Error:" << "wrong arguments passed to" << __FUNCTION__; + return; + } + QString title = map.value(QSL("title")).toString(); + const QString url = map.value(QSL("url")).toString(); + + title = title.isEmpty() ? url : title; + + mApp->history()->addHistoryEntry(QUrl::fromEncoded(url.toUtf8()), title); +} + +void QmlHistory::deleteUrl(const QString &url) +{ + mApp->history()->deleteHistoryEntry(url); +} + +void QmlHistory::deleteRange(const QVariantMap &map) +{ + if (!map.contains(QSL("startTime")) || !map.contains(QSL("endTime"))) { + qWarning() << "Error:" << "wrong arguments passed to" << __FUNCTION__; + return; + } + const qlonglong startTime = map.value(QSL("startTime")).toLongLong(); + const qlonglong endTime = map.value(QSL("endTime")).toLongLong(); + + const QList entries = mApp->history()->indexesFromTimeRange(startTime, endTime); + for (int index : entries) { + mApp->history()->deleteHistoryEntry(index); + } +} + +void QmlHistory::deleteAll() +{ + mApp->history()->clearHistory(); +} diff --git a/src/lib/plugins/qml/api/history/qmlhistory.h b/src/lib/plugins/qml/api/history/qmlhistory.h new file mode 100644 index 000000000..b27d4e31f --- /dev/null +++ b/src/lib/plugins/qml/api/history/qmlhistory.h @@ -0,0 +1,85 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "qmlhistoryitem.h" + +/** + * @brief The class exposing the History API to QML + */ +class QmlHistory : public QObject +{ + Q_OBJECT +public: + explicit QmlHistory(QObject *parent = nullptr); + /** + * @brief Searches History Entries against a search query + * @param String representing the search query + * @return List of History Entries, each of type [QmlHistoryItem](@ref QmlHistoryItem), + * matching the search query + */ + Q_INVOKABLE QList search(const QString &text); + /** + * @brief Get the visit count of a url + * @param String representing the url + * @return Integer representing the visit count of the given url + */ + Q_INVOKABLE int getVisits(const QString &url); + /** + * @brief Add url to the history + * @param A JavaScript object containing + * - title: + * String representing the title of the hisotry entry + * - url: + * String representing the url of the history entry + */ + Q_INVOKABLE void addUrl(const QVariantMap &map); + /** + * @brief Deletes a url from the history + * @param String representing the url of the history entry + */ + Q_INVOKABLE void deleteUrl(const QString &url); + /** + * @brief Deletes history entries within the given range + * @param A JavaScript object containing + * - startTime: + * A JavaScript Date object representing the start time + * - endTime: + * A JavaScript Date object representing the end time + */ + Q_INVOKABLE void deleteRange(const QVariantMap &map); + /** + * @brief Clears all the history + */ + Q_INVOKABLE void deleteAll(); +Q_SIGNALS: + /** + * @brief The signal emitted when a HistoryEntry is added + * @param Object of type [QmlHistoryItem](@ref QmlHistoryItem), representing + * the added History Entry + */ + void visited(QmlHistoryItem *historyItem); + + /** + * @brief The signal emitted when a HistoryEntry is removed + * @param Object of type [QmlHistoryItem](@ref QmlHistoryItem), representing + * the removed History Entry + */ + void visitRemoved(QmlHistoryItem *historyItem); +}; diff --git a/src/lib/plugins/qml/api/history/qmlhistoryitem.cpp b/src/lib/plugins/qml/api/history/qmlhistoryitem.cpp new file mode 100644 index 000000000..dd06e87f5 --- /dev/null +++ b/src/lib/plugins/qml/api/history/qmlhistoryitem.cpp @@ -0,0 +1,66 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlhistoryitem.h" +#include + +QmlHistoryItem::QmlHistoryItem(HistoryEntry *entry, QObject *parent) + : QObject(parent) + , m_entry(entry) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +int QmlHistoryItem::id() const +{ + if (!m_entry) { + return 0; + } + return m_entry->id; +} + +QString QmlHistoryItem::url() const +{ + if (!m_entry) { + return QString(); + } + return QString::fromUtf8(m_entry->url.toEncoded()); +} + +QString QmlHistoryItem::title() const +{ + if (!m_entry) { + return QString(); + } + return m_entry->title; +} + +int QmlHistoryItem::visitCount() const +{ + if (!m_entry) { + return 0; + } + return m_entry->count; +} + +QDateTime QmlHistoryItem::lastVisitTime() const +{ + if (!m_entry) { + return QDateTime().currentDateTime().addMonths(1); + } + return m_entry->date; +} diff --git a/src/lib/plugins/qml/api/history/qmlhistoryitem.h b/src/lib/plugins/qml/api/history/qmlhistoryitem.h new file mode 100644 index 000000000..f7e653598 --- /dev/null +++ b/src/lib/plugins/qml/api/history/qmlhistoryitem.h @@ -0,0 +1,65 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "history.h" + +/** + * @brief The class exposing HistoryEntry to QML + */ +class QmlHistoryItem : public QObject +{ + Q_OBJECT + + /** + * @brief id of the history item + */ + Q_PROPERTY(int id READ id CONSTANT) + + /** + * @brief url of the history item + */ + Q_PROPERTY(QString url READ url CONSTANT) + + /** + * @brief title of the history item + */ + Q_PROPERTY(QString title READ title CONSTANT) + + /** + * @brief visit count of the history item + */ + Q_PROPERTY(int visitCount READ visitCount CONSTANT) + + /** + * @brief last visit time of the history item + */ + Q_PROPERTY(QDateTime lastVisitTime READ lastVisitTime CONSTANT) +public: + explicit QmlHistoryItem(HistoryEntry *entry = nullptr, QObject *parent = nullptr); + +private: + HistoryEntry *m_entry = nullptr; + + int id() const; + QString url() const; + QString title() const; + int visitCount() const; + QDateTime lastVisitTime() const; +}; diff --git a/src/lib/plugins/qml/api/i18n/qmli18n.cpp b/src/lib/plugins/qml/api/i18n/qmli18n.cpp new file mode 100644 index 000000000..8d902f499 --- /dev/null +++ b/src/lib/plugins/qml/api/i18n/qmli18n.cpp @@ -0,0 +1,45 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmli18n.h" +#include "qztools.h" +#include + +QmlI18n::QmlI18n(const QString &pluginName, QObject *parent) + : QObject(parent) +{ + m_pluginName = pluginName; + setlocale(LC_MESSAGES, QLocale::system().name().toUtf8()); + initTranslations(); +} + +void QmlI18n::initTranslations() +{ + m_domain = QString("falkon_%1").arg(m_pluginName); + QString localeDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "locale", QStandardPaths::LocateDirectory); + bindtextdomain(m_domain.toUtf8(), localeDir.toUtf8()); +} + +QString QmlI18n::i18n(const QString &string) +{ + return QString::fromUtf8(dgettext(m_domain.toUtf8(), string.toUtf8())); +} + +QString QmlI18n::i18np(const QString &string1, const QString &string2, int count) +{ + return QString::fromUtf8(dngettext(m_domain.toUtf8(), string1.toUtf8(), string2.toUtf8(), count)); +} diff --git a/src/lib/plugins/qml/api/i18n/qmli18n.h b/src/lib/plugins/qml/api/i18n/qmli18n.h new file mode 100644 index 000000000..6bc43c513 --- /dev/null +++ b/src/lib/plugins/qml/api/i18n/qmli18n.h @@ -0,0 +1,46 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +extern "C" { +#include +} + +/** + * @brief The class exposing GNU Gettext to QML + */ +class QmlI18n : public QObject +{ + Q_OBJECT +public: + explicit QmlI18n(const QString &pluginName, QObject *parent = nullptr); + void initTranslations(); + /** + * @brief wrapper for gettext function + */ + Q_INVOKABLE QString i18n(const QString &string); + /** + * @brief wrapper for ngettext function + */ + Q_INVOKABLE QString i18np(const QString &string1, const QString &string2, int count); +private: + QString m_pluginName; + QString m_domain; +}; diff --git a/src/lib/plugins/qml/api/menus/qmlaction.cpp b/src/lib/plugins/qml/api/menus/qmlaction.cpp new file mode 100644 index 000000000..4a410f01e --- /dev/null +++ b/src/lib/plugins/qml/api/menus/qmlaction.cpp @@ -0,0 +1,57 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlaction.h" +#include "qztools.h" +#include "qml/api/fileutils/qmlfileutils.h" +#include "qml/qmlengine.h" +#include "qml/qmlstaticdata.h" +#include + +QmlAction::QmlAction(QAction *action, QmlEngine *engine, QObject *parent) + : QObject(parent) + , m_action(action) +{ + QmlEngine *qmlEngine = qobject_cast(engine); + m_pluginPath = qmlEngine->extensionPath(); + connect(m_action, &QAction::triggered, this, &QmlAction::triggered); +} + +void QmlAction::setProperties(const QVariantMap &map) +{ + if (!m_action) { + return; + } + + for (auto it = map.cbegin(); it != map.cend(); it++) { + const QString key = it.key(); + if (key == QSL("icon")) { + QString iconPath = map.value(key).toString(); + QIcon icon = QmlStaticData::instance().getIcon(iconPath, m_pluginPath); + m_action->setIcon(icon); + } else if (key == QSL("shortcut")) { + m_action->setShortcut(QKeySequence(map.value(key).toString())); + } else { + m_action->setProperty(key.toUtf8(), map.value(key)); + } + } +} + +void QmlAction::update(const QVariantMap &map) +{ + setProperties(map); +} diff --git a/src/lib/plugins/qml/api/menus/qmlaction.h b/src/lib/plugins/qml/api/menus/qmlaction.h new file mode 100644 index 000000000..05fbf611d --- /dev/null +++ b/src/lib/plugins/qml/api/menus/qmlaction.h @@ -0,0 +1,50 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include +#include + +class QmlEngine; + +/** + * @brief The class exposing Action API to QML + */ +class QmlAction : public QObject +{ + Q_OBJECT +public: + explicit QmlAction(QAction *action, QmlEngine *engine, QObject *parent = nullptr); + void setProperties(const QVariantMap &map); + /** + * @brief Updates the properties of the action + * @param A JavaScript object containing the updated properties of the action. + */ + Q_INVOKABLE void update(const QVariantMap &map); + +Q_SIGNALS: + /** + * @brief This signal is emitted when the action is triggered. + */ + void triggered(); + +private: + QAction *m_action = nullptr; + QString m_pluginPath; +}; diff --git a/src/lib/plugins/qml/api/menus/qmlmenu.cpp b/src/lib/plugins/qml/api/menus/qmlmenu.cpp new file mode 100644 index 000000000..5c6aff2c3 --- /dev/null +++ b/src/lib/plugins/qml/api/menus/qmlmenu.cpp @@ -0,0 +1,78 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlmenu.h" +#include "qztools.h" +#include "qml/api/fileutils/qmlfileutils.h" +#include "qml/qmlengine.h" +#include "qml/qmlstaticdata.h" + +QmlMenu::QmlMenu(QMenu *menu, QQmlEngine *engine, QObject *parent) + : QObject(parent) + , m_menu(menu) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); + + m_engine = qobject_cast(engine); + m_pluginPath = m_engine->extensionPath(); + connect(m_menu, &QMenu::triggered, this, &QmlMenu::triggered); +} + +QmlAction *QmlMenu::addAction(const QVariantMap &map) +{ + if (!m_menu) { + return nullptr; + } + + QAction *action = new QAction(); + QmlAction *qmlAction = new QmlAction(action, m_engine, this); + qmlAction->setProperties(map); + m_menu->addAction(action); + + return qmlAction; +} + +QmlMenu *QmlMenu::addMenu(const QVariantMap &map) +{ + if (!m_menu) { + return nullptr; + } + + QMenu *newMenu = new QMenu(); + for (auto it = map.cbegin(); it != map.cend(); it++) { + const QString key = it.key(); + if (key == QSL("icon")) { + QString iconPath = map.value(key).toString(); + QIcon icon = QmlStaticData::instance().getIcon(iconPath, m_pluginPath); + newMenu->setIcon(icon); + continue; + } + newMenu->setProperty(key.toUtf8(), map.value(key)); + } + m_menu->addMenu(newMenu); + QmlMenu *newQmlMenu = new QmlMenu(newMenu, m_engine, this); + return newQmlMenu; +} + +void QmlMenu::addSeparator() +{ + if (!m_menu) { + return; + } + + m_menu->addSeparator(); +} diff --git a/src/lib/plugins/qml/api/menus/qmlmenu.h b/src/lib/plugins/qml/api/menus/qmlmenu.h new file mode 100644 index 000000000..def353c87 --- /dev/null +++ b/src/lib/plugins/qml/api/menus/qmlmenu.h @@ -0,0 +1,64 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "qmlaction.h" +#include +#include + +class QmlEngine; + +/** + * @brief The class exposing WebView contextmenu to QML as Menu API + */ +class QmlMenu : public QObject +{ + Q_OBJECT +public: + explicit QmlMenu(QMenu *menu, QQmlEngine *engine, QObject *parent = nullptr); + /** + * @brief Adds action to menu + * @param A JavaScript object containing properties for action. + * The icon property must be in form of url of the path + * and shortcut in form string. + * @return action of type [QmlAction](@ref QmlAction) + */ + Q_INVOKABLE QmlAction *addAction(const QVariantMap &map); + /** + * @brief Adds sub-menu to menu + * @param A JavaScript object containing properties of menu. + * The icon property must be in form of url of the path. + * @return menu of type [QmlMenu](@ref QmlMenu) + */ + Q_INVOKABLE QmlMenu *addMenu(const QVariantMap &map); + /** + * @brief Adds a separator to menu + */ + Q_INVOKABLE void addSeparator(); + +Q_SIGNALS: + /** + * @brief This signal is emitted when the menu is triggred + */ + void triggered(); + +private: + QMenu *m_menu = nullptr; + QString m_pluginPath; + QmlEngine *m_engine = nullptr; +}; diff --git a/src/lib/plugins/qml/api/menus/qmlwebhittestresult.cpp b/src/lib/plugins/qml/api/menus/qmlwebhittestresult.cpp new file mode 100644 index 000000000..1166e1643 --- /dev/null +++ b/src/lib/plugins/qml/api/menus/qmlwebhittestresult.cpp @@ -0,0 +1,110 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlwebhittestresult.h" +#include + +QmlWebHitTestResult::QmlWebHitTestResult(const WebHitTestResult &webHitTestResult, QObject *parent) + : QObject(parent) + , m_webHitTestResult(webHitTestResult) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); +} + +bool QmlWebHitTestResult::isImage() const +{ + return !m_webHitTestResult.imageUrl().isEmpty(); +} + +bool QmlWebHitTestResult::isContentEditable() const +{ + return m_webHitTestResult.isContentEditable(); +} + +bool QmlWebHitTestResult::isContentSelected() const +{ + return m_webHitTestResult.isContentSelected(); +} + +bool QmlWebHitTestResult::isNull() const +{ + return m_webHitTestResult.isNull(); +} + +bool QmlWebHitTestResult::isLink() const +{ + return !m_webHitTestResult.linkUrl().isEmpty(); +} + +bool QmlWebHitTestResult::isMedia() const +{ + return !m_webHitTestResult.mediaUrl().isEmpty(); +} + +bool QmlWebHitTestResult::mediaPaused() const +{ + return m_webHitTestResult.mediaPaused(); +} + +bool QmlWebHitTestResult::mediaMuted() const +{ + return m_webHitTestResult.mediaMuted(); +} + +QString QmlWebHitTestResult::tagName() const +{ + return m_webHitTestResult.tagName(); +} + +QString QmlWebHitTestResult::baseUrl() const +{ + const QUrl base = m_webHitTestResult.baseUrl(); + return QString::fromUtf8(base.toEncoded()); +} + +QString QmlWebHitTestResult::linkTitle() const +{ + return m_webHitTestResult.linkTitle(); +} + +QString QmlWebHitTestResult::linkUrl() const +{ + const QUrl link = m_webHitTestResult.linkUrl(); + return QString::fromUtf8(link.toEncoded()); +} + +QString QmlWebHitTestResult::imageUrl() const +{ + const QUrl image = m_webHitTestResult.imageUrl(); + return QString::fromUtf8(image.toEncoded()); +} + +QString QmlWebHitTestResult::mediaUrl() const +{ + const QUrl media = m_webHitTestResult.mediaUrl(); + return QString::fromUtf8(media.toEncoded()); +} + +QPoint QmlWebHitTestResult::pos() const +{ + return m_webHitTestResult.pos(); +} + +QPointF QmlWebHitTestResult::viewportPos() const +{ + return m_webHitTestResult.viewportPos(); +} diff --git a/src/lib/plugins/qml/api/menus/qmlwebhittestresult.h b/src/lib/plugins/qml/api/menus/qmlwebhittestresult.h new file mode 100644 index 000000000..b4ea46328 --- /dev/null +++ b/src/lib/plugins/qml/api/menus/qmlwebhittestresult.h @@ -0,0 +1,114 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "webhittestresult.h" +#include + +/** + * @brief The class exposing result of WebHitTest to QML + */ +class QmlWebHitTestResult : public QObject +{ + Q_OBJECT + /** + * @brief Gets the tagName of the element on which the context menu is requested. + */ + Q_PROPERTY(QString tagName READ tagName CONSTANT) + /** + * @brief Gets the base url on which the context menu is requested. + */ + Q_PROPERTY(QString baseUrl READ baseUrl CONSTANT) + /** + * @brief Gets the link title on which the context menu is requested. + */ + Q_PROPERTY(QString linkTitle READ linkTitle CONSTANT) + /** + * @brief Gets the link url on which the context menu is requested. + */ + Q_PROPERTY(QString linkUrl READ linkUrl CONSTANT) + /** + * @brief Gets the url of image on which the context menu is requested. + */ + Q_PROPERTY(QString imageUrl READ imageUrl CONSTANT) + /** + * @brief Gets the url of media on which the context menu is requested. + */ + Q_PROPERTY(QString mediaUrl READ mediaUrl CONSTANT) + /** + * @brief Gets the position at which the context menu is requested. + */ + Q_PROPERTY(QPoint pos READ pos CONSTANT) + /** + * @brief Gets the viewport position at which the context menu is requested. + */ + Q_PROPERTY(QPointF viewportPos READ viewportPos CONSTANT) +public: + explicit QmlWebHitTestResult(const WebHitTestResult &webHitTestResult, QObject *parent = nullptr); + /** + * @brief Checks if the context menu is requested on image. + * @return true if image, else false + */ + Q_INVOKABLE bool isImage() const; + /** + * @brief Checks if the context menu is requested on editable content. + * @return true if the content is editable, else false + */ + Q_INVOKABLE bool isContentEditable() const; + /** + * @brief Checks if the context menu is requested on the selected content. + * @return true if content is selected, else false. + */ + Q_INVOKABLE bool isContentSelected() const; + /** + * @brief Checks if the context menu is requested on null element. + * @return true if the element is null, else false + */ + Q_INVOKABLE bool isNull() const; + /** + * @brief Checks if the context menu is requested on a link. + * @return true if the element is link, else false + */ + Q_INVOKABLE bool isLink() const; + /** + * @brief Checks if the context menu is requested on a media element. + * @return true if the element is media, else false + */ + Q_INVOKABLE bool isMedia() const; + /** + * @brief Checks if the context menu requested on media element is paused. + * @return true if media is paused, else false + */ + Q_INVOKABLE bool mediaPaused() const; + /** + * @brief Checks if the context menu requested on media element is muted. + * @return true if media is muted, else false + */ + Q_INVOKABLE bool mediaMuted() const; + QString tagName() const; + QString baseUrl() const; + QString linkTitle() const; + QString linkUrl() const; + QString imageUrl() const; + QString mediaUrl() const; + QPoint pos() const; + QPointF viewportPos() const; + +private: + WebHitTestResult m_webHitTestResult; +}; diff --git a/src/lib/plugins/qml/api/notifications/qmlnotifications.cpp b/src/lib/plugins/qml/api/notifications/qmlnotifications.cpp new file mode 100644 index 000000000..def166ca1 --- /dev/null +++ b/src/lib/plugins/qml/api/notifications/qmlnotifications.cpp @@ -0,0 +1,43 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlnotifications.h" +#include "mainapplication.h" +#include "desktopnotificationsfactory.h" +#include "qztools.h" +#include "qml/api/fileutils/qmlfileutils.h" + +QmlNotifications::QmlNotifications(QObject *parent) + : QObject(parent) +{ +} + +void QmlNotifications::create(const QVariantMap &map) +{ + const QString iconUrl = map.value(QSL("icon")).toString(); + QmlFileUtils fileUtils(m_pluginPath); + const QString iconPath = fileUtils.resolve(iconUrl); + QPixmap icon = QPixmap(iconPath); + const QString heading = map.value(QSL("heading")).toString(); + const QString message = map.value(QSL("message")).toString(); + mApp->desktopNotifications()->showNotification(icon, heading, message); +} + +void QmlNotifications::setPluginPath(const QString &path) +{ + m_pluginPath = path; +} diff --git a/src/lib/plugins/qml/api/notifications/qmlnotifications.h b/src/lib/plugins/qml/api/notifications/qmlnotifications.h new file mode 100644 index 000000000..924c94687 --- /dev/null +++ b/src/lib/plugins/qml/api/notifications/qmlnotifications.h @@ -0,0 +1,50 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +/** + * @brief The class to display notifications + */ +class QmlNotifications : public QObject +{ + Q_OBJECT +public: + explicit QmlNotifications(QObject *parent = nullptr); + /** + * @brief Create and display a notification + * @param JavaScript object containing + * - icon: + * String representing the icon file url. The icon path will be + * search in the following order + * - Falkon resource: for the icons starting with ":", they are searched in + * falkon resource file + * - Files in plugin directory: All other paths will be resolved relative to + * the plugin directory. If the icon path is outside the + * plugin directory, then it will be resolved as empty path. + * - heading: + * String representing the heading of the notification + * - message: + * String representing the message of the notification + */ + Q_INVOKABLE void create(const QVariantMap &map); + void setPluginPath(const QString &path); +private: + QString m_pluginPath; +}; diff --git a/src/lib/plugins/qml/api/settings/qmlsettings.cpp b/src/lib/plugins/qml/api/settings/qmlsettings.cpp new file mode 100644 index 000000000..f4a7fd236 --- /dev/null +++ b/src/lib/plugins/qml/api/settings/qmlsettings.cpp @@ -0,0 +1,108 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlsettings.h" +#include "datapaths.h" +#include + +QmlSettings::QmlSettings(QObject *parent) + : QObject(parent) +{ + m_settingsPath = DataPaths::currentProfilePath() + QL1S("/extensions"); +} + +QmlSettings::~QmlSettings() +{ +} + +bool QmlSettings::setValue(const QVariantMap &map) +{ + if (!m_settings) { + return false; + } + + if (!map.contains(QSL("key")) || !map.contains(QSL("value"))) { + qWarning() << "Unable to set value:" << "cannot determine Key-Value from the argument"; + return false; + } + const QString key = map.value(QSL("key")).toString(); + const QVariant value = map.value(QSL("value")); + m_settings->setValue(key, value); + return true; +} + +QVariant QmlSettings::value(const QVariantMap &map) +{ + if (!m_settings) { + return QVariant(); + } + + if (!map.contains(QSL("key"))) { + qWarning() << "Unable to get value:" << "key not defined"; + return QVariant(); + } + + const QString key = map.value(QSL("key")).toString(); + const QVariant defaultValue = map.value(QSL("defaultValue")); + return m_settings->value(key, defaultValue); +} + +bool QmlSettings::contains(const QString &key) +{ + if (!m_settings) { + return false; + } + + return m_settings->contains(key); +} + +bool QmlSettings::remove(const QString &key) +{ + if (!m_settings) { + return false; + } + + m_settings->remove(key); + return true; +} + +bool QmlSettings::sync() +{ + if (!m_settings) { + return false; + } + + m_settings->sync(); + return true; +} + +QString QmlSettings::name() const +{ + return m_name; +} + +void QmlSettings::setName(const QString &name) +{ + m_name = name; + createSettings(); +} + +void QmlSettings::createSettings() +{ + m_settingsPath += QL1S("/") + m_name + QL1S("/settings.ini"); + m_settings = new QSettings(m_settingsPath, QSettings::IniFormat, this); +} diff --git a/src/lib/plugins/qml/api/settings/qmlsettings.h b/src/lib/plugins/qml/api/settings/qmlsettings.h new file mode 100644 index 000000000..bd3f0ffae --- /dev/null +++ b/src/lib/plugins/qml/api/settings/qmlsettings.h @@ -0,0 +1,81 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include + +/** + * @brief The class exposing Settings API to QML + */ +class QmlSettings : public QObject +{ + Q_OBJECT + + /** + * @brief name of the folder in which settings.ini file is located + * on the standard extension path. + */ + Q_PROPERTY(QString name READ name WRITE setName) + +public: + explicit QmlSettings(QObject *parent = nullptr); + ~QmlSettings(); + /** + * @brief Sets the value for a given key. + * @param A JavaScript object containing + * - key: QString representing the key + * - value: QVariant representing the value for the key + * @return true if value is set, else false + */ + Q_INVOKABLE bool setValue(const QVariantMap &map); + /** + * @brief Gets the value for a given key. + * @param A JavaScript object containing + * - key: QString representing the key + * - defaultValue: QVariant representing the default value for the key + * @return QVariant representing value + */ + Q_INVOKABLE QVariant value(const QVariantMap &map); + /** + * @brief Checks if a given key exists. + * @param QString representing the key + * @return true if key exists, else false + */ + Q_INVOKABLE bool contains(const QString &key); + /** + * @brief Removes the given key-value from the settings. + * @param QString representing the key + * @return true if key-value pair is removed, else false + */ + Q_INVOKABLE bool remove(const QString &key); + /** + * @brief syncs the settings + * @return true if success, else false + */ + Q_INVOKABLE bool sync(); + +private: + QSettings *m_settings = nullptr; + QString m_settingsPath; + QString m_name; + + QString name() const; + void setName(const QString &name); + void createSettings(); +}; diff --git a/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp b/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp new file mode 100644 index 000000000..8e3485008 --- /dev/null +++ b/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp @@ -0,0 +1,186 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlsidebar.h" +#include "mainapplication.h" +#include "qztools.h" +#include "sidebar.h" +#include "qml/api/fileutils/qmlfileutils.h" +#include "qml/qmlengine.h" +#include "qml/qmlstaticdata.h" +#include +#include +#include + +QmlSideBar::QmlSideBar(QObject *parent) + : QObject(parent) +{ + m_sideBarHelper = new QmlSideBarHelper(this); + + connect(this, &QmlSideBar::titleChanged, m_sideBarHelper, &QmlSideBarHelper::setTitle); + connect(this, &QmlSideBar::iconChanged, m_sideBarHelper, &QmlSideBarHelper::setIcon); + connect(this, &QmlSideBar::shortcutChanged, m_sideBarHelper, &QmlSideBarHelper::setShortcut); + connect(this, &QmlSideBar::checkableChanged, m_sideBarHelper, &QmlSideBarHelper::setCheckable); + connect(this, &QmlSideBar::itemChanged, m_sideBarHelper, &QmlSideBarHelper::setItem); +} + +QmlSideBar::~QmlSideBar() +{ + SideBarManager::removeSidebar(m_sideBarHelper); +} + +void QmlSideBar::componentComplete() +{ + SideBarManager::addSidebar(name(), sideBar()); +} + +QString QmlSideBar::name() const +{ + return m_name; +} + +SideBarInterface *QmlSideBar::sideBar() const +{ + return m_sideBarHelper; +} + +void QmlSideBar::setName(const QString &name) +{ + m_name = name; + emit nameChanged(m_name); +} + +QString QmlSideBar::title() const +{ + return m_title; +} + +void QmlSideBar::setTitle(const QString &title) +{ + m_title = title; + emit titleChanged(title); +} + +QString QmlSideBar::icon() const +{ + return m_iconUrl; +} + +void QmlSideBar::setIcon(const QString &icon) +{ + m_iconUrl = icon; + emit iconChanged(m_iconUrl); +} + +QString QmlSideBar::shortcut() const +{ + return m_shortcut; +} + +void QmlSideBar::setShortcut(const QString &shortcut) +{ + m_shortcut = shortcut; + emit shortcutChanged(m_shortcut); +} + +bool QmlSideBar::checkable() +{ + return m_checkable; +} + +void QmlSideBar::setCheckable(bool checkable) +{ + m_checkable = checkable; + emit checkableChanged(m_checkable); +} + +QQmlComponent *QmlSideBar::item() const +{ + return m_item; +} + +void QmlSideBar::setItem(QQmlComponent *item) +{ + m_item = item; + emit itemChanged(m_item); +} + +QmlSideBarHelper::QmlSideBarHelper(QObject *parent) + : SideBarInterface(parent) +{ +} + +QString QmlSideBarHelper::title() const +{ + return m_title; +} + +QAction *QmlSideBarHelper::createMenuAction() +{ + QAction *action = new QAction(m_title); + action->setShortcut(QKeySequence(m_shortcut)); + action->setCheckable(m_checkable); + if (!m_item) { + return action; + } + auto qmlEngine = qobject_cast(m_item->creationContext()->engine()); + if (qmlEngine) { + return action; + } + const QString pluginPath = qmlEngine->extensionPath(); + QIcon icon = QmlStaticData::instance().getIcon(m_iconUrl, pluginPath); + action->setIcon(icon); + return action; +} + +QWidget *QmlSideBarHelper::createSideBarWidget(BrowserWindow *mainWindow) +{ + Q_UNUSED(mainWindow) + + QQuickWindow *window = qobject_cast(m_item->create(m_item->creationContext())); + if (!window) { + qWarning() << "Unable to create QQuickWindow"; + return nullptr; + } + + return QWidget::createWindowContainer(window); +} + +void QmlSideBarHelper::setTitle(const QString &title) +{ + m_title = title; +} + +void QmlSideBarHelper::setIcon(const QString &icon) +{ + m_iconUrl = icon; +} + +void QmlSideBarHelper::setShortcut(const QString &shortcut) +{ + m_shortcut = shortcut; +} + +void QmlSideBarHelper::setCheckable(bool checkable) +{ + m_checkable = checkable; +} + +void QmlSideBarHelper::setItem(QQmlComponent *item) +{ + m_item = item; +} diff --git a/src/lib/plugins/qml/api/sidebar/qmlsidebar.h b/src/lib/plugins/qml/api/sidebar/qmlsidebar.h new file mode 100644 index 000000000..08e3cc856 --- /dev/null +++ b/src/lib/plugins/qml/api/sidebar/qmlsidebar.h @@ -0,0 +1,159 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once +#include "sidebarinterface.h" +#include +#include + +class QmlSideBarHelper; + +/** + * @brief The class exposing SideBar API to QML + */ +class QmlSideBar : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + /** + * @brief name of the sidebar. This is required property. + */ + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + + /** + * @brief title of the sidebar action. + */ + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + + /** + * @brief icon path of the sidebar action. + * + * The icon path will be search in the following order + * - Theme icon: if the icon is found as a theme icon, then it will + * be used even if the icon file with same name is present + * in the plugin directory + * - Falkon resource: for the icons starting with ":", they are searched in + * falkon resource file + * - Files in plugin directory: All other paths will be resolved relative to + * the plugin directory. If the icon path is outside the + * plugin directory, then it will be resolved as empty path. + */ + Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged) + + /** + * @brief shortcut for the sidebar action. + */ + Q_PROPERTY(QString shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged) + + /** + * @brief represents whether the sidebar action is checkable + */ + Q_PROPERTY(bool checkable READ checkable WRITE setCheckable NOTIFY checkableChanged) + + /** + * @brief the GUI of the sidebar. This must be provided as QML Window. + * This is a default property. + */ + Q_PROPERTY(QQmlComponent* item READ item WRITE setItem NOTIFY itemChanged) + Q_CLASSINFO("DefaultProperty", "item") + +public: + explicit QmlSideBar(QObject *parent = nullptr); + ~QmlSideBar(); + void classBegin() {} + void componentComplete(); + QString name() const; + SideBarInterface *sideBar() const; + +Q_SIGNALS: + /** + * @brief This signal is emitted when name property is changed. + * @param QString represening name + */ + void nameChanged(const QString &name); + + /** + * @brief This signal is emitted when title property is changed + * @param QString representing title + */ + void titleChanged(const QString &title); + + /** + * @brief This signal is emitted when icon property is changed + * @param QString representing icon path url + */ + void iconChanged(const QString &icon); + + /** + * @brief This signal is emitted when shortcut property is changed + * @param QString representing shortcut + */ + void shortcutChanged(const QString &shortcut); + + /** + * @brief This signal is emitted when checkable property is changed + * @param checkable + */ + void checkableChanged(bool checkable); + void itemChanged(QQmlComponent *item); + +private: + QString m_name; + QString m_title; + QString m_iconUrl; + QString m_shortcut; + bool m_checkable; + QQmlComponent *m_item = nullptr; + + QmlSideBarHelper *m_sideBarHelper = nullptr; + + void setName(const QString &name); + QString title() const; + void setTitle(const QString &title); + QString icon() const; + void setIcon(const QString &icon); + QString shortcut() const; + void setShortcut(const QString &shortcut); + bool checkable(); + void setCheckable(bool checkable); + QQmlComponent *item() const; + void setItem(QQmlComponent *item); +}; + +class QmlSideBarHelper : public SideBarInterface +{ + Q_OBJECT +public: + explicit QmlSideBarHelper(QObject *parent = nullptr); + QString title() const; + QAction *createMenuAction(); + QWidget *createSideBarWidget(BrowserWindow *mainWindow); + + void setTitle(const QString &title); + void setIcon(const QString &icon); + void setShortcut(const QString &shortcut); + void setCheckable(bool checkable); + void setItem(QQmlComponent *item); + +private: + QString m_title; + QString m_iconUrl; + QString m_shortcut; + bool m_checkable = false; + QQmlComponent *m_item = nullptr; +}; diff --git a/src/lib/plugins/qml/api/tabs/qmltab.cpp b/src/lib/plugins/qml/api/tabs/qmltab.cpp new file mode 100644 index 000000000..64570734b --- /dev/null +++ b/src/lib/plugins/qml/api/tabs/qmltab.cpp @@ -0,0 +1,432 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmltab.h" +#include "loadrequest.h" +#include "tabbedwebview.h" +#include "webpage.h" +#include "qml/qmlstaticdata.h" +#include +#include + +QmlTab::QmlTab(WebTab *webTab, QObject *parent) + : QObject(parent) + , m_webTab(webTab) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); + + if (!m_webTab) { + return; + } + + createConnections(); +} + +void QmlTab::detach() +{ + if (!m_webTab) { + return; + } + + m_webTab->detach(); +} + +void QmlTab::setZoomLevel(int zoomLevel) +{ + if (!m_webTab) { + return; + } + + m_webTab->setZoomLevel(zoomLevel); +} + +void QmlTab::stop() +{ + if (!m_webTab) { + return; + } + + m_webTab->stop(); +} + +void QmlTab::reload() +{ + if (!m_webTab) { + return; + } + + m_webTab->reload(); +} + +void QmlTab::unload() +{ + if (!m_webTab) { + return; + } + + m_webTab->unload(); +} + +void QmlTab::load(const QString &url) +{ + if (!m_webTab) { + return; + } + + LoadRequest req; + req.setUrl(QUrl::fromEncoded(url.toUtf8())); + m_webTab->load(req); +} + +void QmlTab::zoomIn() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->zoomIn(); +} + +void QmlTab::zoomOut() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->zoomOut(); +} + +void QmlTab::zoomReset() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->zoomReset(); +} + +void QmlTab::undo() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->editUndo(); +} + +void QmlTab::redo() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->editRedo(); +} + +void QmlTab::selectAll() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->editSelectAll(); +} + +void QmlTab::reloadBypassCache() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->reloadBypassCache(); +} + +void QmlTab::back() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->back(); +} + +void QmlTab::forward() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->forward(); +} + +void QmlTab::printPage() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->printPage(); +} + +void QmlTab::showSource() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->showSource(); +} + +void QmlTab::sendPageByMail() +{ + if (!m_webTab) { + return; + } + + m_webTab->webView()->sendPageByMail(); +} + +QVariant QmlTab::execJavaScript(const QJSValue &value) +{ + if (!m_webPage && !m_webTab) { + return QVariant(); + } + WebPage *webPage = m_webPage; + if (!m_webPage) { + webPage = m_webTab->webView()->page(); + } + return webPage->execJavaScript(value.toString()); +} + +QmlWebHitTestResult *QmlTab::hitTestContent(const QPoint &point) +{ + if (!m_webPage && !m_webTab) { + return nullptr; + } + WebPage *webPage = m_webPage; + if (!m_webPage) { + webPage = m_webTab->webView()->page(); + } + WebHitTestResult result = webPage->hitTestContent(point); + return new QmlWebHitTestResult(result); +} + +QString QmlTab::url() const +{ + if (!m_webTab) { + return QString(); + } + + return QString::fromUtf8(m_webTab->url().toEncoded()); +} + +QString QmlTab::title() const +{ + if (!m_webTab) { + return QString(); + } + + return m_webTab->title(); +} + + +int QmlTab::zoomLevel() const +{ + if (!m_webTab) { + return -1; + } + + return m_webTab->zoomLevel(); +} + +int QmlTab::index() const +{ + if (!m_webTab) { + return -1; + } + + return m_webTab->tabIndex(); +} + +bool QmlTab::pinned() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->isPinned(); +} + +bool QmlTab::muted() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->isMuted(); +} + +bool QmlTab::restored() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->isRestored(); +} + +bool QmlTab::current() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->isCurrentTab(); +} + +bool QmlTab::playing() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->isPlaying(); +} + +QmlWindow *QmlTab::browserWindow() const +{ + if (!m_webTab) { + return nullptr; + } + + return QmlStaticData::instance().getWindow(m_webTab->browserWindow()); +} + +bool QmlTab::loading() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->webView()->isLoading(); +} + +int QmlTab::loadingProgress() const +{ + if (!m_webTab) { + return -1; + } + + return m_webTab->webView()->loadingProgress(); +} + +bool QmlTab::backgroundActivity() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->webView()->backgroundActivity(); +} + +bool QmlTab::canGoBack() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->webView()->history()->canGoBack(); +} + +bool QmlTab::canGoForward() const +{ + if (!m_webTab) { + return false; + } + + return m_webTab->webView()->history()->canGoForward(); +} + +void QmlTab::setWebPage(WebPage *webPage) +{ + if (m_webPage) { + removeConnections(); + } + m_webPage = webPage; + TabbedWebView *tabbedWebView = qobject_cast(m_webPage->view()); + m_webTab = tabbedWebView->webTab(); + if (m_webTab) { + createConnections(); + } +} + +void QmlTab::createConnections() +{ + Q_ASSERT(m_lambdaConnections.length() == 0); + + auto titleChangedConnection = connect(m_webTab, &WebTab::titleChanged, this, [this](const QString &title){ + emit titleChanged(title); + }); + m_lambdaConnections.append(titleChangedConnection); + + auto pinnedChangedConnection = connect(m_webTab, &WebTab::pinnedChanged, this, [this](bool pinned){ + emit pinnedChanged(pinned); + }); + m_lambdaConnections.append(pinnedChangedConnection); + + auto loadingChangedConnection = connect(m_webTab, &WebTab::loadingChanged, this, [this](bool loading){ + emit loadingChanged(loading); + }); + m_lambdaConnections.append(loadingChangedConnection); + + auto mutedChangedConnection = connect(m_webTab, &WebTab::mutedChanged, this, [this](bool muted){ + emit mutedChanged(muted); + }); + m_lambdaConnections.append(mutedChangedConnection); + + auto restoredChangedConnection = connect(m_webTab, &WebTab::restoredChanged, this, [this](bool restored){ + emit restoredChanged(restored); + }); + m_lambdaConnections.append(restoredChangedConnection); + + auto playingChangedConnection = connect(m_webTab, &WebTab::playingChanged, this, [this](bool playing){ + emit playingChanged(playing); + }); + m_lambdaConnections.append(playingChangedConnection); + + connect(m_webTab->webView(), &TabbedWebView::zoomLevelChanged, this, &QmlTab::zoomLevelChanged); + connect(m_webTab->webView(), &TabbedWebView::backgroundActivityChanged, this, &QmlTab::backgroundActivityChanged); + + if (m_webPage) { + connect(m_webPage, &WebPage::navigationRequestAccepted, this, &QmlTab::navigationRequestAccepted); + } +} + +void QmlTab::removeConnections() +{ + for (auto connection : qAsConst(m_lambdaConnections)) { + disconnect(connection); + } + m_lambdaConnections.clear(); + + disconnect(m_webTab->webView(), &TabbedWebView::zoomLevelChanged, this, &QmlTab::zoomLevelChanged); + disconnect(m_webTab->webView(), &TabbedWebView::backgroundActivityChanged, this, &QmlTab::backgroundActivityChanged); + + if (m_webPage) { + disconnect(m_webPage, &WebPage::navigationRequestAccepted, this, &QmlTab::navigationRequestAccepted); + } +} diff --git a/src/lib/plugins/qml/api/tabs/qmltab.h b/src/lib/plugins/qml/api/tabs/qmltab.h new file mode 100644 index 000000000..58454e049 --- /dev/null +++ b/src/lib/plugins/qml/api/tabs/qmltab.h @@ -0,0 +1,283 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include +#include + +#include "webtab.h" +#include "../windows/qmlwindow.h" +#include "qml/api/menus/qmlwebhittestresult.h" + +/** + * @brief The class exposing a browser tab to QML + */ +class QmlTab : public QObject +{ + Q_OBJECT + + /** + * @brief url of the tab + */ + Q_PROPERTY(QString url READ url CONSTANT) + + /** + * @brief title of the tab + */ + Q_PROPERTY(QString title READ title CONSTANT) + + /** + * @brief zoom level of the tab + * + * Zoom levels are from 0 to 18 + */ + Q_PROPERTY(int zoomLevel READ zoomLevel CONSTANT) + + /** + * @brief index of the tab + */ + Q_PROPERTY(int index READ index CONSTANT) + + /** + * @brief checks if the tab is pinned + */ + Q_PROPERTY(bool pinned READ pinned CONSTANT) + + /** + * @brief checks if the tab is muted + */ + Q_PROPERTY(bool muted READ muted CONSTANT) + + /** + * @brief checks if the tab is restored + */ + Q_PROPERTY(bool restored READ restored CONSTANT) + + /** + * @brief checks if the tab is the current tab + */ + Q_PROPERTY(bool current READ current CONSTANT) + + /** + * @brief checks if the tab is playing + */ + Q_PROPERTY(bool playing READ playing CONSTANT) + + /** + * @brief window of the tab + */ + Q_PROPERTY(QmlWindow* browserWindow READ browserWindow CONSTANT) + + /** + * @brief checks if the tab is loading + */ + Q_PROPERTY(bool loading READ loading CONSTANT) + + /** + * @brief get the loading progress of the tab + */ + Q_PROPERTY(int loadingProgress READ loadingProgress CONSTANT) + + /** + * @brief checks if the tab has associated background activity + */ + Q_PROPERTY(bool backgroundActivity READ backgroundActivity CONSTANT) + + /** + * @brief checks if the tab is can go back + */ + Q_PROPERTY(bool canGoBack READ canGoBack CONSTANT) + + /** + * @brief checks if the tab is can go forward + */ + Q_PROPERTY(bool canGoForward READ canGoForward CONSTANT) +public: + explicit QmlTab(WebTab *webTab = nullptr, QObject *parent = nullptr); + + /** + * @brief Detaches the tab + */ + Q_INVOKABLE void detach(); + /** + * @brief Set the zoom level of the tab + * @param Integer representing the zoom level + */ + Q_INVOKABLE void setZoomLevel(int zoomLevel); + /** + * @brief Stops webview associated with the tab + */ + Q_INVOKABLE void stop(); + /** + * @brief Reloads webview associated with the tab + */ + Q_INVOKABLE void reload(); + /** + * @brief Unloads the tab + */ + Q_INVOKABLE void unload(); + /** + * @brief Loads webview associated with the tab + * @param String representing the url to load + */ + Q_INVOKABLE void load(const QString &url); + /** + * @brief Decreases the zoom level of the tab + */ + Q_INVOKABLE void zoomIn(); + /** + * @brief Increases the zoom level of the tab + */ + Q_INVOKABLE void zoomOut(); + /** + * @brief Resets the tab zoom level + */ + Q_INVOKABLE void zoomReset(); + /** + * @brief Performs edit undo on the tab + */ + Q_INVOKABLE void undo(); + /** + * @brief Performs edit redo on the tab + */ + Q_INVOKABLE void redo(); + /** + * @brief Performs edit select-all on the tab + */ + Q_INVOKABLE void selectAll(); + /** + * @brief Reloads the tab by bypassing the cache + */ + Q_INVOKABLE void reloadBypassCache(); + /** + * @brief Loads the previous page + */ + Q_INVOKABLE void back(); + /** + * @brief Loads the next page + */ + Q_INVOKABLE void forward(); + /** + * @brief Prints the page + */ + Q_INVOKABLE void printPage(); + /** + * @brief Shows the page source + */ + Q_INVOKABLE void showSource(); + /** + * @brief Sends page by mail + */ + Q_INVOKABLE void sendPageByMail(); + /** + * @brief execute JavaScript function in a page + * @param value, representing JavaScript function + * @return QVariant, the return value of executed javascript + */ + Q_INVOKABLE QVariant execJavaScript(const QJSValue &value); + /** + * @brief Gets result of web hit test at a given point + * @param point + * @return result of web hit test + */ + Q_INVOKABLE QmlWebHitTestResult *hitTestContent(const QPoint &point); + + void setWebPage(WebPage *webPage); + +Q_SIGNALS: + /** + * @brief The signal emitted when the tab title is changed + * @param String representing the new title + */ + void titleChanged(const QString &title); + + /** + * @brief The signal emitted when pinned state of the tab is changed + * @param Bool representing if a tab is pinned + */ + void pinnedChanged(bool pinned); + + /** + * @brief The signal emitted when loading state of the tab is changed + * @param Bool representing if the tab is loading + */ + void loadingChanged(bool loading); + + /** + * @brief The signal emitted when muted state of the tab is changed + * @param Bool representing if the tab is muted + */ + void mutedChanged(bool muted); + + /** + * @brief The signal emitted when restored state of the tab is changed + * @param Bool representing if the tab is restored + */ + void restoredChanged(bool restored); + + /** + * @brief The signal emitted when playing state of the tab is changed + * @param Bool representing if the tab is in playing state + */ + void playingChanged(bool playing); + + /** + * @brief The signal emitted when zoom level of the tab is changed + * @param Integer representing the zoom level + */ + void zoomLevelChanged(int zoomLevel); + + /** + * @brief The signal emitted when background activity of the tab is changed + * @param Bool representing if there is background activity attached to the tab + */ + void backgroundActivityChanged(int backgroundActivityChanged); + + /** + * @brief The signal emitted when navigation request is accepted + * @param url, representing requested url + * @param type of navigation + * @param isMainFrame, represents if navigation is requested for a top level page. + */ + void navigationRequestAccepted(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame); + +private: + WebTab *m_webTab = nullptr; + WebPage *m_webPage = nullptr; + QList m_lambdaConnections; + + QString url() const; + QString title() const; + int zoomLevel() const; + int index() const; + bool pinned() const; + bool muted() const; + bool restored() const; + bool current() const; + bool playing() const; + QmlWindow *browserWindow() const; + bool loading() const; + int loadingProgress() const; + bool backgroundActivity() const; + bool canGoBack() const; + bool canGoForward() const; + + void createConnections(); + void removeConnections(); +}; diff --git a/src/lib/plugins/qml/api/tabs/qmltabs.cpp b/src/lib/plugins/qml/api/tabs/qmltabs.cpp new file mode 100644 index 000000000..d969c78e0 --- /dev/null +++ b/src/lib/plugins/qml/api/tabs/qmltabs.cpp @@ -0,0 +1,363 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmltabs.h" +#include "tabwidget.h" +#include "pluginproxy.h" +#include "qml/qmlstaticdata.h" +#include + +QmlTabs::QmlTabs(QObject *parent) + : QObject(parent) +{ + const QList windows = mApp->windows(); + for (BrowserWindow *window : windows) { + windowCreated(window); + } + + connect(mApp->plugins(), &PluginProxy::mainWindowCreated, this, &QmlTabs::windowCreated); +} + +bool QmlTabs::setCurrentIndex(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to set current index:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + window->tabWidget()->setCurrentIndex(index); + return true; +} + +bool QmlTabs::nextTab(int windowId) +{ + const auto window = getWindow(windowId); + if (!window) { + return false; + } + window->tabWidget()->nextTab(); + return true; +} + +bool QmlTabs::previousTab(int windowId) +{ + const auto window = getWindow(windowId); + if (!window) { + return false; + } + window->tabWidget()->previousTab(); + return true; +} + +bool QmlTabs::moveTab(const QVariantMap &map) +{ + if (!map.contains(QSL("from"))) { + qWarning() << "Unable to move tab:" << "from not defined"; + return false; + } + if (!map.contains(QSL("to"))) { + qWarning() << "Unable to move tab:" << "to not defined"; + return false; + } + + const int from = map.value(QSL("from")).toInt(); + const int to = map.value(QSL("to")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + window->tabWidget()->moveTab(from, to); + return true; +} + +bool QmlTabs::pinTab(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to pin tab:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + + WebTab *webTab = window->tabWidget()->webTab(index); + + if (webTab->isPinned()) { + return false; + } + + webTab->togglePinned(); + return true; +} + +bool QmlTabs::unpinTab(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to unpin tab:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + + WebTab *webTab = window->tabWidget()->webTab(index); + + if (!webTab->isPinned()) { + return false; + } + + webTab->togglePinned(); + return true; +} + +bool QmlTabs::detachTab(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to detatch tab:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + window->tabWidget()->detachTab(index); + return true; +} + +bool QmlTabs::duplicate(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to duplicate:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + window->tabWidget()->duplicateTab(index); + return true; +} + +bool QmlTabs::closeTab(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to close tab:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + window->tabWidget()->closeTab(index); + return true; +} + +bool QmlTabs::reloadTab(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to reload tab:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + window->tabWidget()->reloadTab(index); + return true; +} + +bool QmlTabs::stopTab(const QVariantMap &map) +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to close tab:" << "index not defined"; + return false; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return false; + } + window->tabWidget()->stopTab(index); + return true; +} + +QmlTab *QmlTabs::get(const QVariantMap &map) const +{ + if (!map.contains(QSL("index"))) { + qWarning() << "Unable to set current index:" << "index not defined"; + return nullptr; + } + + const int index = map.value(QSL("index")).toInt(); + + const auto window = getWindow(map); + if (!window) { + return nullptr; + } + const auto webTab = window->tabWidget()->webTab(index); + return QmlStaticData::instance().getTab(webTab); +} + +int QmlTabs::normalTabsCount(int windowId) const +{ + const auto window = getWindow(windowId); + if (!window) { + return -1; + } + return window->tabWidget()->normalTabsCount(); +} + +int QmlTabs::pinnedTabsCount(int windowId) const +{ + const auto window = getWindow(windowId); + if (!window) { + return -1; + } + return window->tabWidget()->pinnedTabsCount(); +} + +QList QmlTabs::getAll(const QVariantMap &map) const +{ + const auto window = getWindow(map); + if (!window) { + return QList(); + } + + const bool withPinned = map.value(QSL("withPinned")).toBool(); + const QList tabList = window->tabWidget()->allTabs(withPinned); + + QList list; + list.reserve(tabList.size()); + for (WebTab *tab : tabList) { + list.append(QmlStaticData::instance().getTab(tab)); + } + + return list; +} + +QList QmlTabs::search(const QVariantMap &map) +{ + const QString title = map.value(QSL("title")).toString(); + const QString url = map.value(QSL("url")).toString(); + const bool withPinned = map.value(QSL("withPinned")).toBool(); + QList list; + foreach (BrowserWindow *window, mApp->windows()) { + foreach (WebTab *webTab, window->tabWidget()->allTabs(withPinned)) { + if (webTab->title().contains(title, Qt::CaseInsensitive) + || QString::fromUtf8(webTab->url().toEncoded()).contains(url, Qt::CaseInsensitive)) { + list.append(QmlStaticData::instance().getTab(webTab)); + } + } + } + return list; +} + +bool QmlTabs::addTab(const QVariantMap &map) +{ + const QString urlString = map.value(QSL("url")).toString(); + const auto window = getWindow(map); + if (!window) { + qDebug() << "Unable to add tab:" << "window not found"; + return false; + } + LoadRequest req(QUrl::fromEncoded(urlString.toUtf8())); + const int ret = window->tabWidget()->addView(req); + return ret != -1 ? true : false; +} + +BrowserWindow *QmlTabs::getWindow(const QVariantMap &map) const +{ + const int windowId = map.value(QSL("windowId"), -1).toInt(); + return getWindow(windowId); +} + +BrowserWindow *QmlTabs::getWindow(int windowId) const +{ + if (windowId == -1) { + return mApp->getWindow(); + } + + auto windowIdHash = QmlStaticData::instance().windowIdHash(); + for (auto it = windowIdHash.cbegin(); it != windowIdHash.cend(); it++) { + BrowserWindow *window = it.key(); + if (QmlStaticData::instance().windowIdHash().value(window, -1) == windowId) { + return window; + } + } + qWarning() << "Unable to get window with given windowId"; + return nullptr; +} + +void QmlTabs::windowCreated(BrowserWindow *window) +{ + const int windowId = QmlStaticData::instance().windowIdHash().value(window, -1); + + connect(window->tabWidget(), &TabWidget::changed, this, [this, windowId]{ + emit changed(windowId); + }); + + connect(window->tabWidget(), &TabWidget::tabInserted, this, [this, windowId](int index){ + QVariantMap map; + map.insert(QSL("windowId"), windowId); + map.insert(QSL("index"), index); + emit tabInserted(map); + }); + + connect(window->tabWidget(), &TabWidget::tabRemoved, this, [this, windowId](int index){ + QVariantMap map; + map.insert(QSL("windowId"), windowId); + map.insert(QSL("index"), index); + emit tabRemoved(map); + }); + + connect(window->tabWidget(), &TabWidget::tabMoved, this, [this, windowId](int from, int to){ + QVariantMap map; + map.insert(QSL("windowId"), windowId); + map.insert(QSL("from"), from); + map.insert(QSL("to"), to); + emit tabMoved(map); + }); +} diff --git a/src/lib/plugins/qml/api/tabs/qmltabs.h b/src/lib/plugins/qml/api/tabs/qmltabs.h new file mode 100644 index 000000000..f068e95d3 --- /dev/null +++ b/src/lib/plugins/qml/api/tabs/qmltabs.h @@ -0,0 +1,233 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "mainapplication.h" +#include "qmltab.h" + +/** + * @brief The class exposing Tabs API to QML + */ +class QmlTabs : public QObject +{ + Q_OBJECT +public: + explicit QmlTabs(QObject *parent = nullptr); + /** + * @brief Sets the current tab in a window + * @param A JavaScript object containing + * - index: + * Integer representing new current index + * - windowId: + * The id of window containing the tab + * @return True if success, else false + */ + Q_INVOKABLE bool setCurrentIndex(const QVariantMap &map); + /** + * @brief Sets the next tab as current tab + * @param Integer representing the window + * @return True if success, else false + */ + Q_INVOKABLE bool nextTab(int windowId = -1); + /** + * @brief Sets the prvious tab as current tab + * @param Integer representing the window + * @return True if success, else false + */ + Q_INVOKABLE bool previousTab(int windowId = -1); + /** + * @brief Moves a tab + * @param A JavaScript object containing + * - from: + * The initial index of the tab + * - to: + * The final index of the tab + * - windowId: + * The id of window containing the tab + * @return True if tab is moved, else false + */ + Q_INVOKABLE bool moveTab(const QVariantMap &map); + /** + * @brief Pins a tab + * @param A JavaScript object containing + * - index: + * Integer representing the tab to be pinned + * - windowId: + * The id of window containing the tab + * @return True if success, else false + */ + Q_INVOKABLE bool pinTab(const QVariantMap &map); + /** + * @brief Un-pins a tab + * @param A JavaScript object containing + * - index: + * Integer representing the tab to be unpinned + * - windowId: + * The id of window containing the tab + * @return True if success, else false + */ + Q_INVOKABLE bool unpinTab(const QVariantMap &map); + /** + * @brief Detaches a tab + * @param A JavaScript object containing + * - index: + * Integer representing the tab to be detached + * - windowId: + * The id of window containing the tab + * @return True if tab is detached, else false + */ + Q_INVOKABLE bool detachTab(const QVariantMap &map); + /** + * @brief Duplicates a tab + * @param A JavaScript object containing + * - index: + * Integer representing the tab to duplicate + * - windowId: + * The id of window containing the tab + * @return True if success, else false + */ + Q_INVOKABLE bool duplicate(const QVariantMap &map); + /** + * @brief Close a tab + * @param A JavaScript object containing + * - index: + * Integer representing the tab to be closed + * - windowId: + * The id of window containing the tab + * @return True if success, else false + */ + Q_INVOKABLE bool closeTab(const QVariantMap &map); + /** + * @brief Reloads a tab + * @param A JavaScript object containing + * - index: + * Integer representing the tab to be reloaded + * - windowId: + * The id of window containing the tab + * @return True if success, else false + */ + Q_INVOKABLE bool reloadTab(const QVariantMap &map); + /** + * @brief Stops a tab + * @param A JavaScript object containing + * - index: + * Integer representing the tab to be stoped + * - windowId: + * The id of window containing the tab + * @return True if success, else false + */ + Q_INVOKABLE bool stopTab(const QVariantMap &map); + /** + * @brief Gets a tab + * @param A JavaScript object contining + * - index: + * Integer representign the index of the tab + * - windowId: + * The id of window containing the tab + * @return Tab of type [QmlTab](@ref QmlTab) if exists, else null + */ + Q_INVOKABLE QmlTab *get(const QVariantMap &map) const; + /** + * @brief Get the normal tabs count in a window + * @param Integer representing the window + * @return Number of normal tabs in the window + */ + Q_INVOKABLE int normalTabsCount(int windowId = -1) const; + /** + * @brief Get the pinned tabs count in a window + * @param Integer representing the window + * @return Number of pinned tabs in the window + */ + Q_INVOKABLE int pinnedTabsCount(int windowId = -1) const; + /** + * @brief Gets all the tabs of a window + * @param A JavaScript object containing + * - windowId: + * The id of window containing the tab + * - withPinned: + * Bool representing if the searched tab can be pinned + * @return List of tabs, each of type [QmlTab](@ref QmlTab) + */ + Q_INVOKABLE QList getAll(const QVariantMap &map = QVariantMap()) const; + /** + * @brief Searches tabs against a criteria + * @param A JavaScript object containing + * - title: + * String representing the title to be searched + * - url: + * String representing the url to be searched + * - withPinned: + * Bool representing if the searched tab can be pinned + * @return List of tabs, each of type [QmlTab](@ref QmlTab), which are + * matched against the criteria + */ + Q_INVOKABLE QList search(const QVariantMap &map); + /** + * @brief Adds a tab + * @param A JavaScript object containing + * - url: + * String representing the url of the tab + * - windowId: + * The id of window containing the tab + * @return True if the tab is added, else false + */ + Q_INVOKABLE bool addTab(const QVariantMap &map); +Q_SIGNALS: + /** + * @brief The signal emitted when tabs in the tab widget are changed + * @param window id representing the window in which the change occurs + */ + void changed(int windowId); + + /** + * @brief The signal emitted when a tab is inserted + * @param A JavaScript object containing + * - index: + * The index of the inserted tab + * - windowId: + * The id of window in which the tab is inserted + */ + void tabInserted(const QVariantMap &map); + + /** + * @brief The signal emitted when a tab is removed + * @param A JavaScript object containing + * - index: + * The index of the removed tab + * - windowId: + * The id of window in which the tab is removed + */ + void tabRemoved(const QVariantMap &map); + + /** + * @brief The signal emitted when a tab is moved + * @param A JavaScript object containing + * - from: + * The initial index of the moved tab + * - to: + * The final index of the moved tab + * - windowId: + * The id of window in which the tab is moved + */ + void tabMoved(const QVariantMap &map); +private: + BrowserWindow *getWindow(const QVariantMap &map) const; + BrowserWindow *getWindow(int windowId) const; + void windowCreated(BrowserWindow *window); +}; diff --git a/src/lib/plugins/qml/api/topsites/qmlmostvisitedurl.cpp b/src/lib/plugins/qml/api/topsites/qmlmostvisitedurl.cpp new file mode 100644 index 000000000..b9ca66ade --- /dev/null +++ b/src/lib/plugins/qml/api/topsites/qmlmostvisitedurl.cpp @@ -0,0 +1,37 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlmostvisitedurl.h" +#include + +QmlMostVisitedUrl::QmlMostVisitedUrl(const QString &title, const QString &url, QObject *parent) + : QObject(parent) + , m_title(title) + , m_url(url) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +QString QmlMostVisitedUrl::title() const +{ + return m_title; +} + +QString QmlMostVisitedUrl::url() const +{ + return m_url; +} diff --git a/src/lib/plugins/qml/api/topsites/qmlmostvisitedurl.h b/src/lib/plugins/qml/api/topsites/qmlmostvisitedurl.h new file mode 100644 index 000000000..baceb1cc0 --- /dev/null +++ b/src/lib/plugins/qml/api/topsites/qmlmostvisitedurl.h @@ -0,0 +1,49 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include +#include + +/** + * @brief The class exposing MostVisitedUrl type to QML + */ +class QmlMostVisitedUrl : public QObject +{ + Q_OBJECT + + /** + * @brief title of "most visited url" item + */ + Q_PROPERTY(QString title READ title CONSTANT) + + /** + * @brief url of "most visited url" item + */ + Q_PROPERTY(QString url READ url CONSTANT) +public: + explicit QmlMostVisitedUrl(const QString &title = QString(), const QString &url = QString(), QObject *parent = nullptr); + +private: + QString m_title; + QString m_url; + + QString title() const; + QString url() const; +}; diff --git a/src/lib/plugins/qml/api/topsites/qmltopsites.cpp b/src/lib/plugins/qml/api/topsites/qmltopsites.cpp new file mode 100644 index 000000000..7eddd1b13 --- /dev/null +++ b/src/lib/plugins/qml/api/topsites/qmltopsites.cpp @@ -0,0 +1,40 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmltopsites.h" +#include "speeddial.h" +#include "mainapplication.h" +#include "pluginproxy.h" +#include "qml/qmlstaticdata.h" +#include + +QmlTopSites::QmlTopSites(QObject *parent) + : QObject(parent) +{ +} + +QList QmlTopSites::get() const +{ + const QList pages = mApp->plugins()->speedDial()->pages(); + QList list; + list.reserve(pages.size()); + for(const SpeedDial::Page &page : pages) { + auto mostVisitedUrl = QmlStaticData::instance().getMostVisitedUrl(page.title, page.url); + list.append(mostVisitedUrl); + } + return list; +} diff --git a/src/lib/plugins/qml/api/topsites/qmltopsites.h b/src/lib/plugins/qml/api/topsites/qmltopsites.h new file mode 100644 index 000000000..4d52dbae0 --- /dev/null +++ b/src/lib/plugins/qml/api/topsites/qmltopsites.h @@ -0,0 +1,37 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "qmlmostvisitedurl.h" + +/** + * @brief The class exposing TopSites API to QML + */ +class QmlTopSites : public QObject +{ + Q_OBJECT +public: + explicit QmlTopSites(QObject *parent = nullptr); + /** + * @brief Get the topsites. These refer to the sites which + * are displayed in the speed-dial (New tab page) + * @return List of MostVisitedUrl objects of type [QmlMostVisitedUrl](@ref QmlMostVisitedUrl) + */ + Q_INVOKABLE QList get() const; +}; diff --git a/src/lib/plugins/qml/api/userscript/qmlexternaljsobject.cpp b/src/lib/plugins/qml/api/userscript/qmlexternaljsobject.cpp new file mode 100644 index 000000000..b69458fb2 --- /dev/null +++ b/src/lib/plugins/qml/api/userscript/qmlexternaljsobject.cpp @@ -0,0 +1,54 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlexternaljsobject.h" +#include "javascript/externaljsobject.h" +#include + +QmlExternalJsObject::QmlExternalJsObject(QObject *parent) + : QObject(parent) +{ +} + +QmlExternalJsObject::~QmlExternalJsObject() +{ + for (QObject *object : qAsConst(m_objects)) { + ExternalJsObject::unregisterExtraObject(object); + } +} + +void QmlExternalJsObject::registerExtraObject(const QVariantMap &map) +{ + if (!map.contains(QSL("id")) || !map.contains(QSL("object"))) { + qWarning() << "Unable to call" << __FUNCTION__ << ": unsufficient parameters"; + return; + } + + const QString id = map.value(QSL("id")).toString(); + QObject *object = qvariant_cast(map.value(QSL("object"))); + if (!object) { + qWarning() << "Unable to cast to QObject"; + return; + } + ExternalJsObject::registerExtraObject(id, object); + m_objects.append(object); +} + +void QmlExternalJsObject::unregisterExtraObject(QObject *object) +{ + ExternalJsObject::unregisterExtraObject(object); +} diff --git a/src/lib/plugins/qml/api/userscript/qmlexternaljsobject.h b/src/lib/plugins/qml/api/userscript/qmlexternaljsobject.h new file mode 100644 index 000000000..f2f298738 --- /dev/null +++ b/src/lib/plugins/qml/api/userscript/qmlexternaljsobject.h @@ -0,0 +1,32 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +class QmlExternalJsObject : public QObject +{ + Q_OBJECT +public: + explicit QmlExternalJsObject(QObject *parent = nullptr); + ~QmlExternalJsObject(); + Q_INVOKABLE void registerExtraObject(const QVariantMap &map); + Q_INVOKABLE void unregisterExtraObject(QObject *object); +private: + QList m_objects; +}; diff --git a/src/lib/plugins/qml/api/userscript/qmluserscript.cpp b/src/lib/plugins/qml/api/userscript/qmluserscript.cpp new file mode 100644 index 000000000..b4c3617fc --- /dev/null +++ b/src/lib/plugins/qml/api/userscript/qmluserscript.cpp @@ -0,0 +1,117 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmluserscript.h" + +QmlUserScript::QmlUserScript(QObject *parent) + : QObject(parent) +{ +} + +QWebEngineScript QmlUserScript::webEngineScript() const +{ + return m_webEngineScript; +} + +void QmlUserScript::setWebEngineScript(const QWebEngineScript &script) +{ + m_webEngineScript = script; +} + +bool QmlUserScript::null() const +{ + return m_webEngineScript.isNull(); +} + +QString QmlUserScript::name() const +{ + return m_webEngineScript.name(); +} + +void QmlUserScript::setName(const QString &name) +{ + m_webEngineScript.setName(name); + emit nameChanged(name); +} + +bool QmlUserScript::runsOnSubFrames() const +{ + return m_webEngineScript.runsOnSubFrames(); +} + +void QmlUserScript::setRunsOnSubFrames(bool runsOnSubFrames) +{ + m_webEngineScript.setRunsOnSubFrames(runsOnSubFrames); + emit runsOnSubFramesChanged(runsOnSubFrames); +} + +int QmlUserScript::worldId() const +{ + return static_cast(m_webEngineScript.worldId()); +} + +void QmlUserScript::setWorldId(int worldId) +{ + switch (worldId) { + case QWebEngineScript::MainWorld: + m_webEngineScript.setWorldId(QWebEngineScript::MainWorld); + break; + case QWebEngineScript::ApplicationWorld: + m_webEngineScript.setWorldId(QWebEngineScript::ApplicationWorld); + break; + case QWebEngineScript::UserWorld: + m_webEngineScript.setWorldId(QWebEngineScript::UserWorld); + break; + default: + break; + } + emit worldIdChanged(worldId); +} + +QString QmlUserScript::sourceCode() const +{ + return m_webEngineScript.sourceCode(); +} + +void QmlUserScript::setSourceCode(const QString &sourceCode) +{ + m_webEngineScript.setSourceCode(sourceCode); + emit sourceCodeChanged(sourceCode); +} + +QmlUserScript::InjectionPoint QmlUserScript::injectionPoint() const +{ + return (InjectionPoint)m_webEngineScript.injectionPoint(); +} + +void QmlUserScript::setInjectionPoint(InjectionPoint injectionPoint) +{ + switch (injectionPoint) { + case QWebEngineScript::DocumentCreation: + m_webEngineScript.setInjectionPoint(QWebEngineScript::DocumentCreation); + break; + case QWebEngineScript::DocumentReady: + m_webEngineScript.setInjectionPoint(QWebEngineScript::DocumentReady); + break; + case QWebEngineScript::Deferred: + m_webEngineScript.setInjectionPoint(QWebEngineScript::Deferred); + break; + default: + break; + } + emit injectionPointChanged(injectionPoint); +} diff --git a/src/lib/plugins/qml/api/userscript/qmluserscript.h b/src/lib/plugins/qml/api/userscript/qmluserscript.h new file mode 100644 index 000000000..5a6944256 --- /dev/null +++ b/src/lib/plugins/qml/api/userscript/qmluserscript.h @@ -0,0 +1,113 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "qzcommon.h" + +#include +#include + +/** + * @brief The class exposing QWebEngineScript to QML + */ +class FALKON_EXPORT QmlUserScript : public QObject +{ + Q_OBJECT + /** + * @brief Checks if the UserScript is null + */ + Q_PROPERTY(bool null READ null CONSTANT) + /** + * @brief Name of the UserScript + */ + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + /** + * @brief Checks if the UserScript runs on sub frames + */ + Q_PROPERTY(bool runsOnSubFrames READ runsOnSubFrames WRITE setRunsOnSubFrames NOTIFY runsOnSubFramesChanged) + /** + * @brief WorldId of the UserScript + */ + Q_PROPERTY(int worldId READ worldId WRITE setWorldId NOTIFY worldIdChanged) + /** + * @brief Source code of the UserScript + */ + Q_PROPERTY(QString sourceCode READ sourceCode WRITE setSourceCode NOTIFY sourceCodeChanged) + /** + * @brief Injection point of the UserScript + */ + Q_PROPERTY(InjectionPoint injectionPoint READ injectionPoint WRITE setInjectionPoint NOTIFY injectionPointChanged) +public: + /** + * @brief The enum exposing QWebEngineScript::InjectionPoint + */ + enum InjectionPoint { + DocumentCreation = QWebEngineScript::DocumentCreation, //!< Represents QWebEngineScript::DocumentCreation + DocumentReady = QWebEngineScript::DocumentReady, //!< Represents QWebEngineScript::DocumentReady, + Deferred = QWebEngineScript::Deferred //!< Represents QWebEngineScript::Deferred + }; + /** + * @brief The enum wrapping QWebEngineScript::ScriptWorldId + */ + enum ScriptWorldId { + MainWorld = QWebEngineScript::MainWorld, //!< Represents QWebEngineScript::MainWorld + ApplicationWorld = QWebEngineScript::ApplicationWorld, //!< Represents QWebEngineScript::ApplicationWorld + UserWorld = QWebEngineScript::UserWorld //! < Represents QWebEngineScript::UserWorld + }; + Q_ENUM(InjectionPoint) + Q_ENUM(ScriptWorldId) + + explicit QmlUserScript(QObject *parent = nullptr); + QWebEngineScript webEngineScript() const; + void setWebEngineScript(const QWebEngineScript &script); +Q_SIGNALS: + /** + * @brief The signal emitted when the script name is changed + */ + void nameChanged(const QString &name); + /** + * @brief The signal emitted when runsOnSubFrame property of the script is changed + */ + void runsOnSubFramesChanged(bool runsOnSubFrames); + /** + * @brief The signal emitted when worldId property of the script is changed + */ + void worldIdChanged(int worldId); + /** + * @brief The signal emitted when source code of the script is changed + */ + void sourceCodeChanged(const QString &sourceCode); + /** + * @brief The signal emitted when injectionPoint property of the script is changed + */ + void injectionPointChanged(int injectionPoint); +private: + QWebEngineScript m_webEngineScript; + + bool null() const; + QString name() const; + void setName(const QString &name); + bool runsOnSubFrames() const; + void setRunsOnSubFrames(bool runsOnSubFrames); + int worldId() const; + void setWorldId(int worldId); + QString sourceCode() const; + void setSourceCode(const QString &sourceCode); + InjectionPoint injectionPoint() const; + void setInjectionPoint(InjectionPoint injectionPoint); +}; diff --git a/src/lib/plugins/qml/api/userscript/qmluserscripts.cpp b/src/lib/plugins/qml/api/userscript/qmluserscripts.cpp new file mode 100644 index 000000000..0a43ff1b7 --- /dev/null +++ b/src/lib/plugins/qml/api/userscript/qmluserscripts.cpp @@ -0,0 +1,126 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmluserscripts.h" +#include "mainapplication.h" +#include +#include +#include + +QmlUserScripts::QmlUserScripts(QObject *parent) + : QObject(parent) +{ +} + +QmlUserScripts::~QmlUserScripts() +{ + // remove scripts added by the plugin + for (const QWebEngineScript &webEngineScript : qAsConst(m_webEngineScripts)) { + mApp->webProfile()->scripts()->remove(webEngineScript); + } +} + +int QmlUserScripts::count() const +{ + return mApp->webProfile()->scripts()->count(); +} + +int QmlUserScripts::size() const +{ + return mApp->webProfile()->scripts()->size(); +} + +bool QmlUserScripts::empty() const +{ + return mApp->webProfile()->scripts()->isEmpty(); +} + +QList QmlUserScripts::toQObjectList(const QList &list) const +{ + QList userScriptList; + userScriptList.reserve(list.size()); + for (const QWebEngineScript &script : list) { + QmlUserScript *userScript = new QmlUserScript(); + userScript->setWebEngineScript(script); + userScriptList.append(userScript); + } + return userScriptList; +} + +bool QmlUserScripts::contains(QObject *object) const +{ + QmlUserScript *userScript = qobject_cast(object); + if (!userScript) { + return false; + } + QWebEngineScript webEngineScript = userScript->webEngineScript(); + return mApp->webProfile()->scripts()->contains(webEngineScript); +} + +QObject *QmlUserScripts::findScript(const QString &name) const +{ + QWebEngineScript webEngineScript = mApp->webProfile()->scripts()->findScript(name); + QmlUserScript *qmlUserScript = new QmlUserScript(); + qmlUserScript->setWebEngineScript(webEngineScript); + return qmlUserScript; +} + +QList QmlUserScripts::findScripts(const QString &name) const +{ + QList list = mApp->webProfile()->scripts()->findScripts(name); + return toQObjectList(list); +} + +void QmlUserScripts::insert(QObject *object) +{ + QmlUserScript *userScript = qobject_cast(object); + if (!userScript) { + return; + } + QWebEngineScript webEngineScript = userScript->webEngineScript(); + mApp->webProfile()->scripts()->insert(webEngineScript); + m_webEngineScripts.append(webEngineScript); +} + +void QmlUserScripts::insert(const QList &list) +{ + for (QObject *object : list) { + QmlUserScript *userScript = qobject_cast(object); + if (!userScript) { + continue; + } + QWebEngineScript webEngineScript = userScript->webEngineScript(); + mApp->webProfile()->scripts()->insert(webEngineScript); + m_webEngineScripts.append(webEngineScript); + } +} + +void QmlUserScripts::remove(QObject *object) const +{ + QmlUserScript *userScript = qobject_cast(object); + if (!userScript) { + return; + } + QWebEngineScript webEngineScript = userScript->webEngineScript(); + mApp->webProfile()->scripts()->remove(webEngineScript); +} + +QList QmlUserScripts::toList() const +{ + QList list = mApp->webProfile()->scripts()->toList(); + return toQObjectList(list); +} diff --git a/src/lib/plugins/qml/api/userscript/qmluserscripts.h b/src/lib/plugins/qml/api/userscript/qmluserscripts.h new file mode 100644 index 000000000..0ec22658c --- /dev/null +++ b/src/lib/plugins/qml/api/userscript/qmluserscripts.h @@ -0,0 +1,88 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "qmluserscript.h" +#include + +/** + * @brief The class exposing QWebEngineScriptCollection to QML + */ +class FALKON_EXPORT QmlUserScripts : public QObject +{ + Q_OBJECT + /** + * @brief Number of elements in the collection + */ + Q_PROPERTY(int count READ count CONSTANT) + /** + * @brief Size of the collection + */ + Q_PROPERTY(int size READ size CONSTANT) + /** + * @brief Checks if the collection is empty + */ + Q_PROPERTY(bool empty READ empty CONSTANT) +public: + explicit QmlUserScripts(QObject *parent = nullptr); + ~QmlUserScripts(); + /** + * @brief Checks if the script is in collection + * @param object of type QmlUserScript + * @return true if the the script in in collection, else false + */ + Q_INVOKABLE bool contains(QObject *object) const; + /** + * @brief Finds a script in collection by name + * @param name of the script + * @return object of type QmlUserScript, representing the script of given name + */ + Q_INVOKABLE QObject *findScript(const QString &name) const; + /** + * @brief Finds all scripts in collection by a given name + * @return list of objects, each of type QmlUserScript, representing the script of given name + */ + Q_INVOKABLE QList findScripts(const QString &name) const; + /** + * @brief Inserts a script into collection + * @param object of type QmlUserScript + */ + Q_INVOKABLE void insert(QObject *object); + /** + * @brief Inserts a list of scripts into collection + * @param list of objects, each of type QmlUserScript + */ + Q_INVOKABLE void insert(const QList &list); + /** + * @brief Removes a script from collection + * @param object of type QmlUserScript + */ + Q_INVOKABLE void remove(QObject *object) const; + /** + * @brief Gets all the scripts of the collection + * @return list of objects, each of type QmlUserScript + */ + Q_INVOKABLE QList toList() const; +private: + int count() const; + int size() const; + bool empty() const; + QList m_webEngineScripts; + + QList toQObjectList(const QList &list) const; +}; diff --git a/src/lib/plugins/qml/api/windows/qmlwindow.cpp b/src/lib/plugins/qml/api/windows/qmlwindow.cpp new file mode 100644 index 000000000..591c59684 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindow.cpp @@ -0,0 +1,131 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlwindow.h" +#include "mainapplication.h" +#include "../tabs/qmltab.h" +#include "tabwidget.h" +#include "qml/qmlstaticdata.h" +#include + +QmlWindow::QmlWindow(BrowserWindow *window, QObject *parent) + : QObject(parent) + , m_window(window) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +int QmlWindow::id() const +{ + if (!QmlStaticData::instance().windowIdHash().contains(m_window)) { + return -1; + } + + return QmlStaticData::instance().windowIdHash().value(m_window, -1); +} + +bool QmlWindow::incognito() const +{ + return mApp->isPrivate(); +} + +QString QmlWindow::title() const +{ + if (!m_window) { + return QString(); + } + + return m_window->windowTitle(); +} + +QmlWindowState::WindowState QmlWindow::state() const +{ + if (!m_window) { + return QmlWindowState::Invalid; + } + + if (m_window->isFullScreen()) { + return QmlWindowState::FullScreen; + } else if (m_window->isMaximized()) { + return QmlWindowState::Maximized; + } else if (m_window->isMinimized()) { + return QmlWindowState::Minimized; + } else { + return QmlWindowState::Normal; + } +} + +QmlWindowType::WindowType QmlWindow::type() const +{ + if (!m_window) { + return QmlWindowType::OtherRestoredWindow; + } + + switch (m_window->windowType()) { + case Qz::BW_FirstAppWindow: + return QmlWindowType::FirstAppWindow; + case Qz::BW_MacFirstWindow: + return QmlWindowType::MacFirstWindow; + case Qz::BW_NewWindow: + return QmlWindowType::NewWindow; + default: + return QmlWindowType::OtherRestoredWindow; + } +} + +QList QmlWindow::tabs() const +{ + if (!m_window) { + return QList(); + } + + QList list; + const QList allTabs = m_window->tabWidget()->allTabs(true); + list.reserve(allTabs.size()); + for (WebTab *tab : allTabs) { + list.append(new QmlTab(tab)); + } + + return list; +} + +bool QmlWindow::focussed() const +{ + if (!m_window) { + return false; + } + + return m_window->isActiveWindow(); +} + +int QmlWindow::height() const +{ + if (!m_window) { + return -1; + } + + return m_window->height(); +} + +int QmlWindow::width() const +{ + if (!m_window) { + return -1; + } + + return m_window->width(); +} diff --git a/src/lib/plugins/qml/api/windows/qmlwindow.h b/src/lib/plugins/qml/api/windows/qmlwindow.h new file mode 100644 index 000000000..c2abf6ee5 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindow.h @@ -0,0 +1,91 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "browserwindow.h" +#include "qmlwindowstate.h" +#include "qmlwindowtype.h" + +/** + * @brief The class exposing Browser window to QML + */ +class QmlWindow : public QObject +{ + Q_OBJECT + + /** + * @brief id of window + */ + Q_PROPERTY(int id READ id CONSTANT) + + /** + * @brief checks if the window is private + */ + Q_PROPERTY(bool incognito READ incognito CONSTANT) + + /** + * @brief title of window + */ + Q_PROPERTY(QString title READ title CONSTANT) + + /** + * @brief [window state](@ref QmlWindowState::WindowState) of window + */ + Q_PROPERTY(QmlWindowState::WindowState state READ state CONSTANT) + + /** + * @brief [window type](@ref QmlWindowType::WindowType) of window + */ + Q_PROPERTY(QmlWindowType::WindowType type READ type CONSTANT) + + /** + * @brief list of all tabs of window + */ + Q_PROPERTY(QList tabs READ tabs CONSTANT) + + /** + * @brief checks if the window is focussed + */ + Q_PROPERTY(bool focussed READ focussed CONSTANT) + + /** + * @brief height of window + */ + Q_PROPERTY(int height READ height CONSTANT) + + /** + * @brief width of window + */ + Q_PROPERTY(int width READ width CONSTANT) +public: + QmlWindow(BrowserWindow *window = nullptr, QObject *parent = nullptr); + +private: + BrowserWindow *m_window = nullptr; + + int id() const; + bool incognito() const; + QString title() const; + QmlWindowState::WindowState state() const; + QmlWindowType::WindowType type() const; + QList tabs() const; + bool focussed() const; + int height() const; + int width() const; +}; diff --git a/src/lib/plugins/qml/api/windows/qmlwindows.cpp b/src/lib/plugins/qml/api/windows/qmlwindows.cpp new file mode 100644 index 000000000..2a3bbc0a3 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindows.cpp @@ -0,0 +1,84 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlwindows.h" +#include "mainapplication.h" +#include "pluginproxy.h" +#include "qml/qmlstaticdata.h" +#include + +QmlWindows::QmlWindows(QObject *parent) + : QObject(parent) +{ + connect(mApp->plugins(), &PluginProxy::mainWindowCreated, this, [this](BrowserWindow *window){ + QmlWindow *qmlWindow = QmlStaticData::instance().getWindow(window); + emit created(qmlWindow); + }); + + connect(mApp->plugins(), &PluginProxy::mainWindowDeleted, this, [this](BrowserWindow *window){ + QmlWindow *qmlWindow = QmlStaticData::instance().getWindow(window); + emit removed(qmlWindow); + }); +} + +QmlWindow *QmlWindows::get(int id) const +{ + return QmlStaticData::instance().getWindow(getBrowserWindow(id)); +} + +QmlWindow *QmlWindows::getCurrent() const +{ + return QmlStaticData::instance().getWindow(mApp->getWindow()); +} + +QList QmlWindows::getAll() const +{ + QList list; + const QList windows = mApp->windows(); + list.reserve(windows.size()); + for (BrowserWindow *window : windows) { + list.append(QmlStaticData::instance().getWindow(window)); + } + return list; +} + +QmlWindow *QmlWindows::create(const QVariantMap &map) const +{ + const QUrl url = QUrl::fromEncoded(map.value(QSL("url")).toString().toUtf8()); + const Qz::BrowserWindowType type = Qz::BrowserWindowType(map.value(QSL("type"), QmlWindowType::NewWindow).toInt()); + BrowserWindow *window = mApp->createWindow(type, url); + return QmlStaticData::instance().getWindow(window); +} + +void QmlWindows::remove(int windowId) const +{ + BrowserWindow *window = getBrowserWindow(windowId); + window->close(); +} + +BrowserWindow *QmlWindows::getBrowserWindow(int windowId) const +{ + const QList windows = mApp->windows(); + for (BrowserWindow *window : windows) { + if (QmlStaticData::instance().windowIdHash().value(window, -1) == windowId) { + return window; + } + } + + qWarning() << "Unable to get window with given id"; + return nullptr; +} diff --git a/src/lib/plugins/qml/api/windows/qmlwindows.h b/src/lib/plugins/qml/api/windows/qmlwindows.h new file mode 100644 index 000000000..835ee71d6 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindows.h @@ -0,0 +1,76 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "qmlwindow.h" + +/** + * @brief The class exposing Windows API to QML + */ +class QmlWindows : public QObject +{ + Q_OBJECT +public: + QmlWindows(QObject *parent = nullptr); + /** + * @brief Gets a browser window + * @param Integer representing the browser window + * @return Object of type [QmlWindow](@ref QmlWindow) + */ + Q_INVOKABLE QmlWindow *get(int id) const; + /** + * @brief Gets the current browser window + * @return Object of type [QmlWindow](@ref QmlWindow) + */ + Q_INVOKABLE QmlWindow *getCurrent() const; + /** + * @brief Get all the browser window + * @return List of windows of type [QmlWindow](@ref QmlWindow) + */ + Q_INVOKABLE QList getAll() const; + /** + * @brief Creates a browser window + * @param A JavaScript object containing + * - url: + * The url of the first tab of the window + * - type: + * The window [type](@ref QmlWindowType) + * @return + */ + Q_INVOKABLE QmlWindow *create(const QVariantMap &map) const; + /** + * @brief Removes a browser window + * @param Integer representing the window id + */ + Q_INVOKABLE void remove(int windowId) const; +Q_SIGNALS: + /** + * @brief The signal emitted when a window is created + * @param Object of type [QmlWindow](@ref QmlWindow) + */ + void created(QmlWindow *window); + + /** + * @brief The signal emitted when a window is removed + * @param Object of type [QmlWindow](@ref QmlWindow) + */ + void removed(QmlWindow *window); +private: + BrowserWindow *getBrowserWindow(int windowId) const; +}; diff --git a/src/lib/plugins/qml/api/windows/qmlwindowstate.cpp b/src/lib/plugins/qml/api/windows/qmlwindowstate.cpp new file mode 100644 index 000000000..80616e385 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindowstate.cpp @@ -0,0 +1,23 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlwindowstate.h" + +QmlWindowState::QmlWindowState(QObject *parent) + : QObject(parent) +{ +} diff --git a/src/lib/plugins/qml/api/windows/qmlwindowstate.h b/src/lib/plugins/qml/api/windows/qmlwindowstate.h new file mode 100644 index 000000000..76f6f461f --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindowstate.h @@ -0,0 +1,42 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +/** + * @brief The class exposing window state to QML + */ +class QmlWindowState : public QObject +{ + Q_OBJECT +public: + /** + * @brief The WindowState enum + */ + enum WindowState { + FullScreen, //! Represents full screen window + Maximized, //! Represents maximized window + Minimized, //! Represents minimized window + Normal, //! Represents normal window + Invalid //! Represents a invalid window + }; + Q_ENUM(WindowState) + + QmlWindowState(QObject *parent = nullptr); +}; diff --git a/src/lib/plugins/qml/api/windows/qmlwindowtype.cpp b/src/lib/plugins/qml/api/windows/qmlwindowtype.cpp new file mode 100644 index 000000000..90c40cf67 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindowtype.cpp @@ -0,0 +1,23 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlwindowtype.h" + +QmlWindowType::QmlWindowType(QObject *parent) + : QObject(parent) +{ +} diff --git a/src/lib/plugins/qml/api/windows/qmlwindowtype.h b/src/lib/plugins/qml/api/windows/qmlwindowtype.h new file mode 100644 index 000000000..aba851e35 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindowtype.h @@ -0,0 +1,42 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include "qzcommon.h" + +/** + * @brief The class exposing window type to QML + */ +class QmlWindowType : public QObject +{ + Q_OBJECT +public: + /** + * @brief The WindowType enum + */ + enum WindowType { + FirstAppWindow = Qz::BW_FirstAppWindow, //! Represents first app window + MacFirstWindow = Qz::BW_MacFirstWindow, //! Represents first mac window + NewWindow = Qz::BW_NewWindow, //! Represents new window + OtherRestoredWindow = Qz::BW_OtherRestoredWindow //! Represents other restored window + }; + Q_ENUM(WindowType) + + QmlWindowType(QObject *parent = nullptr); +}; diff --git a/src/lib/plugins/qml/qmlengine.cpp b/src/lib/plugins/qml/qmlengine.cpp new file mode 100644 index 000000000..131d5b2a4 --- /dev/null +++ b/src/lib/plugins/qml/qmlengine.cpp @@ -0,0 +1,43 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlengine.h" + +QmlEngine::QmlEngine(QObject *parent) + : QQmlEngine(parent) +{ +} + +QString QmlEngine::extensionName() +{ + return m_extensionName; +} + +void QmlEngine::setExtensionName(const QString &name) +{ + m_extensionName = name; +} + +QString QmlEngine::extensionPath() +{ + return m_extensionPath; +} + +void QmlEngine::setExtensionPath(const QString &path) +{ + m_extensionPath = path; +} diff --git a/src/lib/plugins/qml/qmlengine.h b/src/lib/plugins/qml/qmlengine.h new file mode 100644 index 000000000..064774c97 --- /dev/null +++ b/src/lib/plugins/qml/qmlengine.h @@ -0,0 +1,34 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include + +class QmlEngine : public QQmlEngine +{ + Q_OBJECT +public: + explicit QmlEngine(QObject *parent = nullptr); + QString extensionName(); + void setExtensionName(const QString &name); + QString extensionPath(); + void setExtensionPath(const QString &path); +private: + QString m_extensionName; + QString m_extensionPath; +}; diff --git a/src/lib/plugins/qml/qmlplugin.cpp b/src/lib/plugins/qml/qmlplugin.cpp new file mode 100644 index 000000000..3b6915fef --- /dev/null +++ b/src/lib/plugins/qml/qmlplugin.cpp @@ -0,0 +1,77 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlplugin.h" +#include "qmlplugins.h" +#include "datapaths.h" +#include "desktopfile.h" + +#include +#include + +QmlPlugin::QmlPlugin() +{ +} + +Plugins::Plugin QmlPlugin::loadPlugin(const QString &name) +{ + static bool qmlSupportLoaded = false; + if (!qmlSupportLoaded) { + QmlPlugins::registerQmlTypes(); + qmlSupportLoaded = true; + } + + QString fullPath; + if (QFileInfo(name).isAbsolute()) { + fullPath = name; + } else { + fullPath = DataPaths::locate(DataPaths::Plugins, QSL("qml/") + name); + if (fullPath.isEmpty()) { + qWarning() << "Plugin" << name << "not found"; + return Plugins::Plugin(); + } + } + + Plugins::Plugin plugin; + plugin.type = Plugins::Plugin::QmlPlugin; + plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName()); + DesktopFile desktopFile(fullPath + QSL("/metadata.desktop")); + plugin.pluginSpec = Plugins::createSpec(desktopFile); + QString entryPoint = desktopFile.value(QSL("X-Falkon-EntryPoint")).toString(); + plugin.data = QVariant::fromValue(new QmlPluginLoader(plugin.pluginSpec.name, fullPath, entryPoint)); + return plugin; +} + +void QmlPlugin::initPlugin(Plugins::Plugin *plugin) +{ + Q_ASSERT(plugin->type == Plugins::Plugin::QmlPlugin); + + const QString name = plugin->pluginSpec.name; + + auto qmlPluginLoader = plugin->data.value(); + if (!qmlPluginLoader) { + qWarning() << "Failed to cast from data"; + return; + } + qmlPluginLoader->createComponent(); + if (!qmlPluginLoader->instance()) { + qWarning().noquote() << "Falied to create component for" << name << "plugin:" << qmlPluginLoader->component()->errorString(); + return; + } + + plugin->instance = qobject_cast(qmlPluginLoader->instance()); +} diff --git a/src/lib/plugins/qml/qmlplugin.h b/src/lib/plugins/qml/qmlplugin.h new file mode 100644 index 000000000..7956de547 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugin.h @@ -0,0 +1,28 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "plugins.h" + +class QmlPlugin +{ +public: + explicit QmlPlugin(); + static Plugins::Plugin loadPlugin(const QString &name); + static void initPlugin(Plugins::Plugin *plugin); +}; diff --git a/src/lib/plugins/qml/qmlplugininterface.cpp b/src/lib/plugins/qml/qmlplugininterface.cpp new file mode 100644 index 000000000..54547d541 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugininterface.cpp @@ -0,0 +1,397 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlplugininterface.h" +#include "mainapplication.h" +#include "pluginproxy.h" +#include "statusbar.h" +#include "browserwindow.h" +#include "navigationbar.h" +#include "sidebar.h" +#include "api/menus/qmlmenu.h" +#include "api/menus/qmlwebhittestresult.h" +#include "api/events/qmlqzobjects.h" +#include "api/events/qmlmouseevent.h" +#include "api/events/qmlwheelevent.h" +#include "api/events/qmlkeyevent.h" +#include "api/tabs/qmltab.h" +#include "webpage.h" +#include "qztools.h" +#include "qml/qmlengine.h" +#include +#include +#include +#include +#include + +QmlPluginInterface::QmlPluginInterface() + : m_qmlReusableTab(new QmlTab()) +{ +} + +void QmlPluginInterface::init(InitState state, const QString &settingsPath) +{ + if (!m_init.isCallable()) { + qWarning() << "Unable to call" << __FUNCTION__ << "on" << m_name << "plugin"; + return; + } + + QJSValueList args; + args.append(state); + args.append(settingsPath); + m_init.call(args); +} + +DesktopFile QmlPluginInterface::metaData() const +{ + return DesktopFile(); +} + +void QmlPluginInterface::unload() +{ + if (!m_unload.isCallable()) { + qWarning() << "Unable to call" << __FUNCTION__ << "on" << m_name << "plugin"; + return; + } + + m_unload.call(); + + for (QObject *childItem : qAsConst(m_childItems)) { + childItem->deleteLater(); + } + + emit qmlPluginUnloaded(); +} + +bool QmlPluginInterface::testPlugin() +{ + if (!m_testPlugin.isCallable()) { + qWarning() << "Unable to call" << __FUNCTION__ << "on" << m_name << "plugin"; + return false; + } + + QJSValue ret = m_testPlugin.call(); + return ret.toBool(); +} + +void QmlPluginInterface::populateWebViewMenu(QMenu *menu, WebView *webview, const WebHitTestResult &webHitTestResult) +{ + Q_UNUSED(webview) + + if (!m_populateWebViewMenu.isCallable()) { + return; + } + + QmlMenu *qmlMenu = new QmlMenu(menu, m_engine); + QmlWebHitTestResult *qmlWebHitTestResult = new QmlWebHitTestResult(webHitTestResult); + QJSValueList args; + args.append(m_engine->newQObject(qmlMenu)); + args.append(m_engine->newQObject(qmlWebHitTestResult)); + m_populateWebViewMenu.call(args); + menu->addSeparator(); +} + +void QmlPluginInterface::showSettings(QWidget *parent) +{ + if (!m_settingsWindow) { + qWarning() << "No dialog to show"; + return; + } + + QQuickWindow *window = qobject_cast(m_settingsWindow->create(m_settingsWindow->creationContext())); + if (!window) { + qWarning() << "Unable to created window"; + return; + } + + QWidget *widget = QWidget::createWindowContainer(window); + widget->setFixedSize(window->size()); + widget->show(); + QzTools::centerWidgetToParent(widget, parent); + connect(widget, &QWidget::destroyed, window, &QQuickWindow::destroy); +} + +bool QmlPluginInterface::mouseDoubleClick(Qz::ObjectName type, QObject *obj, QMouseEvent *event) +{ + Q_UNUSED(obj) + if (!m_mouseDoubleClick.isCallable()) { + return false; + } + auto qmlMouseEvent = new QmlMouseEvent(event); + QJSValueList args; + args.append(QmlQzObjects::ObjectName(type)); + args.append(m_engine->newQObject(qmlMouseEvent)); + m_mouseDoubleClick.call(args); + qmlMouseEvent->clear(); + return false; +} + +bool QmlPluginInterface::mousePress(Qz::ObjectName type, QObject *obj, QMouseEvent *event) +{ + Q_UNUSED(obj) + if (!m_mousePress.isCallable()) { + return false; + } + auto qmlMouseEvent = new QmlMouseEvent(event); + QJSValueList args; + args.append(QmlQzObjects::ObjectName(type)); + args.append(m_engine->newQObject(qmlMouseEvent)); + m_mousePress.call(args); + qmlMouseEvent->clear(); + return false; +} + +bool QmlPluginInterface::mouseRelease(Qz::ObjectName type, QObject *obj, QMouseEvent *event) +{ + Q_UNUSED(obj) + if (!m_mouseRelease.isCallable()) { + return false; + } + auto qmlMouseEvent = new QmlMouseEvent(event); + QJSValueList args; + args.append(QmlQzObjects::ObjectName(type)); + args.append(m_engine->newQObject(qmlMouseEvent)); + m_mouseRelease.call(args); + qmlMouseEvent->clear(); + return false; +} + +bool QmlPluginInterface::mouseMove(Qz::ObjectName type, QObject *obj, QMouseEvent *event) +{ + Q_UNUSED(obj) + if (!m_mouseMove.isCallable()) { + return false; + } + auto qmlMouseEvent = new QmlMouseEvent(event); + QJSValueList args; + args.append(QmlQzObjects::ObjectName(type)); + args.append(m_engine->newQObject(qmlMouseEvent)); + m_mouseMove.call(args); + qmlMouseEvent->clear(); + return false; +} + +bool QmlPluginInterface::wheelEvent(Qz::ObjectName type, QObject *obj, QWheelEvent *event) +{ + Q_UNUSED(obj) + if (!m_wheelEvent.isCallable()) { + return false; + } + auto qmlWheelEvent = new QmlWheelEvent(event); + QJSValueList args; + args.append(QmlQzObjects::ObjectName(type)); + args.append(m_engine->newQObject(qmlWheelEvent)); + m_wheelEvent.call(args); + qmlWheelEvent->clear(); + return false; +} + +bool QmlPluginInterface::keyPress(Qz::ObjectName type, QObject *obj, QKeyEvent *event) +{ + Q_UNUSED(obj) + if (!m_keyPress.isCallable()) { + return false; + } + auto qmlKeyEvent = new QmlKeyEvent(event); + QJSValueList args; + args.append(QmlQzObjects::ObjectName(type)); + args.append(m_engine->newQObject(qmlKeyEvent)); + m_keyPress.call(args); + qmlKeyEvent->clear(); + return false; +} + +bool QmlPluginInterface::keyRelease(Qz::ObjectName type, QObject *obj, QKeyEvent *event) +{ + Q_UNUSED(obj) + if (!m_keyRelease.isCallable()) { + return false; + } + auto qmlKeyEvent = new QmlKeyEvent(event); + QJSValueList args; + args.append(QmlQzObjects::ObjectName(type)); + args.append(m_engine->newQObject(qmlKeyEvent)); + m_keyRelease.call(args); + qmlKeyEvent->clear(); + return false; +} + +bool QmlPluginInterface::acceptNavigationRequest(WebPage *page, const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) +{ + if (!m_acceptNavigationRequest.isCallable()) { + return true; + } + m_qmlReusableTab->setWebPage(page); + QJSValueList args; + args.append(m_engine->newQObject(m_qmlReusableTab)); + args.append(QString::fromUtf8(url.toEncoded())); + args.append(type); + args.append(isMainFrame); + return m_acceptNavigationRequest.call(args).toBool(); +} + +QJSValue QmlPluginInterface::readInit() const +{ + return m_init; +} + +void QmlPluginInterface::setInit(const QJSValue &init) +{ + m_init = init; +} + +QJSValue QmlPluginInterface::readUnload() const +{ + return m_unload; +} + +void QmlPluginInterface::setUnload(const QJSValue &unload) +{ + m_unload = unload; +} + +QJSValue QmlPluginInterface::readTestPlugin() const +{ + return m_testPlugin; +} + +void QmlPluginInterface::setTestPlugin(const QJSValue &testPlugin) +{ + m_testPlugin = testPlugin; +} + +void QmlPluginInterface::setEngine(QQmlEngine *engine) +{ + m_engine = engine; +} + +void QmlPluginInterface::setName(const QString &name) +{ + m_name = name; +} + +QJSValue QmlPluginInterface::readPopulateWebViewMenu() const +{ + return m_populateWebViewMenu; +} + +void QmlPluginInterface::setPopulateWebViewMenu(const QJSValue &value) +{ + m_populateWebViewMenu = value; +} + +QQmlComponent *QmlPluginInterface::settingsWindow() const +{ + return m_settingsWindow; +} + +void QmlPluginInterface::setSettingsWindow(QQmlComponent *settingsWindow) +{ + m_settingsWindow = settingsWindow; +} + +QJSValue QmlPluginInterface::readMouseDoubleClick() const +{ + return m_mouseDoubleClick; +} + +void QmlPluginInterface::setMouseDoubleClick(const QJSValue &mouseDoubleClick) +{ + m_mouseDoubleClick = mouseDoubleClick; + mApp->plugins()->registerAppEventHandler(PluginProxy::MouseDoubleClickHandler, this); +} + +QJSValue QmlPluginInterface::readMousePress() const +{ + return m_mousePress; +} + +void QmlPluginInterface::setMousePress(const QJSValue &mousePress) +{ + m_mousePress = mousePress; + mApp->plugins()->registerAppEventHandler(PluginProxy::MousePressHandler, this); +} + +QJSValue QmlPluginInterface::readMouseRelease() const +{ + return m_mouseRelease; +} + +void QmlPluginInterface::setMouseRelease(const QJSValue &mouseRelease) +{ + m_mouseRelease = mouseRelease; + mApp->plugins()->registerAppEventHandler(PluginProxy::MouseReleaseHandler, this); +} + +QJSValue QmlPluginInterface::readMouseMove() const +{ + return m_mouseMove; +} + +void QmlPluginInterface::setMouseMove(const QJSValue &mouseMove) +{ + m_mouseMove = mouseMove; + mApp->plugins()->registerAppEventHandler(PluginProxy::MouseMoveHandler, this); +} + +QJSValue QmlPluginInterface::readWheelEvent() const +{ + return m_wheelEvent; +} + +void QmlPluginInterface::setWheelEvent(const QJSValue &wheelEvent) +{ + m_wheelEvent = wheelEvent; + mApp->plugins()->registerAppEventHandler(PluginProxy::WheelEventHandler, this); +} + +QJSValue QmlPluginInterface::readKeyPress() const +{ + return m_keyPress; +} + +void QmlPluginInterface::setKeyPress(const QJSValue &keyPress) +{ + m_keyPress = keyPress; + mApp->plugins()->registerAppEventHandler(PluginProxy::KeyPressHandler, this); +} + +QJSValue QmlPluginInterface::readKeyRelease() const +{ + return m_keyRelease; +} + +void QmlPluginInterface::setKeyRelease(const QJSValue &keyRelease) +{ + m_keyRelease = keyRelease; + mApp->plugins()->registerAppEventHandler(PluginProxy::KeyReleaseHandler, this); +} + +QJSValue QmlPluginInterface::readAcceptNavigationRequest() const +{ + return m_acceptNavigationRequest; +} + +void QmlPluginInterface::setAcceptNavigationRequest(const QJSValue &acceptNavigationRequest) +{ + m_acceptNavigationRequest = acceptNavigationRequest; +} + +QQmlListProperty QmlPluginInterface::childItems() +{ + return QQmlListProperty(this, m_childItems); +} diff --git a/src/lib/plugins/qml/qmlplugininterface.h b/src/lib/plugins/qml/qmlplugininterface.h new file mode 100644 index 000000000..a31991460 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugininterface.h @@ -0,0 +1,121 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include +#include + +#include "desktopfile.h" +#include "plugininterface.h" + +class QmlTab; + +class QmlPluginInterface : public QObject, public PluginInterface +{ + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_ENUM(InitState) + Q_PROPERTY(QJSValue init READ readInit WRITE setInit) + Q_PROPERTY(QJSValue unload READ readUnload WRITE setUnload) + Q_PROPERTY(QJSValue testPlugin READ readTestPlugin WRITE setTestPlugin) + Q_PROPERTY(QJSValue populateWebViewMenu READ readPopulateWebViewMenu WRITE setPopulateWebViewMenu) + Q_PROPERTY(QQmlComponent* settingsWindow READ settingsWindow WRITE setSettingsWindow) + Q_PROPERTY(QJSValue mouseDoubleClick READ readMouseDoubleClick WRITE setMouseDoubleClick) + Q_PROPERTY(QJSValue mousePress READ readMousePress WRITE setMousePress) + Q_PROPERTY(QJSValue mouseRelease READ readMouseRelease WRITE setMouseRelease) + Q_PROPERTY(QJSValue mouseMove READ readMouseMove WRITE setMouseMove) + Q_PROPERTY(QJSValue wheelEvent READ readWheelEvent WRITE setWheelEvent) + Q_PROPERTY(QJSValue keyPress READ readKeyPress WRITE setKeyPress) + Q_PROPERTY(QJSValue keyRelease READ readKeyRelease WRITE setKeyRelease) + Q_PROPERTY(QJSValue acceptNavigationRequest READ readAcceptNavigationRequest WRITE setAcceptNavigationRequest) + Q_PROPERTY(QQmlListProperty childItems READ childItems) + Q_CLASSINFO("DefaultProperty", "childItems") + +public: + explicit QmlPluginInterface(); + DesktopFile metaData() const; + void init(InitState state, const QString &settingsPath); + void unload(); + bool testPlugin(); + void setEngine(QQmlEngine *engine); + void setName(const QString &name); + void populateWebViewMenu(QMenu *menu, WebView *webview, const WebHitTestResult &webHitTestResult) override; + void showSettings(QWidget *parent = nullptr); + + bool mouseDoubleClick(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; + bool mousePress(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; + bool mouseRelease(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; + bool mouseMove(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; + + bool wheelEvent(Qz::ObjectName type, QObject *obj, QWheelEvent *event) override; + + bool keyPress(Qz::ObjectName type, QObject *obj, QKeyEvent *event) override; + bool keyRelease(Qz::ObjectName type, QObject *obj, QKeyEvent *event) override; + + bool acceptNavigationRequest(WebPage *page, const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) override; + +Q_SIGNALS: + void qmlPluginUnloaded(); + +private: + QQmlEngine *m_engine = nullptr; + QString m_name; + QJSValue m_init; + QJSValue m_unload; + QJSValue m_testPlugin; + QJSValue m_populateWebViewMenu; + QQmlComponent *m_settingsWindow = nullptr; + QJSValue m_mouseDoubleClick; + QJSValue m_mousePress; + QJSValue m_mouseRelease; + QJSValue m_mouseMove; + QJSValue m_wheelEvent; + QJSValue m_keyPress; + QJSValue m_keyRelease; + QJSValue m_acceptNavigationRequest; + QList m_childItems; + QmlTab *m_qmlReusableTab = nullptr; + QJSValue readInit() const; + void setInit(const QJSValue &init); + QJSValue readUnload() const; + void setUnload(const QJSValue &unload); + QJSValue readTestPlugin() const; + void setTestPlugin(const QJSValue &testPlugin); + QJSValue readPopulateWebViewMenu() const; + void setPopulateWebViewMenu(const QJSValue &value); + QQmlComponent *settingsWindow() const; + void setSettingsWindow(QQmlComponent *settingsWindow); + QJSValue readMouseDoubleClick() const; + void setMouseDoubleClick(const QJSValue &mouseDoubleClick); + QJSValue readMousePress() const; + void setMousePress(const QJSValue &mousePress); + QJSValue readMouseRelease() const; + void setMouseRelease(const QJSValue &mouseRelease); + QJSValue readMouseMove() const; + void setMouseMove(const QJSValue &mouseMove); + QJSValue readWheelEvent() const; + void setWheelEvent(const QJSValue &wheelEvent); + QJSValue readKeyPress() const; + void setKeyPress(const QJSValue &keyPress); + QJSValue readKeyRelease() const; + void setKeyRelease(const QJSValue &keyRelease); + QJSValue readAcceptNavigationRequest() const; + void setAcceptNavigationRequest(const QJSValue &acceptNavigationRequest); + QQmlListProperty childItems(); +}; diff --git a/src/lib/plugins/qml/qmlpluginloader.cpp b/src/lib/plugins/qml/qmlpluginloader.cpp new file mode 100644 index 000000000..2a2293bcd --- /dev/null +++ b/src/lib/plugins/qml/qmlpluginloader.cpp @@ -0,0 +1,76 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlpluginloader.h" +#include "qmlengine.h" +#include +#include +#include "../config.h" + +#ifdef HAVE_LIBINTL +#include "qml/api/i18n/qmli18n.h" +#endif + + +QmlPluginLoader::QmlPluginLoader(const QString &name, const QString &path, const QString &entryPoint) +{ + m_name = name; + m_path = path; + m_entryPoint = entryPoint; + initEngineAndComponent(); +} + +void QmlPluginLoader::createComponent() +{ + m_interface = qobject_cast(m_component->create(m_component->creationContext())); + + if (!m_interface) { + return; + } + + m_interface->setEngine(m_engine); + m_interface->setName(m_name); + connect(m_interface, &QmlPluginInterface::qmlPluginUnloaded, this, [this]{ + delete m_component; + delete m_engine; + initEngineAndComponent(); + }); +} + +QQmlComponent *QmlPluginLoader::component() const +{ + return m_component; +} + +QmlPluginInterface *QmlPluginLoader::instance() const +{ + return m_interface; +} + +void QmlPluginLoader::initEngineAndComponent() +{ + m_engine = new QmlEngine(); + m_component = new QQmlComponent(m_engine, QDir(m_path).filePath(m_entryPoint)); + m_engine->setExtensionPath(m_path); + m_engine->setExtensionName(m_name); +#ifdef HAVE_LIBINTL + auto i18n = new QmlI18n(m_name); + m_engine->globalObject().setProperty("__falkon_i18n", m_engine->newQObject(i18n)); + m_engine->globalObject().setProperty("i18n", m_engine->evaluate("function (s) { return __falkon_i18n.i18n(s) }")); + m_engine->globalObject().setProperty("i18np", m_engine->evaluate("function (s1, s2) { return __falkon_i18n.i18np(s1, s2) }")); +#endif +} diff --git a/src/lib/plugins/qml/qmlpluginloader.h b/src/lib/plugins/qml/qmlpluginloader.h new file mode 100644 index 000000000..33fe713c4 --- /dev/null +++ b/src/lib/plugins/qml/qmlpluginloader.h @@ -0,0 +1,47 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include +#include + +#include "qmlplugininterface.h" +#include "plugins.h" + +class QmlEngine; + +class QmlPluginLoader : public QObject +{ + Q_OBJECT +public: + explicit QmlPluginLoader(const QString &name, const QString &path, const QString &entryPoint); + void createComponent(); + QQmlComponent *component() const; + QmlPluginInterface *instance() const; +private: + QString m_path; + QString m_name; + QString m_entryPoint; + QmlEngine *m_engine = nullptr; + QQmlComponent *m_component = nullptr; + QmlPluginInterface *m_interface = nullptr; + + void initEngineAndComponent(); +}; + +Q_DECLARE_METATYPE(QmlPluginLoader *) diff --git a/src/lib/plugins/qml/qmlplugins.cpp b/src/lib/plugins/qml/qmlplugins.cpp new file mode 100644 index 000000000..98c9b8617 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugins.cpp @@ -0,0 +1,214 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlplugins.h" +#include "qmlplugininterface.h" +#include "qmlengine.h" +#include "api/bookmarks/qmlbookmarktreenode.h" +#include "api/bookmarks/qmlbookmarks.h" +#include "api/topsites/qmlmostvisitedurl.h" +#include "api/topsites/qmltopsites.h" +#include "api/history/qmlhistoryitem.h" +#include "api/history/qmlhistory.h" +#include "api/cookies/qmlcookie.h" +#include "api/cookies/qmlcookies.h" +#include "api/tabs/qmltab.h" +#include "api/tabs/qmltabs.h" +#include "api/notifications/qmlnotifications.h" +#include "api/clipboard/qmlclipboard.h" +#include "api/windows/qmlwindow.h" +#include "api/windows/qmlwindows.h" +#include "api/windows/qmlwindowstate.h" +#include "api/windows/qmlwindowtype.h" +#include "api/browseraction/qmlbrowseraction.h" +#include "api/sidebar/qmlsidebar.h" +#include "api/menus/qmlmenu.h" +#include "api/menus/qmlaction.h" +#include "api/menus/qmlwebhittestresult.h" +#include "api/settings/qmlsettings.h" +#include "api/events/qmlqzobjects.h" +#include "api/events/qmlmouseevent.h" +#include "api/events/qmlwheelevent.h" +#include "api/userscript/qmluserscript.h" +#include "api/userscript/qmluserscripts.h" +#include "api/userscript/qmlexternaljsobject.h" +#include "api/extensionscheme/qmlextensionscheme.h" +#include "api/extensionscheme/qmlwebengineurlrequestjob.h" +#include "api/fileutils/qmlfileutils.h" +#include "qml/qmlstaticdata.h" +#include +#include + +// static +void QmlPlugins::registerQmlTypes() +{ + const char *url = "org.kde.falkon"; + const int majorVersion = 1; + const int minorVersion = 0; + // PluginInterface + qmlRegisterType(url, majorVersion, minorVersion, "PluginInterface"); + + // Bookmarks + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "BookmarkTreeNode", "Unable to register type: BookmarkTreeNode"); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "Bookmarks", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getBookmarksSingleton(); + }); + + // TopSites + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "MostVisitedURL", "Unable to register type: MostVisitedURL"); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "TopSites", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getTopSitesSingleton(); + }); + + // History + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "HistoryItem", "Unable to register type: HistoryItem"); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "History", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getHistorySingleton(); + }); + + // Cookies + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Cookie", "Unable to register type: Cookie"); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "Cookies", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getCookiesSingleton(); + }); + + // Tabs + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Tab", "Unable to register type: Tab"); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "Tabs", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getTabsSingleton(); + }); + + // Notifications + qmlRegisterSingletonType(url, majorVersion, minorVersion, "Notifications", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(scriptEngine) + + QmlEngine *qmlEngine = qobject_cast(engine); + if (!qmlEngine) { + qWarning() << "Unable to cast QQmlEngine * to QmlEngine *"; + return nullptr; + } + QString filePath = qmlEngine->extensionPath(); + + auto *object = new QmlNotifications(); + object->setPluginPath(filePath); + return object; + }); + + // Clipboard + qmlRegisterSingletonType(url, majorVersion, minorVersion, "Clipboard", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getClipboardSingleton(); + }); + + // Windows + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Window", "Unable to register type: Window"); + + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WindowState", "Unable to register type: WindowState"); + + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WindowType", "Unable to register type: WindowType"); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "Windows", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getWindowsSingleton(); + }); + + // BrowserAction + qmlRegisterType(url, majorVersion, minorVersion, "BrowserAction"); + + // SideBar + qmlRegisterType(url, majorVersion, minorVersion, "SideBar"); + + // Menu + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Menu", "Unable to register type: Menu"); + + // Action + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Action", "Unable to register type: Action"); + + // WebHitTestResult + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WebHitTestResult", "Unable to register type: WebHitTestResult"); + + // Settings + qmlRegisterType(url, majorVersion, minorVersion, "Settings"); + + // Qz::Objects + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "QzObjects", "Unable to register type: QzObjects"); + + // MouseEvents + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "MouseEvent", "Unable to register type: MouseEvent"); + + // WheelEvents + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WheelEvent", "Unable to register type: WheelEvent"); + + // UserScripts + qmlRegisterType(url, majorVersion, minorVersion, "UserScript"); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "UserScripts", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getUserScriptsSingleton(); + }); + + qmlRegisterSingletonType(url, majorVersion, minorVersion, "ExternalJsObject", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + + return QmlStaticData::instance().getExternalJsObjectSingleton(); + }); + + // ExtensionScheme + qmlRegisterType(url, majorVersion, minorVersion, "ExtensionScheme"); + + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WebEngineUrlRequestJob", "Unable to register type: WebEngineUrlRequestJob"); + + // FileUtils + qmlRegisterSingletonType(url, majorVersion, minorVersion, "FileUtils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { + Q_UNUSED(scriptEngine) + + QmlEngine *qmlEngine = qobject_cast(engine); + if (!qmlEngine) { + qWarning() << "Unable to cast QQmlEngine * to QmlEngine *"; + return nullptr; + } + QString filePath = qmlEngine->extensionPath(); + return new QmlFileUtils(filePath); + }); +} diff --git a/src/lib/plugins/qml/qmlplugins.h b/src/lib/plugins/qml/qmlplugins.h new file mode 100644 index 000000000..ab8696a2c --- /dev/null +++ b/src/lib/plugins/qml/qmlplugins.h @@ -0,0 +1,27 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once +#include "browserwindow.h" + +class FALKON_EXPORT QmlPlugins +{ +public: + static void registerQmlTypes(); +}; + +Q_DECLARE_METATYPE(BrowserWindow *) diff --git a/src/lib/plugins/qml/qmlstaticdata.cpp b/src/lib/plugins/qml/qmlstaticdata.cpp new file mode 100644 index 000000000..845382c36 --- /dev/null +++ b/src/lib/plugins/qml/qmlstaticdata.cpp @@ -0,0 +1,190 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#include "qmlstaticdata.h" +#include "api/bookmarks/qmlbookmarktreenode.h" +#include "api/cookies/qmlcookie.h" +#include "api/history/qmlhistoryitem.h" +#include "api/tabs/qmltab.h" +#include "api/topsites/qmlmostvisitedurl.h" +#include "api/windows/qmlwindow.h" +#include "api/fileutils/qmlfileutils.h" +#include "pluginproxy.h" + +QmlStaticData::QmlStaticData(QObject *parent) + : QObject(parent) +{ + const QList windows = mApp->windows(); + for (BrowserWindow *window : windows) { + m_windowIdHash.insert(window, m_newWindowId++); + } + + connect(mApp->plugins(), &PluginProxy::mainWindowCreated, this, [this](BrowserWindow *window) { + m_windowIdHash.insert(window, m_newWindowId++); + }); + + connect(mApp->plugins(), &PluginProxy::mainWindowDeleted, this, [this](BrowserWindow *window) { + m_windowIdHash.remove(window); + }); +} + +QmlStaticData::~QmlStaticData() +{ + qDeleteAll(m_bookmarkTreeNodes); + qDeleteAll(m_cookies); + qDeleteAll(m_historyItems); + qDeleteAll(m_tabs); + qDeleteAll(m_urls); + qDeleteAll(m_windows); +} + +QmlStaticData &QmlStaticData::instance() +{ + static QmlStaticData qmlStaticData; + return qmlStaticData; +} + +QmlBookmarkTreeNode *QmlStaticData::getBookmarkTreeNode(BookmarkItem *item) +{ + QmlBookmarkTreeNode *node = m_bookmarkTreeNodes.value(item); + if (!node) { + node = new QmlBookmarkTreeNode(item); + m_bookmarkTreeNodes.insert(item, node); + } + return node; +} + +QmlCookie *QmlStaticData::getCookie(QNetworkCookie cookie) +{ + QmlCookie *qmlCookie = m_cookies.value(cookie); + if (!qmlCookie) { + qmlCookie = new QmlCookie(new QNetworkCookie(cookie)); + m_cookies.insert(cookie, qmlCookie); + } + return qmlCookie; +} + +QmlHistoryItem *QmlStaticData::getHistoryItem(HistoryEntry *entry) +{ + QmlHistoryItem *item = m_historyItems.value(entry); + if (!item) { + item = new QmlHistoryItem(entry); + m_historyItems.insert(entry, item); + } + return item; +} + +QmlTab *QmlStaticData::getTab(WebTab *webTab) +{ + QmlTab *tab = m_tabs.value(webTab); + if (!tab) { + tab = new QmlTab(webTab); + m_tabs.insert(webTab, tab); + } + return tab; +} + +QmlMostVisitedUrl *QmlStaticData::getMostVisitedUrl(const QString &title, const QString &url) +{ + QmlMostVisitedUrl *visitedUrl = m_urls.value({title, url}); + if (!visitedUrl) { + visitedUrl = new QmlMostVisitedUrl(title, url); + m_urls.insert({title, url}, visitedUrl); + } + return visitedUrl; +} + +QmlWindow *QmlStaticData::getWindow(BrowserWindow *window) +{ + QmlWindow *qmlWindow = m_windows.value(window); + if (!qmlWindow) { + qmlWindow = new QmlWindow(window); + m_windows.insert(window, qmlWindow); + } + return qmlWindow; +} + +QHash QmlStaticData::windowIdHash() +{ + return m_windowIdHash; +} + +QIcon QmlStaticData::getIcon(const QString &iconPath, const QString &pluginPath) +{ + QIcon icon; + if (QIcon::hasThemeIcon(iconPath)) { + icon = QIcon::fromTheme(iconPath); + } else { + QmlFileUtils fileUtils(pluginPath); + icon = QIcon(fileUtils.resolve(iconPath)); + } + return icon; +} + +QmlBookmarks *QmlStaticData::getBookmarksSingleton() +{ + static QmlBookmarks *bookmarks = new QmlBookmarks(this); + return bookmarks; +} + +QmlHistory *QmlStaticData::getHistorySingleton() +{ + static QmlHistory *history = new QmlHistory(this); + return history; +} + +QmlCookies *QmlStaticData::getCookiesSingleton() +{ + static QmlCookies *cookies = new QmlCookies(this); + return cookies; +} + +QmlTopSites *QmlStaticData::getTopSitesSingleton() +{ + static QmlTopSites *topSites = new QmlTopSites(this); + return topSites; +} + +QmlTabs *QmlStaticData::getTabsSingleton() +{ + static QmlTabs *tabs = new QmlTabs(this); + return tabs; +} + +QmlClipboard *QmlStaticData::getClipboardSingleton() +{ + static QmlClipboard *clipboard = new QmlClipboard(this); + return clipboard; +} + +QmlWindows *QmlStaticData::getWindowsSingleton() +{ + static QmlWindows *windows = new QmlWindows(this); + return windows; +} + +QmlExternalJsObject *QmlStaticData::getExternalJsObjectSingleton() +{ + static QmlExternalJsObject *externalJsObject = new QmlExternalJsObject(this); + return externalJsObject; +} + +QmlUserScripts *QmlStaticData::getUserScriptsSingleton() +{ + static QmlUserScripts *userScripts = new QmlUserScripts(this); + return userScripts; +} diff --git a/src/lib/plugins/qml/qmlstaticdata.h b/src/lib/plugins/qml/qmlstaticdata.h new file mode 100644 index 000000000..e5221cd11 --- /dev/null +++ b/src/lib/plugins/qml/qmlstaticdata.h @@ -0,0 +1,85 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2018 Anmol Gautam +* +* 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 . +* ============================================================ */ +#pragma once + +#include "mainapplication.h" +#include "browserwindow.h" +#include "bookmarkitem.h" +#include "historyitem.h" +#include "api/bookmarks/qmlbookmarks.h" +#include "api/history/qmlhistory.h" +#include "api/cookies/qmlcookies.h" +#include "api/topsites/qmltopsites.h" +#include "api/tabs/qmltabs.h" +#include "api/clipboard/qmlclipboard.h" +#include "api/windows/qmlwindows.h" +#include "api/userscript/qmlexternaljsobject.h" +#include "api/userscript/qmluserscripts.h" +#include +#include + +class QmlBookmarkTreeNode; +class QmlCookie; +class QmlHistoryItem; +class QmlTab; +class QmlMostVisitedUrl; +class QmlWindow; + +class QmlStaticData : public QObject +{ + Q_OBJECT + +public: + explicit QmlStaticData(QObject *parent = nullptr); + ~QmlStaticData(); + + static QmlStaticData &instance(); + QmlBookmarkTreeNode *getBookmarkTreeNode(BookmarkItem *item); + QmlCookie *getCookie(QNetworkCookie cookie); + QmlHistoryItem *getHistoryItem(HistoryEntry *entry); + QmlTab *getTab(WebTab *webTab); + QmlMostVisitedUrl *getMostVisitedUrl(const QString &title = QString(), const QString &url = QString()); + QmlWindow *getWindow(BrowserWindow *window); + + QHash windowIdHash(); + QIcon getIcon(const QString &iconPath, const QString &pluginPath); + + QmlBookmarks *getBookmarksSingleton(); + QmlHistory *getHistorySingleton(); + QmlCookies *getCookiesSingleton(); + QmlTopSites *getTopSitesSingleton(); + QmlTabs *getTabsSingleton(); + QmlClipboard *getClipboardSingleton(); + QmlWindows *getWindowsSingleton(); + QmlExternalJsObject *getExternalJsObjectSingleton(); + QmlUserScripts *getUserScriptsSingleton(); +private: + QHash m_bookmarkTreeNodes; + QHash m_cookies; + QHash m_historyItems; + QHash m_tabs; + QHash, QmlMostVisitedUrl*> m_urls; + QHash m_windows; + + int m_newWindowId = 0; + QHash m_windowIdHash; +}; + +inline uint qHash(QNetworkCookie cookie) { + return qHash(QString::fromUtf8(cookie.toRawForm())); +} diff --git a/src/lib/plugins/speeddial.cpp b/src/lib/plugins/speeddial.cpp index b82c654be..39cb673c2 100644 --- a/src/lib/plugins/speeddial.cpp +++ b/src/lib/plugins/speeddial.cpp @@ -376,3 +376,10 @@ QString SpeedDial::generateAllPages() return allPages; } + +QList SpeedDial::pages() +{ + ENSURE_LOADED; + + return m_pages; +} diff --git a/src/lib/plugins/speeddial.h b/src/lib/plugins/speeddial.h index 36e2449ff..f59826233 100644 --- a/src/lib/plugins/speeddial.h +++ b/src/lib/plugins/speeddial.h @@ -67,6 +67,7 @@ public: QString backgroundImageUrl(); QString backgroundImageSize(); QString initialScript(); + QList pages(); Q_SIGNALS: void pagesChanged();