diff --git a/CMakeLists.txt b/CMakeLists.txt index cb35545d..4badb64f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,185 +1,187 @@ # CMake version required. This must be the very first line, because it sets default policies affecting everything else cmake_minimum_required(VERSION 3.1) # Project name and version project(Falkon VERSION 3.0.99) # Find ECM, with nice error handling in case of failure include(FeatureSummary) find_package(ECM 5.27.0 CONFIG) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/frameworks/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # Many includes from ECM, to get all the nice cmake functions and settings include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMAddAppIcon) include(ECMQtDeclareLoggingCategory) include(ECMPoQmTools) # Output dirs (like ECM 5.38 does) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") if (UNIX AND NOT APPLE) set(FALKON_INSTALL_PLUGINDIR "${KDE_INSTALL_PLUGINDIR}/falkon") else() set(FALKON_INSTALL_PLUGINDIR "${KDE_INSTALL_PLUGINDIR}") endif() if (IS_ABSOLUTE ${FALKON_INSTALL_PLUGINDIR}) set(PLUGIN_PATH "${FALKON_INSTALL_PLUGINDIR}") else() set(PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/${FALKON_INSTALL_PLUGINDIR}") endif() if (NOT WIN32) set(FALKON_PLUGIN_PATH "${PLUGIN_PATH}" CACHE PATH "Default plugin search path") endif() # Defines that are always set add_definitions(-DQT_NO_URL_CAST_FROM_STRING -DQT_USE_QSTRINGBUILDER -DQT_NO_CAST_TO_ASCII) # Mandatory: Qt5 set(QT_MIN_VERSION "5.9.0") find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Widgets Network Sql QuickWidgets PrintSupport WebEngine WebEngineWidgets WebChannel) if (BUILD_TESTING) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Test) endif() if (NOT DISABLE_DBUS) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS DBus) endif() if (UNIX AND NOT APPLE AND NOT NO_X11) add_definitions(-DQZ_WS_X11) find_package(XCB REQUIRED COMPONENTS XCB UTIL) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras) endif() if (WIN32) add_definitions(-DW7API) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS WinExtras) # taken from https://stackoverflow.com/a/40217291 macro(get_WIN32_WINNT version) if (CMAKE_SYSTEM_VERSION) set(ver ${CMAKE_SYSTEM_VERSION}) string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver}) string(REGEX MATCH "^([0-9]+)" verMajor ${ver}) # Check for Windows 10, b/c we'll need to convert to hex 'A'. if ("${verMajor}" MATCHES "10") set(verMajor "A") string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver}) endif ("${verMajor}" MATCHES "10") # Remove all remaining '.' characters. string(REPLACE "." "" ver ${ver}) # Prepend each digit with a zero. string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver}) set(${version} "0x${ver}") endif(CMAKE_SYSTEM_VERSION) endmacro(get_WIN32_WINNT) get_WIN32_WINNT(ver) add_definitions(-D_WIN32_WINNT=${ver}) endif() # Mandatory: OpenSSL find_package(OpenSSL REQUIRED) # KF5I18n: Mandatory with downloaded translations (only for ki18n_install) if (EXISTS "${CMAKE_SOURCE_DIR}/po") find_package(KF5I18n REQUIRED) endif() # Optional: GnomeKeyring find_package(PkgConfig) if (PKG_CONFIG_FOUND) option(BUILD_KEYRING "Gnome keyring password plugin" ON) if (BUILD_KEYRING) pkg_check_modules(GNOME_KEYRING IMPORTED_TARGET gnome-keyring-1 ) endif() endif() # Optional: KWallet, KIO, KCrash, KCoreAddons set(KF5_MIN_VERSION "5.27.0") find_package(KF5Wallet ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Wallet PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) find_package(KF5KIO ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5KIO PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) find_package(KF5Crash ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Crash PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) find_package(KF5CoreAddons ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5CoreAddons PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) if (KF5Wallet_FOUND AND KF5KIO_FOUND AND KF5Crash_FOUND AND KF5CoreAddons_FOUND) set(ENABLE_KDE_FRAMEWORKS_INTEGRATION_PLUGIN TRUE) endif() # Optional: PySide2 find_package(PySide2 "2.0.0") find_package(Shiboken2 "2.0.0") find_package(PythonLibs "3.0") set_package_properties(PySide2 PROPERTIES DESCRIPTION "Python plugins (experimental)" TYPE OPTIONAL) set_package_properties(Shiboken2 PROPERTIES DESCRIPTION "Python plugins (experimental)" TYPE OPTIONAL) set_package_properties(PythonLibs PROPERTIES DESCRIPTION "Python plugins (experimental)" TYPE OPTIONAL) if (PySide2_FOUND AND Shiboken2_FOUND AND PythonLibs_FOUND) set(ENABLE_PYTHON_PLUGINS TRUE) endif() +find_package(LibIntl) + # Git revision if (EXISTS "${CMAKE_SOURCE_DIR}/.git") find_package(Git QUIET) if(GIT_FOUND) execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_REVISION ) string(REGEX REPLACE "\n" "" GIT_REVISION "${GIT_REVISION}") set(FALKON_GIT_REVISION "${GIT_REVISION}") else() message(STATUS "Git revision could not be determined") endif() endif() configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config.h) # Include dirs used everywhere include_directories( ${CMAKE_SOURCE_DIR}/src/lib/3rdparty ${CMAKE_SOURCE_DIR}/src/lib/adblock ${CMAKE_SOURCE_DIR}/src/lib/app ${CMAKE_SOURCE_DIR}/src/lib/autofill ${CMAKE_SOURCE_DIR}/src/lib/bookmarks ${CMAKE_SOURCE_DIR}/src/lib/cookies ${CMAKE_SOURCE_DIR}/src/lib/downloads ${CMAKE_SOURCE_DIR}/src/lib/history ${CMAKE_SOURCE_DIR}/src/lib/navigation ${CMAKE_SOURCE_DIR}/src/lib/network ${CMAKE_SOURCE_DIR}/src/lib/notifications ${CMAKE_SOURCE_DIR}/src/lib/opensearch ${CMAKE_SOURCE_DIR}/src/lib/other ${CMAKE_SOURCE_DIR}/src/lib/plugins ${CMAKE_SOURCE_DIR}/src/lib/popupwindow ${CMAKE_SOURCE_DIR}/src/lib/preferences ${CMAKE_SOURCE_DIR}/src/lib/session ${CMAKE_SOURCE_DIR}/src/lib/sidebar ${CMAKE_SOURCE_DIR}/src/lib/tabwidget ${CMAKE_SOURCE_DIR}/src/lib/tools ${CMAKE_SOURCE_DIR}/src/lib/webengine ${CMAKE_SOURCE_DIR}/src/lib/webtab ) # Finally, go into the subdirs add_subdirectory(src) if (BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(tests/benchmarks) endif() # Tell releaseme that po is already taken care of # SKIP_PO_INSTALL feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/cmake/FindLibIntl.cmake b/cmake/FindLibIntl.cmake new file mode 100644 index 00000000..4d0bcd97 --- /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(HAVE_LIBINTL TRUE) +else() + set(HAVE_LIBINTL FALSE) +endif() diff --git a/config.h.cmake b/config.h.cmake index d35648e5..b101ef2c 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -1,11 +1,13 @@ /* config.h. Generated by cmake from config.h.cmake */ #define FALKON_VERSION "${PROJECT_VERSION}" #cmakedefine FALKON_PLUGIN_PATH "${FALKON_PLUGIN_PATH}" #cmakedefine FALKON_GIT_REVISION "${FALKON_GIT_REVISION}" /* Enable portable build */ #cmakedefine PORTABLE_BUILD /* Disable DBus support */ #cmakedefine DISABLE_DBUS + +#cmakedefine01 HAVE_LIBINTL diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index ee82c94e..6aeb1c1a 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,329 +1,370 @@ add_definitions(-DFALKON_SHAREDLIBRARY) set(CMAKE_CXX_STANDARD 14) # Enable C++14, with cmake >= 3.1 set(CMAKE_CXX_EXTENSIONS OFF) # Don't enable gcc-specific extensions set(SRCS 3rdparty/qtsingleapplication/qtsingleapplication.cpp 3rdparty/qtsingleapplication/qtlocalpeer.cpp ) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(SRCS ${SRCS} ${CMAKE_SOURCE_DIR}/tests/modeltest/modeltest.cpp) include_directories(${CMAKE_SOURCE_DIR}/tests/modeltest) endif() include_directories( 3rdparty adblock app autofill bookmarks cookies downloads history navigation network notifications opensearch other plugins popupwindow preferences session sidebar tabwidget tools webengine webtab ) include_directories(${OPENSSL_INCLUDE_DIR}) set(SRCS ${SRCS} 3rdparty/fancytabwidget.cpp 3rdparty/lineedit.cpp 3rdparty/processinfo.cpp 3rdparty/squeezelabelv1.cpp 3rdparty/squeezelabelv2.cpp 3rdparty/stylehelper.cpp adblock/adblockaddsubscriptiondialog.cpp adblock/adblockurlinterceptor.cpp adblock/adblockdialog.cpp adblock/adblockicon.cpp adblock/adblockmanager.cpp adblock/adblockmatcher.cpp adblock/adblockrule.cpp adblock/adblocksearchtree.cpp adblock/adblocksubscription.cpp adblock/adblocktreewidget.cpp adblock/adblockplugin.cpp app/autosaver.cpp app/browserwindow.cpp app/commandlineoptions.cpp app/datapaths.cpp app/mainapplication.cpp app/mainmenu.cpp app/profilemanager.cpp app/proxystyle.cpp app/qzcommon.cpp app/settings.cpp autofill/autofill.cpp autofill/autofillicon.cpp autofill/autofillnotification.cpp autofill/autofillwidget.cpp autofill/passwordbackends/databaseencryptedpasswordbackend.cpp autofill/passwordbackends/databasepasswordbackend.cpp autofill/passwordbackends/passwordbackend.cpp autofill/passwordmanager.cpp bookmarks/bookmarkitem.cpp bookmarks/bookmarks.cpp bookmarks/bookmarksexport/bookmarksexportdialog.cpp bookmarks/bookmarksexport/bookmarksexporter.cpp bookmarks/bookmarksexport/htmlexporter.cpp bookmarks/bookmarksicon.cpp bookmarks/bookmarksimport/bookmarksimportdialog.cpp bookmarks/bookmarksimport/bookmarksimporter.cpp bookmarks/bookmarksimport/firefoximporter.cpp bookmarks/bookmarksimport/htmlimporter.cpp bookmarks/bookmarksimport/chromeimporter.cpp bookmarks/bookmarksimport/ieimporter.cpp bookmarks/bookmarksimport/operaimporter.cpp bookmarks/bookmarksitemdelegate.cpp bookmarks/bookmarksmanager.cpp bookmarks/bookmarksmenu.cpp bookmarks/bookmarksmodel.cpp bookmarks/bookmarkstoolbarbutton.cpp bookmarks/bookmarkstoolbar.cpp bookmarks/bookmarkstools.cpp bookmarks/bookmarkstreeview.cpp bookmarks/bookmarkswidget.cpp cookies/cookiejar.cpp cookies/cookiemanager.cpp downloads/downloaditem.cpp downloads/downloadmanager.cpp downloads/downloadoptionsdialog.cpp downloads/downloadsbutton.cpp history/history.cpp history/historyitem.cpp history/historymanager.cpp history/historymenu.cpp history/historymodel.cpp history/historytreeview.cpp navigation/completer/locationcompleter.cpp navigation/completer/locationcompleterdelegate.cpp navigation/completer/locationcompletermodel.cpp navigation/completer/locationcompleterrefreshjob.cpp navigation/completer/locationcompleterview.cpp navigation/downicon.cpp navigation/goicon.cpp navigation/locationbar.cpp navigation/locationbarpopup.cpp navigation/navigationbar.cpp navigation/navigationbartoolbutton.cpp navigation/navigationbarconfigdialog.cpp navigation/navigationcontainer.cpp navigation/reloadstopbutton.cpp navigation/siteicon.cpp navigation/websearchbar.cpp network/networkmanager.cpp network/networkurlinterceptor.cpp network/schemehandlers/extensionschemehandler.cpp network/schemehandlers/falkonschemehandler.cpp network/sslerrordialog.cpp notifications/desktopnotification.cpp notifications/desktopnotificationsfactory.cpp opensearch/editsearchengine.cpp opensearch/opensearchengine.cpp opensearch/opensearchenginedelegate.cpp opensearch/opensearchreader.cpp opensearch/searchenginesdialog.cpp opensearch/searchenginesmanager.cpp other/aboutdialog.cpp other/browsinglibrary.cpp other/clearprivatedata.cpp other/checkboxdialog.cpp other/iconchooser.cpp other/licenseviewer.cpp other/qzsettings.cpp other/siteinfo.cpp other/siteinfowidget.cpp other/statusbar.cpp other/updater.cpp other/useragentmanager.cpp 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/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 + plugins/qml/api/qmlenums.cpp popupwindow/popuplocationbar.cpp popupwindow/popupstatusbarmessage.cpp popupwindow/popupwebview.cpp popupwindow/popupwindow.cpp preferences/acceptlanguage.cpp preferences/autofillmanager.cpp preferences/jsoptions.cpp preferences/pluginlistdelegate.cpp preferences/pluginsmanager.cpp preferences/preferences.cpp preferences/thememanager.cpp preferences/useragentdialog.cpp session/recoveryjsobject.cpp session/restoremanager.cpp session/sessionmanager.cpp session/sessionmanagerdialog.cpp sidebar/bookmarkssidebar.cpp sidebar/historysidebar.cpp sidebar/sidebar.cpp tabwidget/combotabbar.cpp tabwidget/tabbar.cpp tabwidget/tabicon.cpp tabwidget/tabmodel.cpp tabwidget/tabmrumodel.cpp tabwidget/tabtreemodel.cpp tabwidget/tabstackedwidget.cpp tabwidget/tabwidget.cpp tabwidget/tabcontextmenu.cpp tools/abstractbuttoninterface.cpp tools/aesinterface.cpp tools/animatedwidget.cpp tools/buttonwithmenu.cpp tools/certificateinfowidget.cpp tools/clickablelabel.cpp tools/closedtabsmanager.cpp tools/closedwindowsmanager.cpp tools/colors.cpp tools/delayedfilewatcher.cpp tools/desktopfile.cpp tools/docktitlebarwidget.cpp tools/enhancedmenu.cpp tools/focusselectlineedit.cpp tools/headerview.cpp tools/horizontallistwidget.cpp tools/html5permissions/html5permissionsdialog.cpp tools/html5permissions/html5permissionsmanager.cpp tools/html5permissions/html5permissionsnotification.cpp tools/iconprovider.cpp tools/listitemdelegate.cpp tools/mactoolbutton.cpp tools/menubar.cpp tools/pagethumbnailer.cpp tools/progressbar.cpp tools/qztools.cpp tools/removeitemfocusdelegate.cpp tools/scripts.cpp tools/sqldatabase.cpp tools/toolbutton.cpp tools/treewidget.cpp tools/wheelhelper.cpp webengine/javascript/autofilljsobject.cpp webengine/javascript/externaljsobject.cpp webengine/loadrequest.cpp webengine/webhittestresult.cpp webengine/webinspector.cpp webengine/webpage.cpp webengine/webview.cpp webengine/webscrollbar.cpp webengine/webscrollbarmanager.cpp webtab/searchtoolbar.cpp webtab/tabbedwebview.cpp webtab/webtab.cpp ) +if (HAVE_LIBINTL) + set(SRCS ${SRCS} plugins/qml/api/i18n/qmli18n.cpp) +endif() + if (WIN32) set(SRCS ${SRCS} other/registerqappassociation.cpp) endif() if (APPLE) set(SRCS ${SRCS} tools/disablewindowtabbbing.mm) endif() # TODO: use ki18n_wrap_ui? qt5_wrap_ui(SRCS adblock/adblockaddsubscriptiondialog.ui adblock/adblockdialog.ui autofill/autofillnotification.ui autofill/autofillwidget.ui autofill/passwordbackends/masterpassworddialog.ui bookmarks/bookmarksexport/bookmarksexportdialog.ui bookmarks/bookmarksimport/bookmarksimportdialog.ui bookmarks/bookmarksmanager.ui bookmarks/bookmarkswidget.ui cookies/cookiemanager.ui downloads/downloaditem.ui downloads/downloadmanager.ui downloads/downloadoptionsdialog.ui history/historymanager.ui navigation/navigationbarconfigdialog.ui network/sslerrordialog.ui notifications/desktopnotification.ui opensearch/editsearchengine.ui opensearch/searchenginesdialog.ui other/aboutdialog.ui other/browsinglibrary.ui other/clearprivatedata.ui other/iconchooser.ui other/siteinfo.ui other/siteinfowidget.ui preferences/acceptlanguage.ui preferences/addacceptlanguage.ui preferences/autofillmanager.ui preferences/jsoptions.ui preferences/pluginslist.ui preferences/preferences.ui preferences/thememanager.ui preferences/useragentdialog.ui session/sessionmanagerdialog.ui sidebar/bookmarkssidebar.ui sidebar/historysidebar.ui tools/certificateinfowidget.ui tools/docktitlebarwidget.ui tools/html5permissions/html5permissionsdialog.ui tools/html5permissions/html5permissionsnotification.ui webengine/jsalert.ui webengine/jsconfirm.ui webengine/jsprompt.ui webtab/searchtoolbar.ui ) qt5_add_resources(SRCS data/data.qrc data/html.qrc data/icons.qrc data/breeze-fallback.qrc adblock/adblock.qrc ) add_library(FalkonPrivate SHARED ${SRCS}) get_property(QT_WEBENGINE_INCLUDE_DIRS TARGET Qt5::WebEngine PROPERTY INTERFACE_INCLUDE_DIRECTORIES) target_include_directories(FalkonPrivate SYSTEM PUBLIC ${QT_WEBENGINE_INCLUDE_DIRS}) target_link_libraries(FalkonPrivate Qt5::Widgets Qt5::WebEngineWidgets Qt5::Network Qt5::Sql Qt5::PrintSupport Qt5::QuickWidgets Qt5::WebChannel ${OPENSSL_CRYPTO_LIBRARY} ) if (UNIX AND NOT APPLE) if (NOT NO_X11) target_link_libraries(FalkonPrivate XCB::XCB Qt5::X11Extras) endif() set_target_properties(FalkonPrivate PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION "3") install(TARGETS FalkonPrivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) endif() if (WIN32) target_link_libraries(FalkonPrivate Qt5::WinExtras) endif() if (APPLE) target_link_libraries(FalkonPrivate "-framework CoreServices -framework AppKit") endif() if (NOT DISABLE_DBUS) target_link_libraries(FalkonPrivate Qt5::DBus) endif() diff --git a/src/lib/history/history.cpp b/src/lib/history/history.cpp index 3bda5897..82fbaeb1 100644 --- a/src/lib/history/history.cpp +++ b/src/lib/history/history.cpp @@ -1,287 +1,337 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 "history.h" #include "historymodel.h" #include "browserwindow.h" #include "iconprovider.h" #include "settings.h" #include "mainapplication.h" #include "sqldatabase.h" #include "webview.h" #include History::History(QObject* parent) : QObject(parent) , m_isSaving(true) , m_model(0) { loadSettings(); } HistoryModel* History::model() { if (!m_model) { m_model = new HistoryModel(this); } return m_model; } void History::loadSettings() { Settings settings; settings.beginGroup("Web-Browser-Settings"); m_isSaving = settings.value("allowHistory", true).toBool(); settings.endGroup(); } // AddHistoryEntry void History::addHistoryEntry(WebView* view) { if (!m_isSaving) { return; } const QUrl url = view->url(); const QString title = view->title(); addHistoryEntry(url, title); } void History::addHistoryEntry(const QUrl &url, QString title) { if (!m_isSaving) { return; } const QStringList schemes = { QSL("http"), QSL("https"), QSL("ftp"), QSL("file") }; if (!schemes.contains(url.scheme())) { return; } if (title.isEmpty()) { title = tr("Empty Page"); } auto job = new SqlQueryJob(QSL("SELECT id, count, date, title FROM history WHERE url=?"), this); job->addBindValue(url); connect(job, &SqlQueryJob::finished, this, [=]() { if (job->records().isEmpty()) { auto job = new SqlQueryJob(QSL("INSERT INTO history (count, date, url, title) VALUES (1,?,?,?)"), this); job->addBindValue(QDateTime::currentMSecsSinceEpoch()); job->addBindValue(url); job->addBindValue(title); connect(job, &SqlQueryJob::finished, this, [=]() { HistoryEntry entry; entry.id = job->lastInsertId().toInt(); entry.count = 1; entry.date = QDateTime::currentDateTime(); entry.url = url; entry.urlString = url.toEncoded(); entry.title = title; emit historyEntryAdded(entry); }); job->start(); } else { const auto record = job->records().at(0); const int id = record.value(0).toInt(); const int count = record.value(1).toInt(); const QDateTime date = QDateTime::fromMSecsSinceEpoch(record.value(2).toLongLong()); const QString oldTitle = record.value(3).toString(); auto job = new SqlQueryJob(QSL("UPDATE history SET count = count + 1, date=?, title=? WHERE url=?"), this); job->addBindValue(QDateTime::currentMSecsSinceEpoch()); job->addBindValue(title); job->addBindValue(url); connect(job, &SqlQueryJob::finished, this, [=]() { HistoryEntry before; before.id = id; before.count = count; before.date = date; before.url = url; before.urlString = url.toEncoded(); before.title = oldTitle; HistoryEntry after = before; after.count = count + 1; after.date = QDateTime::currentDateTime(); after.title = title; emit historyEntryEdited(before, after); }); job->start(); } }); job->start(); } // DeleteHistoryEntry void History::deleteHistoryEntry(int index) { QList list; list.append(index); deleteHistoryEntry(list); } void History::deleteHistoryEntry(const QList &list) { QSqlDatabase db = SqlDatabase::instance()->database(); db.transaction(); foreach (int index, list) { QSqlQuery query(SqlDatabase::instance()->database()); query.prepare("SELECT count, date, url, title FROM history WHERE id=?"); query.addBindValue(index); query.exec(); if (!query.isActive() || !query.next()) { continue; } HistoryEntry entry; entry.id = index; entry.count = query.value(0).toInt(); entry.date = QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()); entry.url = query.value(2).toUrl(); entry.urlString = entry.url.toEncoded(); entry.title = query.value(3).toString(); query.prepare("DELETE FROM history WHERE id=?"); query.addBindValue(index); query.exec(); query.prepare("DELETE FROM icons WHERE url=?"); query.addBindValue(entry.url.toEncoded(QUrl::RemoveFragment)); query.exec(); emit historyEntryDeleted(entry); } db.commit(); } +void History::deleteHistoryEntry(const QString &url) +{ + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(QSL("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()); query.prepare("SELECT id FROM history WHERE url=? AND title=?"); query.bindValue(0, url); query.bindValue(1, title); query.exec(); if (query.next()) { int id = query.value(0).toInt(); deleteHistoryEntry(id); } } QList History::indexesFromTimeRange(qint64 start, qint64 end) { QList list; if (start < 0 || end < 0) { return list; } QSqlQuery query(SqlDatabase::instance()->database()); query.prepare("SELECT id FROM history WHERE date BETWEEN ? AND ?"); query.addBindValue(end); query.addBindValue(start); query.exec(); while (query.next()) { list.append(query.value(0).toInt()); } return list; } QVector History::mostVisited(int count) { QVector list; QSqlQuery query(SqlDatabase::instance()->database()); query.prepare(QString("SELECT count, date, id, title, url FROM history ORDER BY count DESC LIMIT %1").arg(count)); query.exec(); while (query.next()) { HistoryEntry entry; 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; } void History::clearHistory() { QSqlQuery query(SqlDatabase::instance()->database()); query.exec(QSL("DELETE FROM history")); query.exec(QSL("VACUUM")); mApp->webProfile()->clearAllVisitedLinks(); emit resetHistory(); } void History::setSaving(bool state) { m_isSaving = state; } bool History::isSaving() { return m_isSaving; } QString History::titleCaseLocalizedMonth(int month) { switch (month) { case 1: return tr("January"); case 2: return tr("February"); case 3: return tr("March"); case 4: return tr("April"); case 5: return tr("May"); case 6: return tr("June"); case 7: return tr("July"); case 8: return tr("August"); case 9: return tr("September"); case 10: return tr("October"); case 11: return tr("November"); case 12: return tr("December"); default: qWarning("Month number out of range!"); return QString(); } } + +QList History::searchHistoryEntry(const QString &text) +{ + QList list; + QSqlQuery query(SqlDatabase::instance()->database()); + query.prepare(QSL("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; + 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(QSL("SELECT count, date, id, title, url FROM history WHERE url = ?")); + query.bindValue(0, text); + query.exec(); + + HistoryEntry entry; + 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 ad634d2e..c40fd75b 100644 --- a/src/lib/history/history.h +++ b/src/lib/history/history.h @@ -1,86 +1,90 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2014 David Rosca * * 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 . * ============================================================ */ #ifndef HISTORY_H #define HISTORY_H #include #include #include #include #include "qzcommon.h" class QIcon; class WebView; class HistoryModel; class FALKON_EXPORT History : public QObject { Q_OBJECT public: History(QObject* parent); struct HistoryEntry { int id; int count; QDateTime date; QUrl url; QString urlString; QString title; }; static QString titleCaseLocalizedMonth(int month); HistoryModel* model(); void addHistoryEntry(WebView* view); void addHistoryEntry(const QUrl &url, QString title); 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); QVector mostVisited(int count); void clearHistory(); bool isSaving(); void setSaving(bool state); void loadSettings(); + QList searchHistoryEntry(const QString &text); + HistoryEntry getHistoryEntry(const QString &text); + Q_SIGNALS: void historyEntryAdded(const HistoryEntry &entry); void historyEntryDeleted(const HistoryEntry &entry); void historyEntryEdited(const HistoryEntry &before, const HistoryEntry &after); void resetHistory(); private: bool m_isSaving; HistoryModel* m_model; }; typedef History::HistoryEntry HistoryEntry; // Hint to QVector to use std::realloc on item moving Q_DECLARE_TYPEINFO(HistoryEntry, Q_MOVABLE_TYPE); #endif // HISTORY_H diff --git a/src/lib/plugins/plugins.cpp b/src/lib/plugins/plugins.cpp index 7a360bcc..9eb3e175 100644 --- a/src/lib/plugins/plugins.cpp +++ b/src/lib/plugins/plugins.cpp @@ -1,411 +1,468 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 "pluginproxy.h" #include "plugininterface.h" #include "mainapplication.h" #include "speeddial.h" #include "settings.h" #include "datapaths.h" #include "adblock/adblockplugin.h" #include "../config.h" #include "desktopfile.h" +#include "qml/qmlplugins.h" +#include "qml/qmlplugin.h" #include #include #include +#include +#include Plugins::Plugins(QObject* parent) : QObject(parent) , m_pluginsLoaded(false) , m_speedDial(new SpeedDial(this)) { loadSettings(); if (!MainApplication::isTestModeEnabled()) { loadPythonSupport(); } } QList Plugins::getAvailablePlugins() { loadAvailablePlugins(); return m_availablePlugins; } bool Plugins::loadPlugin(Plugins::Plugin* plugin) { if (plugin->isLoaded()) { return true; } if (!initPlugin(PluginInterface::LateInitState, plugin)) { return false; } m_availablePlugins.removeOne(*plugin); m_availablePlugins.prepend(*plugin); refreshLoadedPlugins(); return plugin->isLoaded(); } void Plugins::unloadPlugin(Plugins::Plugin* plugin) { if (!plugin->isLoaded()) { return; } plugin->instance->unload(); emit pluginUnloaded(plugin->instance); plugin->instance = nullptr; m_availablePlugins.removeOne(*plugin); m_availablePlugins.append(*plugin); refreshLoadedPlugins(); } +void Plugins::removePlugin(Plugins::Plugin *plugin) +{ + if (plugin->type != Plugin::QmlPlugin) { + return; + } + if (plugin->isLoaded()) { + unloadPlugin(plugin); + } + + // For QML plugins, pluginId is qml: + const QString dirName = plugin->pluginId.mid(4); + 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() { 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")); } Settings settings; settings.beginGroup("Plugin-Settings"); m_allowedPlugins = settings.value("AllowedPlugins", defaultAllowedPlugins).toStringList(); settings.endGroup(); } void Plugins::shutdown() { foreach (PluginInterface* iPlugin, m_loadedPlugins) { iPlugin->unload(); } } PluginSpec Plugins::createSpec(const DesktopFile &metaData) { PluginSpec spec; spec.name = metaData.name(); spec.description = metaData.comment(); spec.version = metaData.value(QSL("X-Falkon-Version")).toString(); spec.author = QSL("%1 <%2>").arg(metaData.value(QSL("X-Falkon-Author")).toString(), metaData.value(QSL("X-Falkon-Email")).toString()); spec.hasSettings = metaData.value(QSL("X-Falkon-Settings")).toBool(); const QString iconName = metaData.icon(); if (!iconName.isEmpty()) { if (QFileInfo::exists(iconName)) { spec.icon = QIcon(iconName).pixmap(32); } else { const QString relativeFile = QFileInfo(metaData.fileName()).dir().absoluteFilePath(iconName); if (QFileInfo::exists(relativeFile)) { spec.icon = QIcon(relativeFile).pixmap(32); } else { spec.icon = QIcon::fromTheme(iconName).pixmap(32); } } } return spec; } void Plugins::loadPlugins() { QDir settingsDir(DataPaths::currentProfilePath() + "/extensions/"); if (!settingsDir.exists()) { settingsDir.mkdir(settingsDir.absolutePath()); } foreach (const QString &pluginId, m_allowedPlugins) { Plugin plugin = loadPlugin(pluginId); if (plugin.type == Plugin::Invalid) { continue; } if (plugin.pluginSpec.name.isEmpty()) { qWarning() << "Invalid plugin spec of" << pluginId << "plugin"; continue; } if (!initPlugin(PluginInterface::StartupInitState, &plugin)) { qWarning() << "Failed to init" << pluginId << "plugin"; continue; } registerAvailablePlugin(plugin); } refreshLoadedPlugins(); std::cout << "Falkon: " << m_loadedPlugins.count() << " extensions loaded" << std::endl; } void Plugins::loadAvailablePlugins() { if (m_pluginsLoaded) { return; } m_pluginsLoaded = true; const QStringList dirs = DataPaths::allPaths(DataPaths::Plugins); // InternalPlugin registerAvailablePlugin(loadInternalPlugin(QSL("adblock"))); // SharedLibraryPlugin for (const QString &dir : dirs) { const auto files = QDir(dir).entryInfoList(QDir::Files); for (const QFileInfo &info : files) { if (info.baseName() == QL1S("PyFalkon")) { continue; } Plugin plugin = loadSharedLibraryPlugin(info.absoluteFilePath()); if (plugin.type == Plugin::Invalid) { continue; } if (plugin.pluginSpec.name.isEmpty()) { qWarning() << "Invalid plugin spec of" << info.absoluteFilePath() << "plugin"; continue; } registerAvailablePlugin(plugin); } } // PythonPlugin if (m_pythonPlugin) { auto f = (QVector(*)()) m_pythonPlugin->resolve("pyfalkon_load_available_plugins"); if (!f) { qWarning() << "Failed to resolve" << "pyfalkon_load_available_plugins"; } else { const auto plugins = f(); for (const auto &plugin : plugins) { registerAvailablePlugin(plugin); } } } + + // 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) { if (!m_availablePlugins.contains(plugin)) { m_availablePlugins.append(plugin); } } void Plugins::refreshLoadedPlugins() { m_loadedPlugins.clear(); foreach (const Plugin &plugin, m_availablePlugins) { if (plugin.isLoaded()) { m_loadedPlugins.append(plugin.instance); } } + + emit refreshedLoadedPlugins(); } void Plugins::loadPythonSupport() { const QStringList dirs = DataPaths::allPaths(DataPaths::Plugins); for (const QString &dir : dirs) { const auto files = QDir(dir).entryInfoList({QSL("PyFalkon*")}, QDir::Files); for (const QFileInfo &info : files) { m_pythonPlugin = new QLibrary(info.absoluteFilePath(), this); m_pythonPlugin->setLoadHints(QLibrary::ExportExternalSymbolsHint); if (!m_pythonPlugin->load()) { qWarning() << "Failed to load python support plugin" << m_pythonPlugin->errorString(); delete m_pythonPlugin; m_pythonPlugin = nullptr; } else { std::cout << "Falkon: Python plugin support initialized" << std::endl; return; } } } } Plugins::Plugin Plugins::loadPlugin(const QString &id) { QString name; Plugin::Type type = Plugin::Invalid; const int colon = id.indexOf(QL1C(':')); if (colon > -1) { const auto t = id.leftRef(colon); if (t == QL1S("internal")) { type = Plugin::InternalPlugin; } else if (t == QL1S("lib")) { 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 { name = id; type = Plugin::SharedLibraryPlugin; } switch (type) { case Plugin::InternalPlugin: return loadInternalPlugin(name); case Plugin::SharedLibraryPlugin: return loadSharedLibraryPlugin(name); case Plugin::PythonPlugin: return loadPythonPlugin(name); + case Plugin::QmlPlugin: + return QmlPlugin::loadPlugin(name); + default: return Plugin(); } } Plugins::Plugin Plugins::loadInternalPlugin(const QString &name) { if (name == QL1S("adblock")) { Plugin plugin; plugin.type = Plugin::InternalPlugin; plugin.pluginId = QSL("internal:adblock"); plugin.internalInstance = new AdBlockPlugin(); plugin.pluginSpec = createSpec(plugin.internalInstance->metaData()); return plugin; } else { return Plugin(); } } Plugins::Plugin Plugins::loadSharedLibraryPlugin(const QString &name) { QString fullPath; if (QFileInfo(name).isAbsolute()) { fullPath = name; } else { fullPath = DataPaths::locate(DataPaths::Plugins, name); if (fullPath.isEmpty()) { qWarning() << "Plugin" << name << "not found"; return Plugin(); } } QPluginLoader *loader = new QPluginLoader(fullPath); PluginInterface *iPlugin = qobject_cast(loader->instance()); if (!iPlugin) { qWarning() << "Loading" << fullPath << "failed:" << loader->errorString(); return Plugin(); } Plugin plugin; plugin.type = Plugin::SharedLibraryPlugin; plugin.pluginId = QSL("lib:%1").arg(QFileInfo(fullPath).fileName()); plugin.libraryPath = fullPath; plugin.pluginLoader = loader; plugin.pluginSpec = createSpec(iPlugin->metaData()); return plugin; } Plugins::Plugin Plugins::loadPythonPlugin(const QString &name) { if (!m_pythonPlugin) { qWarning() << "Python support plugin is not loaded"; return Plugin(); } auto f = (Plugin(*)(const QString &)) m_pythonPlugin->resolve("pyfalkon_load_plugin"); if (!f) { qWarning() << "Failed to resolve" << "pyfalkon_load_plugin"; return Plugin(); } return f(name); } bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin) { if (!plugin) { return false; } switch (plugin->type) { case Plugin::InternalPlugin: initInternalPlugin(plugin); break; case Plugin::SharedLibraryPlugin: initSharedLibraryPlugin(plugin); break; case Plugin::PythonPlugin: initPythonPlugin(plugin); break; + case Plugin::QmlPlugin: + QmlPlugin::initPlugin(plugin); + break; + default: return false; } if (!plugin->instance) { 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()) { emit pluginUnloaded(plugin->instance); plugin->instance = nullptr; return false; } return true; } void Plugins::initInternalPlugin(Plugin *plugin) { Q_ASSERT(plugin->type == Plugin::InternalPlugin); plugin->instance = plugin->internalInstance; } void Plugins::initSharedLibraryPlugin(Plugin *plugin) { Q_ASSERT(plugin->type == Plugin::SharedLibraryPlugin); plugin->instance = qobject_cast(plugin->pluginLoader->instance()); } void Plugins::initPythonPlugin(Plugin *plugin) { Q_ASSERT(plugin->type == Plugin::PythonPlugin); if (!m_pythonPlugin) { qWarning() << "Python support plugin is not loaded"; return; } auto f = (void(*)(Plugin *)) m_pythonPlugin->resolve("pyfalkon_init_plugin"); if (!f) { qWarning() << "Failed to resolve" << "pyfalkon_init_plugin"; return; } f(plugin); } diff --git a/src/lib/plugins/plugins.h b/src/lib/plugins/plugins.h index bfd77b5f..9163a195 100644 --- a/src/lib/plugins/plugins.h +++ b/src/lib/plugins/plugins.h @@ -1,139 +1,143 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 . * ============================================================ */ #ifndef PLUGINLOADER_H #define PLUGINLOADER_H #include #include #include #include "qzcommon.h" #include "plugininterface.h" +#include "qml/qmlpluginloader.h" class QLibrary; class QPluginLoader; class SpeedDial; struct PluginSpec { QString name; QString description; QString author; QString version; QPixmap icon; bool hasSettings = false; bool operator==(const PluginSpec &other) const { return (this->name == other.name && this->description == other.description && this->author == other.author && this->version == other.version); } }; class FALKON_EXPORT Plugins : public QObject { Q_OBJECT public: struct Plugin { enum Type { Invalid = 0, InternalPlugin, SharedLibraryPlugin, - PythonPlugin + PythonPlugin, + QmlPlugin }; Type type = Invalid; QString pluginId; PluginSpec pluginSpec; PluginInterface *instance = nullptr; // InternalPlugin PluginInterface *internalInstance = nullptr; // SharedLibraryPlugin QString libraryPath; QPluginLoader *pluginLoader = nullptr; // Other QVariant data; bool isLoaded() const { return instance; } bool operator==(const Plugin &other) const { return this->type == other.type && this->pluginId == other.pluginId; } }; explicit Plugins(QObject* parent = 0); QList getAvailablePlugins(); bool loadPlugin(Plugin* plugin); void unloadPlugin(Plugin* plugin); + void removePlugin(Plugin *plugin); void shutdown(); // SpeedDial SpeedDial* speedDial() { return m_speedDial; } static PluginSpec createSpec(const DesktopFile &metaData); public Q_SLOTS: void loadSettings(); void loadPlugins(); protected: QList m_loadedPlugins; Q_SIGNALS: void pluginUnloaded(PluginInterface* plugin); + void refreshedLoadedPlugins(); private: void loadPythonSupport(); Plugin loadPlugin(const QString &id); Plugin loadInternalPlugin(const QString &name); Plugin loadSharedLibraryPlugin(const QString &name); Plugin loadPythonPlugin(const QString &name); bool initPlugin(PluginInterface::InitState state, Plugin *plugin); void initInternalPlugin(Plugin *plugin); void initSharedLibraryPlugin(Plugin *plugin); void initPythonPlugin(Plugin *plugin); void registerAvailablePlugin(const Plugin &plugin); void refreshLoadedPlugins(); void loadAvailablePlugins(); QList m_availablePlugins; QStringList m_allowedPlugins; bool m_pluginsLoaded; SpeedDial* m_speedDial; QList m_internalPlugins; QLibrary *m_pythonPlugin = nullptr; }; Q_DECLARE_METATYPE(Plugins::Plugin) #endif // PLUGINLOADER_H 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 00000000..c0981e49 --- /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 00000000..fd86cac0 --- /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 00000000..fbb54d8f --- /dev/null +++ b/src/lib/plugins/qml/api/bookmarks/qmlbookmarktreenode.cpp @@ -0,0 +1,129 @@ +/* ============================================================ +* 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: + return Invalid; + } + + 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 00000000..4bc2532c --- /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 00000000..8ab4f250 --- /dev/null +++ b/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp @@ -0,0 +1,261 @@ +/* ============================================================ +* 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; + } + + QQuickWidget *quickWidget = new QQuickWidget(); + quickWidget->setContent(m_popup->url(), m_popup, m_popup->create(m_popup->creationContext())); + + QWidget *widget = new QWidget(); + quickWidget->setParent(widget); + + widget->setWindowFlag(Qt::Popup); + widget->setAttribute(Qt::WA_DeleteOnClose); + widget->move(clickController->callPopupPosition(quickWidget->size())); + + connect(quickWidget, &QQuickWidget::destroyed, this, [clickController]{ + clickController->callPopupClosed(); + }); + + widget->show(); +} 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 00000000..5917c5dd --- /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() override; + void classBegin() override {} + void componentComplete() override; + 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 00000000..ffe6314d --- /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 00000000..5e2cbbcc --- /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 00000000..d653824f --- /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 00000000..6b3e18df --- /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 00000000..79e1621a --- /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 00000000..7c3dff67 --- /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 00000000..ece12038 --- /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 0; + } + return static_cast(m_keyEvent->nativeModifiers()); +} + +quint32 QmlKeyEvent::nativeScanCode() const +{ + if (!m_keyEvent) { + return 0; + } + return static_cast(m_keyEvent->nativeScanCode()); +} + +quint32 QmlKeyEvent::nativeVirtualKey() const +{ + if (!m_keyEvent) { + return 0; + } + return static_cast(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 00000000..dd41b6a4 --- /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 00000000..5c96b62a --- /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 00000000..f504a384 --- /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 00000000..196854ca --- /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 00000000..b3f39060 --- /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 00000000..0390bf38 --- /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 00000000..5c6b16a5 --- /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 00000000..b2063edb --- /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 *qmlRequest = new QmlWebEngineUrlRequestJob(job); + const QJSValue request = qmlEngine(this)->newQObject(qmlRequest); + 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 00000000..c39e65e8 --- /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() override; + void classBegin() override {} + void componentComplete() override; +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(const QJSValue &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 00000000..f379628d --- /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 00000000..1da0331b --- /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 00000000..f1e59c46 --- /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 00000000..eb7969e9 --- /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 00000000..06dd5f61 --- /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 (const 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 00000000..b27d4e31 --- /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 00000000..853a3dfe --- /dev/null +++ b/src/lib/plugins/qml/api/history/qmlhistoryitem.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 "qmlhistoryitem.h" +#include + +QmlHistoryItem::QmlHistoryItem(HistoryEntry entry, QObject *parent) + : QObject(parent) + , m_entry(entry) +{ + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); +} + +int QmlHistoryItem::id() const +{ + return m_entry.id; +} + +QString QmlHistoryItem::url() const +{ + return QString::fromUtf8(m_entry.url.toEncoded()); +} + +QString QmlHistoryItem::title() const +{ + return m_entry.title; +} + +int QmlHistoryItem::visitCount() const +{ + return m_entry.count; +} + +QDateTime QmlHistoryItem::lastVisitTime() const +{ + 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 00000000..b43c624b --- /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, QObject *parent = nullptr); + +private: + HistoryEntry m_entry; + + 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 00000000..abb7c365 --- /dev/null +++ b/src/lib/plugins/qml/api/i18n/qmli18n.cpp @@ -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 . +* ============================================================ */ +#include "qmli18n.h" +#include "qztools.h" +#include + +QmlI18n::QmlI18n(const QString &pluginName, QObject *parent) + : QObject(parent) +{ + m_pluginName = pluginName; + initTranslations(); +} + +void QmlI18n::initTranslations() +{ + m_domain = QString(QSL("falkon_%1")).arg(m_pluginName); + const QString localeDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSL("locale"), QStandardPaths::LocateDirectory); + const bool isLanguageSet = qEnvironmentVariableIsSet("LANGUAGE"); + const QByteArray language = qgetenv("LANGUAGE"); + qputenv("LANGUAGE", QLocale::system().name().toUtf8()); + bindtextdomain(m_domain.toUtf8(), localeDir.toUtf8()); + if (!isLanguageSet) { + qunsetenv("LANGUAGE"); + } else { + qputenv("LANGUAGE", language); + } +} + +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 00000000..6bc43c51 --- /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 00000000..4a410f01 --- /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 00000000..05fbf611 --- /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 00000000..39d99688 --- /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")) { + const QString iconPath = map.value(key).toString(); + const 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 00000000..def353c8 --- /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 00000000..1166e164 --- /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 00000000..b4ea4632 --- /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 00000000..2b14626f --- /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); + const 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 00000000..924c9468 --- /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/qmlenums.cpp b/src/lib/plugins/qml/api/qmlenums.cpp new file mode 100644 index 00000000..059dcf05 --- /dev/null +++ b/src/lib/plugins/qml/api/qmlenums.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 "qmlenums.h" + +QmlEnums::QmlEnums(QObject *parent) + : QObject(parent) +{ +} diff --git a/src/lib/plugins/qml/api/qmlenums.h b/src/lib/plugins/qml/api/qmlenums.h new file mode 100644 index 00000000..5e52c65b --- /dev/null +++ b/src/lib/plugins/qml/api/qmlenums.h @@ -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 . +* ============================================================ */ +#pragma once + +#include +#include "qzcommon.h" + +/** + * @brief The class exposing Enums to QML + */ +class QmlEnums : 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) + + /** + * @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) + + QmlEnums(QObject *parent = nullptr); +}; 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 00000000..d385668f --- /dev/null +++ b/src/lib/plugins/qml/api/settings/qmlsettings.cpp @@ -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 . +* ============================================================ */ +#include "qmlsettings.h" +#include "datapaths.h" +#include + +QmlSettings::QmlSettings(QObject *parent) + : QObject(parent) +{ + m_settingsPath = DataPaths::currentProfilePath() + QL1S("/extensions"); +} + +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 += QL1C('/') + 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 00000000..917fa632 --- /dev/null +++ b/src/lib/plugins/qml/api/settings/qmlsettings.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 + +/** + * @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); + /** + * @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 00000000..964a3820 --- /dev/null +++ b/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp @@ -0,0 +1,183 @@ +/* ============================================================ +* 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(); + const QIcon icon = QmlStaticData::instance().getIcon(m_iconUrl, pluginPath); + action->setIcon(icon); + return action; +} + +QWidget *QmlSideBarHelper::createSideBarWidget(BrowserWindow *mainWindow) +{ + Q_UNUSED(mainWindow) + + QQuickWidget *widget = new QQuickWidget(); + widget->setContent(m_item->url(), m_item, m_item->create(m_item->creationContext())); + + return widget; +} + +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 00000000..de998179 --- /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() override; + void classBegin() override {} + void componentComplete() override; + 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 = false; + 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 00000000..8f0c069e --- /dev/null +++ b/src/lib/plugins/qml/api/tabs/qmltab.cpp @@ -0,0 +1,422 @@ +/* ============================================================ +* 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(); + } + const 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() +{ + disconnect(this); +} 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 00000000..58454e04 --- /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 00000000..5b455968 --- /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; + for (BrowserWindow *window : mApp->windows()) { + for (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 00000000..f068e95d --- /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 00000000..b9ca66ad --- /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 00000000..baceb1cc --- /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 00000000..7eddd1b1 --- /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 00000000..4d52dbae --- /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 00000000..b69458fb --- /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 00000000..f2f29873 --- /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 00000000..5ae35a82 --- /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 static_cast(m_webEngineScript.injectionPoint()); +} + +void QmlUserScript::setInjectionPoint(InjectionPoint injectionPoint) +{ + switch (static_cast(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 00000000..5a694425 --- /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 00000000..0a43ff1b --- /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 00000000..0ec22658 --- /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 00000000..4368b32d --- /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(); +} + +QmlEnums::WindowState QmlWindow::state() const +{ + if (!m_window) { + return QmlEnums::Invalid; + } + + if (m_window->isFullScreen()) { + return QmlEnums::FullScreen; + } else if (m_window->isMaximized()) { + return QmlEnums::Maximized; + } else if (m_window->isMinimized()) { + return QmlEnums::Minimized; + } else { + return QmlEnums::Normal; + } +} + +QmlEnums::WindowType QmlWindow::type() const +{ + if (!m_window) { + return QmlEnums::OtherRestoredWindow; + } + + switch (m_window->windowType()) { + case Qz::BW_FirstAppWindow: + return QmlEnums::FirstAppWindow; + case Qz::BW_MacFirstWindow: + return QmlEnums::MacFirstWindow; + case Qz::BW_NewWindow: + return QmlEnums::NewWindow; + default: + return QmlEnums::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 00000000..e2fbda17 --- /dev/null +++ b/src/lib/plugins/qml/api/windows/qmlwindow.h @@ -0,0 +1,89 @@ +/* ============================================================ +* 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 "../qmlenums.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(QmlEnums::WindowState state READ state CONSTANT) + + /** + * @brief [window type](@ref QmlWindowType::WindowType) of window + */ + Q_PROPERTY(QmlEnums::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; + QmlEnums::WindowState state() const; + QmlEnums::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 00000000..0f64ac5e --- /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"), QmlEnums::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 id:" << windowId; + 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 00000000..835ee71d --- /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/qmlengine.cpp b/src/lib/plugins/qml/qmlengine.cpp new file mode 100644 index 00000000..131d5b2a --- /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 00000000..064774c9 --- /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 00000000..3b6915fe --- /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 00000000..7956de54 --- /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 00000000..2f5213c4 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugininterface.cpp @@ -0,0 +1,395 @@ +/* ============================================================ +* 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 + +QmlPluginInterface::QmlPluginInterface() + : m_qmlReusableTab(new QmlTab()) +{ +} + +QmlPluginInterface::~QmlPluginInterface() +{ + m_qmlReusableTab->deleteLater(); +} + +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; + } + + QQuickWidget *widget = new QQuickWidget(); + widget->setContent(m_settingsWindow->url(), m_settingsWindow, m_settingsWindow->create(m_settingsWindow->creationContext())); + widget->show(); + + QzTools::centerWidgetToParent(widget, parent); +} + +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 00000000..7fa43f81 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugininterface.h @@ -0,0 +1,122 @@ +/* ============================================================ +* 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(); + ~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 00000000..a7ef1ad5 --- /dev/null +++ b/src/lib/plugins/qml/qmlpluginloader.cpp @@ -0,0 +1,75 @@ +/* ============================================================ +* 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" + +#if 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(QSL("__falkon_i18n"), m_engine->newQObject(i18n)); + m_engine->globalObject().setProperty(QSL("i18n"), m_engine->evaluate(QSL("function (s) { return __falkon_i18n.i18n(s) }"))); + m_engine->globalObject().setProperty(QSL("i18np"), m_engine->evaluate(QSL("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 00000000..33fe713c --- /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 00000000..fd9c2953 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugins.cpp @@ -0,0 +1,215 @@ +/* ============================================================ +* 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/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/qmlkeyevent.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 "api/qmlenums.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", QSL("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", QSL("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", QSL("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", QSL("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", QSL("Unable to register type: Window")); + + 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", QSL("Unable to register type: Menu")); + + // Action + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Action", QSL("Unable to register type: Action")); + + // WebHitTestResult + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WebHitTestResult", QSL("Unable to register type: WebHitTestResult")); + + // Settings + qmlRegisterType(url, majorVersion, minorVersion, "Settings"); + + // Qz::Objects + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "QzObjects", QSL("Unable to register type: QzObjects")); + + // KeyEvents + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "KeyEvent", QSL("Unable to register type: KeyEvent")); + + // MouseEvents + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "MouseEvent", QSL("Unable to register type: MouseEvent")); + + // WheelEvents + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WheelEvent", QSL("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", QSL("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); + }); + + qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Enums", QSL("Unable to register type: Enums")); +} diff --git a/src/lib/plugins/qml/qmlplugins.h b/src/lib/plugins/qml/qmlplugins.h new file mode 100644 index 00000000..ab8696a2 --- /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 00000000..5ebf23dc --- /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(const 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 00000000..83dda99a --- /dev/null +++ b/src/lib/plugins/qml/qmlstaticdata.h @@ -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 . +* ============================================================ */ +#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 +#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(const 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 bool operator ==(const HistoryEntry &x, const HistoryEntry &y) { + return x.title == y.title && x.urlString == y.urlString && x.date == y.date && x.count == y.count; +} + +inline uint qHash(const HistoryEntry &entry) { + return qHash(QSL("%1 %2 %3 %4").arg(entry.title, entry.urlString, entry.date.toString(), QString::number(entry.count))); +} + +inline uint qHash(const QNetworkCookie &cookie) { + return qHash(QString::fromUtf8(cookie.toRawForm())); +} diff --git a/src/lib/plugins/speeddial.cpp b/src/lib/plugins/speeddial.cpp index b82c654b..39cb673c 100644 --- a/src/lib/plugins/speeddial.cpp +++ b/src/lib/plugins/speeddial.cpp @@ -1,378 +1,385 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2017 David Rosca * * 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 "speeddial.h" #include "pagethumbnailer.h" #include "settings.h" #include "datapaths.h" #include "qztools.h" #include "autosaver.h" #include #include #include #include #include #include #define ENSURE_LOADED if (!m_loaded) loadSettings(); SpeedDial::SpeedDial(QObject* parent) : QObject(parent) , m_maxPagesInRow(4) , m_sizeOfSpeedDials(231) , m_sdcentered(false) , m_loaded(false) , m_regenerateScript(true) { m_autoSaver = new AutoSaver(this); connect(m_autoSaver, SIGNAL(save()), this, SLOT(saveSettings())); connect(this, SIGNAL(pagesChanged()), m_autoSaver, SLOT(changeOccurred())); } SpeedDial::~SpeedDial() { m_autoSaver->saveIfNecessary(); } void SpeedDial::loadSettings() { m_loaded = true; Settings settings; settings.beginGroup("SpeedDial"); QString allPages = settings.value("pages", QString()).toString(); setBackgroundImage(settings.value("background", QString()).toString()); m_backgroundImageSize = settings.value("backsize", "auto").toString(); m_maxPagesInRow = settings.value("pagesrow", 4).toInt(); m_sizeOfSpeedDials = settings.value("sdsize", 231).toInt(); m_sdcentered = settings.value("sdcenter", false).toBool(); settings.endGroup(); changed(allPages); m_thumbnailsDir = DataPaths::currentProfilePath() + "/thumbnails/"; // If needed, create thumbnails directory if (!QDir(m_thumbnailsDir).exists()) { QDir(DataPaths::currentProfilePath()).mkdir("thumbnails"); } } void SpeedDial::saveSettings() { ENSURE_LOADED; Settings settings; settings.beginGroup("SpeedDial"); settings.setValue("pages", generateAllPages()); settings.setValue("background", m_backgroundImageUrl); settings.setValue("backsize", m_backgroundImageSize); settings.setValue("pagesrow", m_maxPagesInRow); settings.setValue("sdsize", m_sizeOfSpeedDials); settings.setValue("sdcenter", m_sdcentered); settings.endGroup(); } SpeedDial::Page SpeedDial::pageForUrl(const QUrl &url) { ENSURE_LOADED; QString urlString = url.toString(); if (urlString.endsWith(QL1C('/'))) urlString = urlString.left(urlString.size() - 1); foreach (const Page &page, m_pages) { if (page.url == urlString) { return page; } } return Page(); } QUrl SpeedDial::urlForShortcut(int key) { ENSURE_LOADED; if (key < 0 || m_pages.count() <= key) { return QUrl(); } return QUrl::fromEncoded(m_pages.at(key).url.toUtf8()); } void SpeedDial::addPage(const QUrl &url, const QString &title) { ENSURE_LOADED; if (url.isEmpty()) { return; } Page page; page.title = escapeTitle(title); page.url = escapeUrl(url.toString()); m_pages.append(page); m_regenerateScript = true; emit pagesChanged(); } void SpeedDial::removePage(const Page &page) { ENSURE_LOADED; if (!page.isValid()) { return; } removeImageForUrl(page.url); m_pages.removeAll(page); m_regenerateScript = true; emit pagesChanged(); } int SpeedDial::pagesInRow() { ENSURE_LOADED; return m_maxPagesInRow; } int SpeedDial::sdSize() { ENSURE_LOADED; return m_sizeOfSpeedDials; } bool SpeedDial::sdCenter() { ENSURE_LOADED; return m_sdcentered; } QString SpeedDial::backgroundImage() { ENSURE_LOADED; return m_backgroundImage; } QString SpeedDial::backgroundImageUrl() { return m_backgroundImageUrl; } QString SpeedDial::backgroundImageSize() { ENSURE_LOADED; return m_backgroundImageSize; } QString SpeedDial::initialScript() { ENSURE_LOADED; if (!m_regenerateScript) { return m_initialScript; } m_regenerateScript = false; m_initialScript.clear(); QVariantList pages; foreach (const Page &page, m_pages) { QString imgSource = m_thumbnailsDir + QCryptographicHash::hash(page.url.toUtf8(), QCryptographicHash::Md4).toHex() + ".png"; if (!QFile(imgSource).exists()) { imgSource = "qrc:html/loading.gif"; if (!page.isValid()) { imgSource.clear(); } } else { imgSource = QzTools::pixmapToDataUrl(QPixmap(imgSource)).toString(); } QVariantMap map; map[QSL("url")] = page.url; map[QSL("title")] = page.title; map[QSL("img")] = imgSource; pages.append(map); } m_initialScript = QJsonDocument::fromVariant(pages).toJson(QJsonDocument::Compact); return m_initialScript; } void SpeedDial::changed(const QString &allPages) { const QStringList entries = allPages.split(QLatin1String("\";"), QString::SkipEmptyParts); m_pages.clear(); foreach (const QString &entry, entries) { if (entry.isEmpty()) { continue; } const QStringList tmp = entry.split(QLatin1String("\"|"), QString::SkipEmptyParts); if (tmp.count() != 2) { continue; } Page page; page.url = tmp.at(0).mid(5); page.title = tmp.at(1).mid(7); if (page.url.endsWith(QL1C('/'))) page.url = page.url.left(page.url.size() - 1); m_pages.append(page); } m_regenerateScript = true; emit pagesChanged(); } void SpeedDial::loadThumbnail(const QString &url, bool loadTitle) { PageThumbnailer* thumbnailer = new PageThumbnailer(this); thumbnailer->setUrl(QUrl::fromEncoded(url.toUtf8())); thumbnailer->setLoadTitle(loadTitle); connect(thumbnailer, SIGNAL(thumbnailCreated(QPixmap)), this, SLOT(thumbnailCreated(QPixmap))); thumbnailer->start(); } void SpeedDial::removeImageForUrl(const QString &url) { QString fileName = m_thumbnailsDir + QCryptographicHash::hash(url.toUtf8(), QCryptographicHash::Md4).toHex() + ".png"; if (QFile(fileName).exists()) { QFile(fileName).remove(); } } QStringList SpeedDial::getOpenFileName() { const QString fileTypes = QString("%3(*.png *.jpg *.jpeg *.bmp *.gif *.svg *.tiff)").arg(tr("Image files")); const QString image = QzTools::getOpenFileName("SpeedDial-GetOpenFileName", 0, tr("Click to select image..."), QDir::homePath(), fileTypes); if (image.isEmpty()) return QStringList(); return {QzTools::pixmapToDataUrl(QPixmap(image)).toString(), QUrl::fromLocalFile(image).toEncoded()}; } QString SpeedDial::urlFromUserInput(const QString &url) { return QUrl::fromUserInput(url).toString(); } void SpeedDial::setBackgroundImage(const QString &image) { m_backgroundImage = QzTools::pixmapToDataUrl(QPixmap(QUrl(image).toLocalFile())).toString(); m_backgroundImageUrl = image; } void SpeedDial::setBackgroundImageSize(const QString &size) { m_backgroundImageSize = size; } void SpeedDial::setPagesInRow(int count) { m_maxPagesInRow = count; } void SpeedDial::setSdSize(int count) { m_sizeOfSpeedDials = count; } void SpeedDial::setSdCentered(bool centered) { m_sdcentered = centered; m_autoSaver->changeOccurred(); } void SpeedDial::thumbnailCreated(const QPixmap &pixmap) { PageThumbnailer* thumbnailer = qobject_cast(sender()); if (!thumbnailer) { return; } bool loadTitle = thumbnailer->loadTitle(); QString title = thumbnailer->title(); QString url = thumbnailer->url().toString(); QString fileName = m_thumbnailsDir + QCryptographicHash::hash(url.toUtf8(), QCryptographicHash::Md4).toHex() + ".png"; if (pixmap.isNull()) { fileName = ":/html/broken-page.svg"; title = tr("Unable to load"); } else { if (!pixmap.save(fileName, "PNG")) { qWarning() << "SpeedDial::thumbnailCreated Cannot save thumbnail to " << fileName; } //fileName = QUrl::fromLocalFile(fileName).toString(); } m_regenerateScript = true; thumbnailer->deleteLater(); if (loadTitle) emit pageTitleLoaded(url, title); emit thumbnailLoaded(url, QzTools::pixmapToDataUrl(QPixmap(fileName)).toString()); } QString SpeedDial::escapeTitle(QString title) const { title.replace(QLatin1Char('"'), QLatin1String(""")); title.replace(QLatin1Char('\''), QLatin1String("'")); return title; } QString SpeedDial::escapeUrl(QString url) const { url.remove(QLatin1Char('"')); url.remove(QLatin1Char('\'')); return url; } QString SpeedDial::generateAllPages() { QString allPages; foreach (const Page &page, m_pages) { const QString string = QString("url:\"%1\"|title:\"%2\";").arg(page.url, page.title); allPages.append(string); } 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 36e2449f..f5982623 100644 --- a/src/lib/plugins/speeddial.h +++ b/src/lib/plugins/speeddial.h @@ -1,115 +1,116 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2014 David Rosca * * 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 . * ============================================================ */ #ifndef SPEEDDIAL_H #define SPEEDDIAL_H #include #include #include #include "qzcommon.h" class QUrl; class QPixmap; class AutoSaver; class PageThumbnailer; class FALKON_EXPORT SpeedDial : public QObject { Q_OBJECT public: struct Page { QString title; QString url; bool isValid() const { return !url.isEmpty(); } bool operator==(const Page &other) { return (this->title == other.title && this->url == other.url); } }; explicit SpeedDial(QObject* parent = 0); ~SpeedDial(); void loadSettings(); Page pageForUrl(const QUrl &url); QUrl urlForShortcut(int key); void addPage(const QUrl &url, const QString &title); void removePage(const Page &page); int pagesInRow(); int sdSize(); bool sdCenter(); QString backgroundImage(); QString backgroundImageUrl(); QString backgroundImageSize(); QString initialScript(); + QList pages(); Q_SIGNALS: void pagesChanged(); void thumbnailLoaded(const QString &url, const QString &src); void pageTitleLoaded(const QString &url, const QString &title); public Q_SLOTS: void changed(const QString &allPages); void loadThumbnail(const QString &url, bool loadTitle); void removeImageForUrl(const QString &url); QStringList getOpenFileName(); QString urlFromUserInput(const QString &url); void setBackgroundImage(const QString &image); void setBackgroundImageSize(const QString &size); void setPagesInRow(int count); void setSdSize(int count); void setSdCentered(bool centered); private Q_SLOTS: void thumbnailCreated(const QPixmap &pixmap); void saveSettings(); private: QString escapeTitle(QString string) const; QString escapeUrl(QString url) const; QString generateAllPages(); QString m_initialScript; QString m_thumbnailsDir; QString m_backgroundImage; QString m_backgroundImageUrl; QString m_backgroundImageSize; int m_maxPagesInRow; int m_sizeOfSpeedDials; bool m_sdcentered; QList m_pages; AutoSaver* m_autoSaver; bool m_loaded; bool m_regenerateScript; }; #endif // SPEEDDIAL_H