diff --git a/CMakeLists.txt b/CMakeLists.txt index 94f58e96e7..9d80b8ae11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -377,7 +377,6 @@ if (Qt5WebKitWidgets_FOUND AND ENABLE_QTWEBKIT) src/modules/backends/web/qtwebkit/QtWebKitCookieJar.cpp src/modules/backends/web/qtwebkit/QtWebKitFtpListingNetworkReply.cpp src/modules/backends/web/qtwebkit/QtWebKitHistoryInterface.cpp - src/modules/backends/web/qtwebkit/QtWebKitInspector.cpp src/modules/backends/web/qtwebkit/QtWebKitNetworkManager.cpp src/modules/backends/web/qtwebkit/QtWebKitNotificationPresenter.cpp src/modules/backends/web/qtwebkit/QtWebKitPage.cpp diff --git a/src/core/Application.cpp b/src/core/Application.cpp index 9471bfb601..283d9b0bde 100644 --- a/src/core/Application.cpp +++ b/src/core/Application.cpp @@ -277,10 +277,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv), QCryptographicHash hash(QCryptographicHash::Md5); hash.addData(profilePath.toUtf8()); - const QString identifier(QString::fromLatin1(hash.result().toHex())); - const QString server(applicationName() + (identifier.isEmpty() ? QString() : (QLatin1Char('-') + identifier))); + const QString serverName(applicationName() + QLatin1Char('-') + QString::fromLatin1(hash.result().toHex())); QLocalSocket socket; - socket.connectToServer(server); + socket.connectToServer(serverName); if (socket.waitForConnected(500)) { @@ -311,9 +310,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv), m_localServer->setSocketOptions(QLocalServer::UserAccessOption); - if (!m_localServer->listen(server) && m_localServer->serverError() == QAbstractSocket::AddressInUseError && QLocalServer::removeServer(server)) + if (!m_localServer->listen(serverName) && m_localServer->serverError() == QAbstractSocket::AddressInUseError && QLocalServer::removeServer(serverName)) { - m_localServer->listen(server); + m_localServer->listen(serverName); } m_isFirstRun = !QFile::exists(profilePath); @@ -445,7 +444,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv), const WebBackend *webBackend(AddonsManager::getWebBackend()); - if (!QSslSocket::supportsSsl() || (webBackend && webBackend->getSslVersion().isEmpty())) + if (!QSslSocket::supportsSsl() || (webBackend && !webBackend->hasSslSupport())) { QMessageBox::warning(nullptr, tr("Warning"), tr("SSL support is not available or incomplete.\nSome websites may work incorrectly or do not work at all."), QMessageBox::Close); } @@ -1017,14 +1016,7 @@ void Application::handleNewConnection() if (!mainWindow || !SettingsManager::getOption(SettingsManager::Browser_OpenLinksInNewTabOption).toBool() || (isPrivate && !mainWindow->isPrivate())) { - QVariantMap parameters; - - if (isPrivate) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } - - createWindow(parameters); + createWindow({{QLatin1String("hints"), (isPrivate ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}); } } else @@ -1033,12 +1025,7 @@ void Application::handleNewConnection() if (sessionData.isClean || QMessageBox::warning(nullptr, tr("Warning"), tr("This session was not saved correctly.\nAre you sure that you want to restore this session anyway?"), (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes) { - QVariantMap parameters; - - if (isPrivate) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } + const QVariantMap parameters({{QLatin1String("hints"), (isPrivate ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}); for (int i = 0; i < sessionData.windows.count(); ++i) { @@ -1084,12 +1071,7 @@ void Application::handlePositionalArguments(QCommandLineParser *parser, bool for if (openHints.testFlag(SessionsManager::NewWindowOpen)) { - QVariantMap parameters; - - if (openHints.testFlag(SessionsManager::PrivateOpen)) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } + const QVariantMap parameters({{QLatin1String("hints"), (openHints.testFlag(SessionsManager::PrivateOpen) ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}); if (urls.isEmpty()) { diff --git a/src/core/BookmarksModel.cpp b/src/core/BookmarksModel.cpp index e26d143355..5954048a99 100644 --- a/src/core/BookmarksModel.cpp +++ b/src/core/BookmarksModel.cpp @@ -1215,6 +1215,7 @@ QMimeData* BookmarksModel::mimeData(const QModelIndexList &indexes) const if (indexes.count() == 1) { mimeData->setProperty("x-item-index", indexes.at(0)); + mimeData->setProperty("x-url-title", indexes.at(0).data(TitleRole).toString()); } for (int i = 0; i < indexes.count(); ++i) diff --git a/src/core/Importer.cpp b/src/core/Importer.cpp index fbf5189c09..45dcf20a8d 100644 --- a/src/core/Importer.cpp +++ b/src/core/Importer.cpp @@ -99,6 +99,19 @@ BookmarksModel::Bookmark* BookmarksImportJob::getImportFolder() const return m_importFolder; } +QDateTime BookmarksImportJob::getDateTime(const QString ×tamp) const +{ +#if QT_VERSION < 0x050800 + const uint seconds(timestamp.toUInt()); + + return ((seconds > 0) ? QDateTime::fromTime_t(seconds) : QDateTime()); +#else + const qint64 seconds(timestamp.toLongLong()); + + return ((seconds != 0) ? QDateTime::fromSecsSinceEpoch(seconds) : QDateTime()); +#endif +} + bool BookmarksImportJob::areDuplicatesAllowed() const { return m_areDuplicatesAllowed; diff --git a/src/core/Importer.h b/src/core/Importer.h index 1aa73b1dd9..1805818aa0 100644 --- a/src/core/Importer.h +++ b/src/core/Importer.h @@ -111,6 +111,7 @@ class BookmarksImportJob : public ImportJob void setCurrentFolder(BookmarksModel::Bookmark *folder); BookmarksModel::Bookmark* getCurrentFolder() const; BookmarksModel::Bookmark* getImportFolder() const; + QDateTime getDateTime(const QString ×tamp) const; bool areDuplicatesAllowed() const; private: diff --git a/src/core/SessionsManager.cpp b/src/core/SessionsManager.cpp index 974c79310f..c7c1d63719 100644 --- a/src/core/SessionsManager.cpp +++ b/src/core/SessionsManager.cpp @@ -558,12 +558,7 @@ bool SessionsManager::restoreSession(const SessionInformation &session, MainWind m_sessionTitle = session.title; } - QVariantMap parameters; - - if (isPrivate) - { - parameters[QLatin1String("hints")] = PrivateOpen; - } + const QVariantMap parameters({{QLatin1String("hints"), (isPrivate ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}); for (int i = 0; i < session.windows.count(); ++i) { diff --git a/src/core/TransfersManager.cpp b/src/core/TransfersManager.cpp index 3b83bac996..ccf727ebb0 100644 --- a/src/core/TransfersManager.cpp +++ b/src/core/TransfersManager.cpp @@ -1046,7 +1046,12 @@ void TransfersManager::addTransfer(Transfer *transfer) } else { - HistoryManager::addEntry(transfer->getSource()); + const QString scheme(transfer->getSource().scheme()); + + if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) + { + HistoryManager::addEntry(transfer->getSource()); + } } } diff --git a/src/core/WebBackend.h b/src/core/WebBackend.h index e8cb85910e..cf2ad17abf 100644 --- a/src/core/WebBackend.h +++ b/src/core/WebBackend.h @@ -85,6 +85,7 @@ class WebBackend : public QObject, public Addon virtual QVector getDictionaries() const; AddonType getType() const override; virtual BackendCapabilities getCapabilities() const; + virtual bool hasSslSupport() const = 0; }; } diff --git a/src/main.cpp b/src/main.cpp index 68d946f96f..888e6cfa4a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -207,14 +207,7 @@ int main(int argc, char *argv[]) if (Application::getWindows().isEmpty()) { - QVariantMap parameters; - - if (isPrivate) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } - - Application::createWindow(parameters); + Application::createWindow({{QLatin1String("hints"), (isPrivate ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}); } return Application::exec(); diff --git a/src/modules/backends/web/qtwebengine/QtWebEnginePage.cpp b/src/modules/backends/web/qtwebengine/QtWebEnginePage.cpp index 27c3844902..930c4dc9b8 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEnginePage.cpp +++ b/src/modules/backends/web/qtwebengine/QtWebEnginePage.cpp @@ -337,19 +337,21 @@ QtWebEngineWebWidget* QtWebEnginePage::createWidget(SessionsManager::OpenHints h return widget; } -QString QtWebEnginePage::createJavaScriptList(QStringList rules) const +QString QtWebEnginePage::createJavaScriptList(const QStringList &rules) const { if (rules.isEmpty()) { return {}; } + QStringList parsedRules(rules); + for (int i = 0; i < rules.count(); ++i) { - rules[i].replace(QLatin1Char('\''), QLatin1String("\\'")); + parsedRules[i].replace(QLatin1Char('\''), QLatin1String("\\'")); } - return QLatin1Char('\'') + rules.join(QLatin1String("','")) + QLatin1Char('\''); + return QLatin1Char('\'') + parsedRules.join(QLatin1String("','")) + QLatin1Char('\''); } QString QtWebEnginePage::createScriptSource(const QString &path, const QStringList ¶meters) const @@ -402,6 +404,13 @@ QVariant QtWebEnginePage::runScriptFile(const QString &path, const QStringList & return runScriptSource(createScriptSource(path, parameters)); } +#if QTWEBENGINECORE_VERSION >= 0x050E00 +WebWidget::SslInformation QtWebEnginePage::getSslInformation() const +{ + return m_sslInformation; +} +#endif + Session::Window::History QtWebEnginePage::getHistory() const { QWebEngineHistory *pageHistory(history()); @@ -526,6 +535,10 @@ bool QtWebEnginePage::acceptNavigationRequest(const QUrl &url, NavigationType ty } } +#if QTWEBENGINECORE_VERSION >= 0x050E00 + m_sslInformation = {}; +#endif + if (type != NavigationTypeReload) { m_previousNavigationType = type; @@ -584,6 +597,39 @@ bool QtWebEnginePage::acceptNavigationRequest(const QUrl &url, NavigationType ty return true; } +#if QTWEBENGINECORE_VERSION >= 0x050E00 +bool QtWebEnginePage::certificateError(const QWebEngineCertificateError &error) +{ + if (!m_widget || error.certificateChain().isEmpty()) + { + return false; + } + + const QList errors(QSslCertificate::verify(error.certificateChain(), error.url().host())); + + m_sslInformation.errors.reserve(m_sslInformation.errors.count() + errors.count()); + + for (int i = 0; i < errors.count(); ++i) + { + m_sslInformation.errors.append({errors.at(i), error.url()}); + } + + const QString firstPartyUrl(m_widget->getUrl().toString()); + const QString thirdPartyUrl(error.url().toString()); + + if (m_widget->getOption(SettingsManager::Security_IgnoreSslErrorsOption, m_widget->getUrl()).toStringList().contains(QString::fromLatin1(error.certificateChain().first().digest().toBase64()))) + { + Console::addMessage(QStringLiteral("[accepted] The page at %1 was allowed to display insecure content from %2").arg(firstPartyUrl, thirdPartyUrl), Console::SecurityCategory, Console::WarningLevel, thirdPartyUrl, -1, m_widget->getWindowIdentifier()); + + return true; + } + + Console::addMessage(QStringLiteral("[blocked] The page at %1 was not allowed to display insecure content from %2").arg(firstPartyUrl, thirdPartyUrl), Console::SecurityCategory, Console::WarningLevel, thirdPartyUrl, -1, m_widget->getWindowIdentifier()); + + return false; +} +#endif + bool QtWebEnginePage::javaScriptConfirm(const QUrl &url, const QString &message) { if (m_isIgnoringJavaScriptPopups) diff --git a/src/modules/backends/web/qtwebengine/QtWebEnginePage.h b/src/modules/backends/web/qtwebengine/QtWebEnginePage.h index eebdb8126f..04f29101ca 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEnginePage.h +++ b/src/modules/backends/web/qtwebengine/QtWebEnginePage.h @@ -22,7 +22,12 @@ #define OTTER_QTWEBENGINEPAGE_H #include "../../../../core/SessionsManager.h" +#include "../../../../ui/WebWidget.h" +#include +#if QTWEBENGINECORE_VERSION >= 0x050E00 +#include +#endif #include namespace Otter @@ -53,6 +58,9 @@ class QtWebEnginePage final : public QWebEnginePage QString createScriptSource(const QString &path, const QStringList ¶meters = {}) const; QVariant runScriptSource(const QString &script); QVariant runScriptFile(const QString &path, const QStringList ¶meters = {}); +#if QTWEBENGINECORE_VERSION >= 0x050E00 + WebWidget::SslInformation getSslInformation() const; +#endif Session::Window::History getHistory() const; bool isPopup() const; bool isViewingMedia() const; @@ -63,9 +71,12 @@ class QtWebEnginePage final : public QWebEnginePage void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString ¬e, int line, const QString &source) override; QWebEnginePage* createWindow(WebWindowType type) override; QtWebEngineWebWidget* createWidget(SessionsManager::OpenHints hints); - QString createJavaScriptList(QStringList rules) const; + QString createJavaScriptList(const QStringList &rules) const; QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) override; - bool acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) override; + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override; +#if QTWEBENGINECORE_VERSION >= 0x050E00 + bool certificateError(const QWebEngineCertificateError &error) override; +#endif bool javaScriptConfirm(const QUrl &url, const QString &message) override; bool javaScriptPrompt(const QUrl &url, const QString &message, const QString &defaultValue, QString *result) override; @@ -75,9 +86,12 @@ protected slots: private: QtWebEngineWebWidget *m_widget; +#if QTWEBENGINECORE_VERSION >= 0x050E00 + WebWidget::SslInformation m_sslInformation; +#endif QVector m_popups; QVector m_history; - QWebEnginePage::NavigationType m_previousNavigationType; + NavigationType m_previousNavigationType; bool m_isIgnoringJavaScriptPopups; bool m_isViewingMedia; bool m_isPopup; @@ -85,7 +99,7 @@ protected slots: signals: void requestedNewWindow(WebWidget *widget, SessionsManager::OpenHints hints, const QVariantMap ¶meters); void requestedPopupWindow(const QUrl &parentUrl, const QUrl &popupUrl); - void aboutToNavigate(const QUrl &url, QWebEnginePage::NavigationType navigationType); + void aboutToNavigate(const QUrl &url, NavigationType navigationType); void viewingMediaChanged(bool isViewingMedia); }; diff --git a/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.cpp b/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.cpp index 21aa8706f3..b90b10638b 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.cpp +++ b/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.cpp @@ -19,6 +19,9 @@ #include "QtWebEngineTransfer.h" +#if QTWEBENGINECORE_VERSION >= 0x050E00 +#include +#endif #include #include @@ -26,8 +29,10 @@ namespace Otter { QtWebEngineTransfer::QtWebEngineTransfer(QWebEngineDownloadItem *item, TransferOptions options, QObject *parent) : Transfer(options, parent), - m_item(item), - m_suggestedFileName(QFileInfo(item->path()).fileName()) + m_item(item) +#if QTWEBENGINECORE_VERSION < 0x050E00 + , m_suggestedFileName(QFileInfo(item->path()).fileName()) +#endif { m_item->accept(); m_item->setParent(this); @@ -79,7 +84,16 @@ QUrl QtWebEngineTransfer::getSource() const QString QtWebEngineTransfer::getSuggestedFileName() { +#if QTWEBENGINECORE_VERSION >= 0x050E00 + if (!m_item) + { + return {}; + } + + return m_item->suggestedFileName(); +#else return m_suggestedFileName; +#endif } QString QtWebEngineTransfer::getTarget() const @@ -89,7 +103,11 @@ QString QtWebEngineTransfer::getTarget() const return Transfer::getTarget(); } +#if QTWEBENGINECORE_VERSION >= 0x050E00 + return QDir(m_item->downloadDirectory()).absoluteFilePath(m_item->downloadFileName()); +#else return m_item->path(); +#endif } QMimeType QtWebEngineTransfer::getMimeType() const @@ -154,7 +172,14 @@ bool QtWebEngineTransfer::setTarget(const QString &target, bool canOverwriteExis return Transfer::setTarget(target, canOverwriteExisting); } +#if QTWEBENGINECORE_VERSION >= 0x050E00 + QFileInfo fileInformation(target); + + m_item->setDownloadDirectory(fileInformation.path()); + m_item->setDownloadFileName(fileInformation.fileName()); +#else m_item->setPath(target); +#endif return true; } diff --git a/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.h b/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.h index 52981d8bc7..df23bd91ee 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.h +++ b/src/modules/backends/web/qtwebengine/QtWebEngineTransfer.h @@ -22,6 +22,7 @@ #include "../../../../core/TransfersManager.h" +#include #include namespace Otter @@ -48,7 +49,9 @@ public slots: private: QPointer m_item; +#if QTWEBENGINECORE_VERSION < 0x050E00 QString m_suggestedFileName; +#endif }; } diff --git a/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.cpp b/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.cpp index ffa0e68a26..2129212314 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.cpp +++ b/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.cpp @@ -550,4 +550,9 @@ void QtWebEngineBookmarksImportJob::addBookmark(QVariant itemVariant) } } +bool QtWebEngineWebBackend::hasSslSupport() const +{ + return true; +} + } diff --git a/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.h b/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.h index 71fd1b3180..95ed50dfeb 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.h +++ b/src/modules/backends/web/qtwebengine/QtWebEngineWebBackend.h @@ -58,6 +58,7 @@ class QtWebEngineWebBackend final : public WebBackend #endif QUrl getHomePage() const override; WebBackend::BackendCapabilities getCapabilities() const override; + bool hasSslSupport() const override; #if QTWEBENGINECORE_VERSION >= 0x050D00 protected: diff --git a/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.cpp b/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.cpp index ebd39f7f49..451ee16e9e 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.cpp +++ b/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.cpp @@ -54,6 +54,9 @@ #include #include #include +#if QTWEBENGINECORE_VERSION >= 0x050E00 +#include +#endif #include #include #include @@ -112,6 +115,12 @@ QtWebEngineWebWidget::QtWebEngineWebWidget(const QVariantMap ¶meters, WebBac { notifyPermissionRequested(url, feature, true); }); +#if QTWEBENGINECORE_VERSION >= 0x050E00 + connect(m_page, &QtWebEnginePage::findTextFinished, [&](const QWebEngineFindTextResult &result) + { + emit findInPageResultsChanged(m_findInPageText, result.numberOfMatches(), result.activeMatch()); + }); +#endif connect(m_page, &QtWebEnginePage::recentlyAudibleChanged, this, &QtWebEngineWebWidget::isAudibleChanged); connect(m_page, &QtWebEnginePage::viewingMediaChanged, this, &QtWebEngineWebWidget::notifyNavigationActionsChanged); connect(m_page, &QtWebEnginePage::titleChanged, this, &QtWebEngineWebWidget::notifyTitleChanged); @@ -198,50 +207,6 @@ void QtWebEngineWebWidget::ensureInitialized() } } -void QtWebEngineWebWidget::search(const QString &query, const QString &searchEngine) -{ - QNetworkRequest request; - QNetworkAccessManager::Operation method; - QByteArray body; - - if (SearchEnginesManager::setupSearchQuery(query, searchEngine, &request, &method, &body)) - { - setRequestedUrl(request.url(), false, true); - updateOptions(request.url()); - - if (method == QNetworkAccessManager::PostOperation) - { - QWebEngineHttpRequest httpRequest(request.url(), QWebEngineHttpRequest::Post); - httpRequest.setPostData(body); - - m_page->load(httpRequest); - } - else - { - setUrl(request.url(), false); - } - } -} - -void QtWebEngineWebWidget::print(QPrinter *printer) -{ - QEventLoop eventLoop; - - m_page->print(printer, [&](bool) - { - eventLoop.quit(); - }); - - eventLoop.exec(); -} - -void QtWebEngineWebWidget::clearOptions() -{ - WebWidget::clearOptions(); - - updateOptions(getUrl()); -} - void QtWebEngineWebWidget::triggerAction(int identifier, const QVariantMap ¶meters, ActionsManager::TriggerType trigger) { switch (identifier) @@ -879,6 +844,89 @@ void QtWebEngineWebWidget::triggerAction(int identifier, const QVariantMap ¶ } } +void QtWebEngineWebWidget::clearOptions() +{ + WebWidget::clearOptions(); + + updateOptions(getUrl()); +} + +void QtWebEngineWebWidget::findInPage(const QString &text, FindFlags flags) +{ +#if QTWEBENGINECORE_VERSION >= 0x050E00 + m_findInPageText = text; +#endif + + if (text.isEmpty()) + { + m_page->findText(text); + +#if QTWEBENGINECORE_VERSION <= 0x050E00 + emit findInPageResultsChanged(text, 0, 0); +#endif + + return; + } + + QWebEnginePage::FindFlags nativeFlags; + + if (flags.testFlag(BackwardFind)) + { + nativeFlags |= QWebEnginePage::FindBackward; + } + + if (flags.testFlag(CaseSensitiveFind)) + { + nativeFlags |= QWebEnginePage::FindCaseSensitively; + } + +#if QTWEBENGINECORE_VERSION >= 0x050E00 + m_page->findText(text, nativeFlags); +#else + m_page->findText(text, nativeFlags, [&](bool hasMatches) + { + emit findInPageResultsChanged(text, (hasMatches ? -1 : 0), (hasMatches ? -1 : 0)); + }); +#endif +} + +void QtWebEngineWebWidget::search(const QString &query, const QString &searchEngine) +{ + QNetworkRequest request; + QNetworkAccessManager::Operation method; + QByteArray body; + + if (SearchEnginesManager::setupSearchQuery(query, searchEngine, &request, &method, &body)) + { + setRequestedUrl(request.url(), false, true); + updateOptions(request.url()); + + if (method == QNetworkAccessManager::PostOperation) + { + QWebEngineHttpRequest httpRequest(request.url(), QWebEngineHttpRequest::Post); + httpRequest.setPostData(body); + + m_page->load(httpRequest); + } + else + { + setUrl(request.url(), false); + } + } +} + +void QtWebEngineWebWidget::print(QPrinter *printer) +{ + QEventLoop eventLoop; + + m_page->print(printer, [&](bool) + { + eventLoop.quit(); + }); + + eventLoop.exec(); +} + void QtWebEngineWebWidget::handleLoadStarted() { m_lastUrlClickTime = {}; @@ -1651,6 +1699,13 @@ WebWidget::LinkUrl QtWebEngineWebWidget::getActiveMedia() const return link; } +#if QTWEBENGINECORE_VERSION >= 0x050E00 +WebWidget::SslInformation QtWebEngineWebWidget::getSslInformation() const +{ + return m_page->getSslInformation(); +} +#endif + Session::Window::History QtWebEngineWebWidget::getHistory() const { return m_page->getHistory(); @@ -1730,45 +1785,6 @@ int QtWebEngineWebWidget::getZoom() const return static_cast(m_page->zoomFactor() * 100); } -int QtWebEngineWebWidget::findInPage(const QString &text, FindFlags flags) -{ - if (text.isEmpty()) - { - m_page->findText(text); - - return 0; - } - - QWebEnginePage::FindFlags nativeFlags; - - if (flags.testFlag(BackwardFind)) - { - nativeFlags |= QWebEnginePage::FindBackward; - } - - if (flags.testFlag(CaseSensitiveFind)) - { - nativeFlags |= QWebEnginePage::FindCaseSensitively; - } - - QEventLoop eventLoop; - bool hasMatch(false); - - m_page->findText(text, nativeFlags, [&](const QVariant &result) - { - hasMatch = result.toBool(); - - eventLoop.quit(); - }); - - connect(this, &QtWebEngineWebWidget::aboutToReload, &eventLoop, &QEventLoop::quit); - connect(this, &QtWebEngineWebWidget::destroyed, &eventLoop, &QEventLoop::quit); - - eventLoop.exec(); - - return (hasMatch ? -1 : 0); -} - bool QtWebEngineWebWidget::canGoBack() const { return m_page->history()->canGoBack(); diff --git a/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.h b/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.h index 085dea5f87..cdb252b2fa 100644 --- a/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.h +++ b/src/modules/backends/web/qtwebengine/QtWebEngineWebWidget.h @@ -80,6 +80,9 @@ class QtWebEngineWebWidget final : public WebWidget LinkUrl getActiveImage() const override; LinkUrl getActiveLink() const override; LinkUrl getActiveMedia() const override; +#if QTWEBENGINECORE_VERSION >= 0x050E00 + SslInformation getSslInformation() const override; +#endif Session::Window::History getHistory() const override; HitTestResult getHitTestResult(const QPoint &position) override; QStringList getStyleSheets() const override; @@ -92,7 +95,6 @@ class QtWebEngineWebWidget final : public WebWidget QMultiMap getMetaData() const override; LoadingState getLoadingState() const override; int getZoom() const override; - int findInPage(const QString &text, FindFlags flags = NoFlagsFind) override; bool hasSelection() const override; bool hasWatchedChanges(ChangeWatcher watcher) const override; bool isAudible() const override; @@ -102,8 +104,9 @@ class QtWebEngineWebWidget final : public WebWidget bool eventFilter(QObject *object, QEvent *event) override; public slots: - void clearOptions() override; void triggerAction(int identifier, const QVariantMap ¶meters = {}, ActionsManager::TriggerType trigger = ActionsManager::UnknownTrigger) override; + void clearOptions() override; + void findInPage(const QString &text, FindFlags flags = NoFlagsFind) override; void setActiveStyleSheet(const QString &styleSheet) override; void setPermission(FeaturePermission feature, const QUrl &url, PermissionPolicies policies) override; void setOption(int identifier, const QVariant &value) override; @@ -166,6 +169,9 @@ protected slots: QtWebEnginePage *m_page; #if QTWEBENGINECORE_VERSION >= 0x050D00 QtWebEngineUrlRequestInterceptor *m_requestInterceptor; +#endif +#if QTWEBENGINECORE_VERSION >= 0x050E00 + QString m_findInPageText; #endif QDateTime m_lastUrlClickTime; QPixmap m_thumbnail; diff --git a/src/modules/backends/web/qtwebkit/QtWebKitInspector.cpp b/src/modules/backends/web/qtwebkit/QtWebKitInspector.cpp deleted file mode 100644 index 11b9b27a1f..0000000000 --- a/src/modules/backends/web/qtwebkit/QtWebKitInspector.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/************************************************************************** -* Otter Browser: Web browser controlled by the user, not vice-versa. -* Copyright (C) 2015 - 2019 Michal Dutkiewicz aka Emdek -* -* 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 "QtWebKitInspector.h" - -#include -#include - -namespace Otter -{ - -QtWebKitInspector::QtWebKitInspector(QWidget *parent) : QWebInspector(parent) -{ - setMinimumHeight(200); -} - -void QtWebKitInspector::childEvent(QChildEvent *event) -{ - QWebInspector::childEvent(event); - - if (event->type() == QEvent::ChildAdded && event->child()->inherits("QWebView")) - { - QWebView *webView(qobject_cast(event->child())); - - if (webView) - { - webView->settings()->setAttribute(QWebSettings::JavascriptEnabled, true); - } - } -} - -} diff --git a/src/modules/backends/web/qtwebkit/QtWebKitInspector.h b/src/modules/backends/web/qtwebkit/QtWebKitInspector.h deleted file mode 100644 index 4e3e8a6b67..0000000000 --- a/src/modules/backends/web/qtwebkit/QtWebKitInspector.h +++ /dev/null @@ -1,41 +0,0 @@ -/************************************************************************** -* Otter Browser: Web browser controlled by the user, not vice-versa. -* Copyright (C) 2015 - 2019 Michal Dutkiewicz aka Emdek -* -* 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 OTTER_QTWEBKITINSPECTOR_H -#define OTTER_QTWEBKITINSPECTOR_H - -#include - -namespace Otter -{ - -class QtWebKitInspector final : public QWebInspector -{ - Q_OBJECT - -public: - explicit QtWebKitInspector(QWidget *parent); - -protected: - void childEvent(QChildEvent *event) override; -}; - -} - -#endif diff --git a/src/modules/backends/web/qtwebkit/QtWebKitPage.cpp b/src/modules/backends/web/qtwebkit/QtWebKitPage.cpp index 8517705cd4..5f765d88ff 100644 --- a/src/modules/backends/web/qtwebkit/QtWebKitPage.cpp +++ b/src/modules/backends/web/qtwebkit/QtWebKitPage.cpp @@ -577,28 +577,6 @@ bool QtWebKitPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkReque return false; } - const bool isAnchorNavigation(frame && (type == NavigationTypeLinkClicked || type == NavigationTypeOther) && frame->url().matches(request.url(), QUrl::RemoveFragment)); - - if (mainFrame() == frame) - { - if (m_widget && !isAnchorNavigation) - { - if (frame->url().isEmpty()) - { - m_widget->setRequestedUrl(request.url(), false, true); - } - - m_widget->handleNavigationRequest(request.url(), type); - } - - m_networkManager->setMainRequest(request.url()); - } - - if (type == NavigationTypeFormSubmitted && QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) - { - m_networkManager->setFormRequest(request.url()); - } - if (type == NavigationTypeFormResubmitted && SettingsManager::getOption(SettingsManager::Choices_WarnFormResendOption).toBool()) { bool shouldCancelRequest(false); @@ -639,6 +617,28 @@ bool QtWebKitPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkReque } } + const bool isAnchorNavigation(frame && (type == NavigationTypeLinkClicked || type == NavigationTypeOther) && frame->url().matches(request.url(), QUrl::RemoveFragment)); + + if (mainFrame() == frame) + { + if (m_widget && !isAnchorNavigation) + { + if (frame->url().isEmpty()) + { + m_widget->setRequestedUrl(request.url(), false, true); + } + + m_widget->handleNavigationRequest(request.url(), type); + } + + m_networkManager->setMainRequest(request.url()); + } + + if (type == NavigationTypeFormSubmitted && QGuiApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)) + { + m_networkManager->setFormRequest(request.url()); + } + if (type != NavigationTypeOther) { emit isDisplayingErrorPageChanged(frame, false); diff --git a/src/modules/backends/web/qtwebkit/QtWebKitPage.h b/src/modules/backends/web/qtwebkit/QtWebKitPage.h index 332164427d..b6d3dc5260 100644 --- a/src/modules/backends/web/qtwebkit/QtWebKitPage.h +++ b/src/modules/backends/web/qtwebkit/QtWebKitPage.h @@ -83,7 +83,7 @@ public slots: void updateStyleSheets(const QUrl &url = {}); protected: - QtWebKitPage(); + explicit QtWebKitPage(); explicit QtWebKitPage(const QUrl &url); void markAsPopup(); diff --git a/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.cpp b/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.cpp index c1ebc8ad3f..226923cc8c 100644 --- a/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.cpp +++ b/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.cpp @@ -283,6 +283,11 @@ int QtWebKitWebBackend::getOptionIdentifier(QtWebKitWebBackend::OptionIdentifier return -1; } +bool QtWebKitWebBackend::hasSslSupport() const +{ + return QSslSocket::supportsSsl(); +} + QtWebKitBookmarksImportJob::QtWebKitBookmarksImportJob(BookmarksModel::Bookmark *folder, const QString &path, bool areDuplicatesAllowed, QObject *parent) : BookmarksImportJob(folder, areDuplicatesAllowed, parent), m_path(path), m_currentAmount(0), @@ -355,7 +360,7 @@ void QtWebKitBookmarksImportJob::processElement(const QWebElement &element) if (matchedElement.hasAttribute(QLatin1String("ADD_DATE"))) { - const QDateTime dateTime(getDateTime(matchedElement, QLatin1String("ADD_DATE"))); + const QDateTime dateTime(getDateTime(matchedElement.attribute(QLatin1String("ADD_DATE")))); if (dateTime.isValid()) { @@ -366,7 +371,7 @@ void QtWebKitBookmarksImportJob::processElement(const QWebElement &element) if (matchedElement.hasAttribute(QLatin1String("LAST_MODIFIED"))) { - const QDateTime dateTime(getDateTime(matchedElement, QLatin1String("LAST_MODIFIED"))); + const QDateTime dateTime(getDateTime(matchedElement.attribute(QLatin1String("LAST_MODIFIED")))); if (dateTime.isValid()) { @@ -376,7 +381,7 @@ void QtWebKitBookmarksImportJob::processElement(const QWebElement &element) if (isUrlBookmark && matchedElement.hasAttribute(QLatin1String("LAST_VISITED"))) { - const QDateTime dateTime(getDateTime(matchedElement, QLatin1String("LAST_VISITED"))); + const QDateTime dateTime(getDateTime(matchedElement.attribute(QLatin1String("LAST_VISITED")))); if (dateTime.isValid()) { @@ -455,19 +460,6 @@ void QtWebKitBookmarksImportJob::cancel() { } -QDateTime QtWebKitBookmarksImportJob::getDateTime(const QWebElement &element, const QString &attribute) -{ -#if QT_VERSION < 0x050800 - const uint seconds(element.attribute(attribute).toUInt()); - - return ((seconds > 0) ? QDateTime::fromTime_t(seconds) : QDateTime()); -#else - const qint64 seconds(element.attribute(attribute).toLongLong()); - - return ((seconds != 0) ? QDateTime::fromSecsSinceEpoch(seconds) : QDateTime()); -#endif -} - bool QtWebKitBookmarksImportJob::isRunning() const { return m_isRunning; diff --git a/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.h b/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.h index 235ffa396d..4593d7bbe5 100644 --- a/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.h +++ b/src/modules/backends/web/qtwebkit/QtWebKitWebBackend.h @@ -57,6 +57,7 @@ class QtWebKitWebBackend final : public WebBackend QUrl getHomePage() const override; BackendCapabilities getCapabilities() const override; static int getOptionIdentifier(OptionIdentifier identifier); + bool hasSslSupport() const override; protected: static QtWebKitWebBackend* getInstance(); @@ -97,7 +98,6 @@ public slots: protected: void processElement(const QWebElement &element); - static QDateTime getDateTime(const QWebElement &element, const QString &attribute); private: QString m_path; diff --git a/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.cpp b/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.cpp index ad7cb2524d..9c747b99e8 100644 --- a/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.cpp +++ b/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.cpp @@ -19,7 +19,6 @@ **************************************************************************/ #include "QtWebKitWebWidget.h" -#include "QtWebKitInspector.h" #include "QtWebKitNetworkManager.h" #include "QtWebKitPage.h" #include "QtWebKitPluginWidget.h" @@ -74,10 +73,30 @@ namespace Otter { +QtWebKitInspectorWidget::QtWebKitInspectorWidget(QWidget *parent) : QWebInspector(parent) +{ + setMinimumHeight(200); +} + +void QtWebKitInspectorWidget::childEvent(QChildEvent *event) +{ + QWebInspector::childEvent(event); + + if (event->type() == QEvent::ChildAdded && event->child()->inherits("QWebView")) + { + QWebView *webView(qobject_cast(event->child())); + + if (webView) + { + webView->settings()->setAttribute(QWebSettings::JavascriptEnabled, true); + } + } +} + QtWebKitWebWidget::QtWebKitWebWidget(const QVariantMap ¶meters, WebBackend *backend, QtWebKitNetworkManager *networkManager, ContentsWidget *parent) : WebWidget(parameters, backend, parent), m_webView(new QWebView(this)), m_page(nullptr), - m_inspector(nullptr), + m_inspectorWidget(nullptr), m_networkManager(networkManager), m_formRequestOperation(QNetworkAccessManager::GetOperation), m_loadingState(FinishedLoadingState), @@ -229,1507 +248,1532 @@ void QtWebKitWebWidget::focusInEvent(QFocusEvent *event) emit widgetActivated(this); } -void QtWebKitWebWidget::search(const QString &query, const QString &searchEngine) +void QtWebKitWebWidget::triggerAction(int identifier, const QVariantMap ¶meters, ActionsManager::TriggerType trigger) { - QNetworkRequest request; - QNetworkAccessManager::Operation method; - QByteArray body; + const HitTestResult hitResult(getCurrentHitTestResult()); - if (SearchEnginesManager::setupSearchQuery(query, searchEngine, &request, &method, &body)) + switch (identifier) { - setRequestedUrl(request.url(), false, true); - updateOptions(request.url()); + case ActionsManager::SaveAction: + if (m_page->isViewingMedia()) + { + const SaveInformation information(Utils::getSavePath(suggestSaveFileName(SingleFileSaveFormat))); - m_page->mainFrame()->load(request, method, body); - } -} + if (information.canSave) + { + QNetworkRequest request(getUrl()); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); -void QtWebKitWebWidget::print(QPrinter *printer) -{ - m_page->mainFrame()->print(printer); -} + TransfersManager::startTransfer(m_networkManager->get(request), information.path, (Transfer::CanAskForPathOption | Transfer::CanAutoDeleteOption | Transfer::CanOverwriteOption | Transfer::IsPrivateOption)); + } + } + else + { + SaveFormat format(UnknownSaveFormat); + const QString path(getSavePath({SingleFileSaveFormat, PdfSaveFormat}, &format)); -void QtWebKitWebWidget::saveState(QWebFrame *frame, QWebHistoryItem *item) -{ - if (frame == m_page->mainFrame()) - { - QVariantList state(m_page->history()->currentItem().userData().toList()); + if (!path.isEmpty()) + { + switch (format) + { + case PdfSaveFormat: + { + QPrinter printer; + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setOutputFileName(path); + printer.setCreator(QStringLiteral("Otter Browser %1").arg(Application::getFullVersion())); + printer.setDocName(getTitle()); - if (state.isEmpty() || state.count() < 4) - { - state = {0, getZoom(), m_page->mainFrame()->scrollPosition(), QDateTime::currentDateTimeUtc()}; - } - else - { - state[ZoomEntryData] = getZoom(); - state[PositionEntryData] = m_page->mainFrame()->scrollPosition(); - } + m_page->mainFrame()->print(&printer); + } - item->setUserData(state); - } -} + break; + default: + { + QNetworkRequest request(getUrl()); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); -void QtWebKitWebWidget::restoreState(QWebFrame *frame) -{ - if (frame == m_page->mainFrame()) - { - const QVariantList state(m_page->history()->currentItem().userData().toList()); + TransfersManager::startTransfer(m_networkManager->get(request), path, (Transfer::CanAskForPathOption | Transfer::CanAutoDeleteOption | Transfer::CanOverwriteOption | Transfer::IsPrivateOption)); + } - setZoom(state.value(ZoomEntryData, getZoom()).toInt()); + break; + } + } + } - if (m_page->mainFrame()->scrollPosition().isNull()) - { - m_page->mainFrame()->setScrollPosition(state.value(PositionEntryData).toPoint()); - } - } -} + break; + case ActionsManager::ClearTabHistoryAction: + if (parameters.value(QLatin1String("clearGlobalHistory")).toBool()) + { + for (int i = 0; i < m_page->history()->count(); ++i) + { + const quint64 historyIdentifier(m_page->history()->itemAt(i).userData().toList().value(IdentifierEntryData).toULongLong()); -void QtWebKitWebWidget::clearPluginToken() -{ - QList frames({m_page->mainFrame()}); + if (historyIdentifier > 0) + { + HistoryManager::removeEntry(historyIdentifier); + } + } + } - while (!frames.isEmpty()) - { - const QWebFrame *frame(frames.takeFirst()); - QWebElement element(frame->documentElement().findFirst(QStringLiteral("object[data-otter-browser='%1'], embed[data-otter-browser='%1']").arg(m_pluginToken))); + setUrl(QUrl(QLatin1String("about:blank"))); - if (!element.isNull()) - { - element.removeAttribute(QLatin1String("data-otter-browser")); + m_page->history()->clear(); - break; - } + emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory}); - frames.append(frame->childFrames()); - } + break; + case ActionsManager::PurgeTabHistoryAction: + triggerAction(ActionsManager::ClearTabHistoryAction, {{QLatin1String("clearGlobalHistory"), true}}, trigger); - emit arbitraryActionsStateChanged({ActionsManager::LoadPluginsAction}); + break; + case ActionsManager::MuteTabMediaAction: + m_isAudioMuted = !m_isAudioMuted; - m_pluginToken.clear(); -} + muteAudio(m_page->mainFrame(), m_isAudioMuted); -void QtWebKitWebWidget::resetSpellCheck(QWebElement element) -{ - if (element.isNull()) - { - element = m_page->mainFrame()->findFirstElement(QLatin1String("*:focus")); - } + emit arbitraryActionsStateChanged({ActionsManager::MuteTabMediaAction}); - if (!element.isNull()) - { - m_page->runScript(QLatin1String("resetSpellCheck"), element); - } -} + break; + case ActionsManager::OpenLinkAction: + case ActionsManager::OpenLinkInCurrentTabAction: + case ActionsManager::OpenLinkInNewTabAction: + case ActionsManager::OpenLinkInNewTabBackgroundAction: + case ActionsManager::OpenLinkInNewWindowAction: + case ActionsManager::OpenLinkInNewWindowBackgroundAction: + case ActionsManager::OpenLinkInNewPrivateTabAction: + case ActionsManager::OpenLinkInNewPrivateTabBackgroundAction: + case ActionsManager::OpenLinkInNewPrivateWindowAction: + case ActionsManager::OpenLinkInNewPrivateWindowBackgroundAction: + { + const SessionsManager::OpenHints hints((identifier == ActionsManager::OpenLinkAction) ? SessionsManager::calculateOpenHints(parameters) : mapOpenActionToOpenHints(identifier)); -void QtWebKitWebWidget::muteAudio(QWebFrame *frame, bool isMuted) -{ - if (!frame) - { - return; - } + if (hints == SessionsManager::DefaultOpen && !hitResult.flags.testFlag(HitTestResult::IsLinkFromSelectionTest)) + { + m_page->triggerAction(QWebPage::OpenLink); - const QString script(QLatin1String("this.muted = ") + (isMuted ? QLatin1String("true") : QLatin1String("false"))); - const QWebElementCollection elements(frame->findAllElements(QLatin1String("audio, video"))); + setClickPosition({}); + } + else if (hitResult.linkUrl.isValid()) + { + openUrl(hitResult.linkUrl, hints); + } + } - for (int i = 0; i < elements.count(); ++i) - { - elements.at(i).evaluateJavaScript(script); - } + break; + case ActionsManager::CopyLinkToClipboardAction: + if (!hitResult.linkUrl.isEmpty()) + { + Application::clipboard()->setText(hitResult.linkUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); + } - const QList frames(frame->childFrames()); + break; + case ActionsManager::BookmarkLinkAction: + if (hitResult.linkUrl.isValid()) + { + const QString title(hitResult.title); - for (int i = 0; i < frames.count(); ++i) - { - muteAudio(frames.at(i), isMuted); - } -} + Application::triggerAction(ActionsManager::BookmarkPageAction, {{QLatin1String("url"), hitResult.linkUrl}, {QLatin1String("title"), (title.isEmpty() ? m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element().toPlainText() : title)}}, parentWidget(), trigger); + } -void QtWebKitWebWidget::openRequest(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, QIODevice *outgoingData) -{ - m_formRequest = request; - m_formRequestOperation = operation; - m_formRequestBody = (outgoingData ? outgoingData->readAll() : QByteArray()); + break; + case ActionsManager::SaveLinkToDiskAction: + if (hitResult.linkUrl.isValid()) + { + handleDownloadRequested(QNetworkRequest(hitResult.linkUrl)); + } + else + { + m_page->triggerAction(QWebPage::DownloadLinkToDisk); + } - if (outgoingData) - { - outgoingData->close(); - outgoingData->deleteLater(); - } + break; + case ActionsManager::SaveLinkToDownloadsAction: + TransfersManager::addTransfer(TransfersManager::startTransfer(hitResult.linkUrl.toString(), {}, (Transfer::CanNotifyOption | Transfer::CanAskForPathOption | Transfer::IsQuickTransferOption | (isPrivate() ? Transfer::IsPrivateOption : Transfer::NoOption)))); - setRequestedUrl(m_formRequest.url(), false, true); - updateOptions(m_formRequest.url()); + break; + case ActionsManager::OpenFrameAction: + case ActionsManager::OpenFrameInCurrentTabAction: + case ActionsManager::OpenFrameInNewTabAction: + case ActionsManager::OpenFrameInNewTabBackgroundAction: + if (hitResult.frameUrl.isValid()) + { + openUrl(hitResult.frameUrl, ((identifier == ActionsManager::OpenFrameAction) ? SessionsManager::calculateOpenHints(parameters) : mapOpenActionToOpenHints(identifier))); + } - QTimer::singleShot(50, this, [&]() - { - m_page->mainFrame()->load(m_formRequest, m_formRequestOperation, m_formRequestBody); + break; + case ActionsManager::CopyFrameLinkToClipboardAction: + if (hitResult.frameUrl.isValid()) + { + Application::clipboard()->setText(hitResult.frameUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); + } - m_formRequest = QNetworkRequest(); - m_formRequestBody.clear(); - }); -} + break; + case ActionsManager::ReloadFrameAction: + if (hitResult.frameUrl.isValid()) + { + const QUrl url(hitResult.frameUrl); + QWebFrame *frame(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).frame()); -void QtWebKitWebWidget::openFormRequest(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, QIODevice *outgoingData) -{ - m_page->triggerAction(QWebPage::Stop); + if (frame) + { + m_networkManager->addContentBlockingException(url, NetworkManager::SubFrameType); - QtWebKitWebWidget *widget(qobject_cast(clone(false))); - widget->openRequest(request, operation, outgoingData); + frame->setUrl({}); + frame->setUrl(url); + } + } - emit requestedNewWindow(widget, SessionsManager::calculateOpenHints(SessionsManager::NewTabOpen), {}); -} + break; + case ActionsManager::ViewFrameSourceAction: + if (hitResult.frameUrl.isValid()) + { + const QString defaultEncoding(m_page->settings()->defaultTextEncoding()); + QNetworkRequest request(hitResult.frameUrl); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); -void QtWebKitWebWidget::startDelayedTransfer(Transfer *transfer) -{ - m_transfers.enqueue(transfer); + QNetworkReply *reply(m_networkManager->get(request)); + SourceViewerWebWidget *sourceViewer(new SourceViewerWebWidget(isPrivate())); + sourceViewer->setRequestedUrl(QUrl(QLatin1String("view-source:") + hitResult.frameUrl.toString()), false); - if (m_transfersTimer == 0) - { - m_transfersTimer = startTimer(250); - } -} + if (!defaultEncoding.isEmpty()) + { + sourceViewer->setOption(SettingsManager::Content_DefaultCharacterEncodingOption, defaultEncoding); + } -void QtWebKitWebWidget::handleDownloadRequested(const QNetworkRequest &request) -{ - const HitTestResult hitResult(getCurrentHitTestResult()); + m_viewSourceReplies[reply] = sourceViewer; - if ((!hitResult.imageUrl.isEmpty() && request.url() == hitResult.imageUrl) || (!hitResult.mediaUrl.isEmpty() && request.url() == hitResult.mediaUrl)) - { - NetworkCache *cache(NetworkManagerFactory::getCache()); + connect(reply, &QNetworkReply::finished, this, &QtWebKitWebWidget::handleViewSourceReplyFinished); - if (cache && cache->metaData(request.url()).isValid()) - { - QIODevice *device(cache->data(request.url())); + emit requestedNewWindow(sourceViewer, SessionsManager::DefaultOpen, {}); + } - if (device && device->size() > 0) + break; + case ActionsManager::OpenImageAction: + case ActionsManager::OpenImageInNewTabAction: + case ActionsManager::OpenImageInNewTabBackgroundAction: + if (hitResult.imageUrl.isValid()) { - const QString path(Utils::getSavePath(request.url().fileName()).path); + openUrl(hitResult.imageUrl, ((identifier == ActionsManager::OpenImageAction) ? SessionsManager::calculateOpenHints(parameters) : mapOpenActionToOpenHints(identifier))); + } - if (path.isEmpty()) - { - device->deleteLater(); + break; + case ActionsManager::SaveImageToDiskAction: + if (hitResult.imageUrl.isValid()) + { + handleDownloadRequested(QNetworkRequest(hitResult.imageUrl)); + } - return; + break; + case ActionsManager::CopyImageToClipboardAction: + { + const QPixmap pixmap(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).pixmap()); + + if (!pixmap.isNull()) + { + Application::clipboard()->setPixmap(pixmap); + } + else + { + m_page->triggerAction(QWebPage::CopyImageToClipboard); } + } - QFile file(path); + break; + case ActionsManager::CopyImageUrlToClipboardAction: + if (!hitResult.imageUrl.isEmpty()) + { + Application::clipboard()->setText(hitResult.imageUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); + } - if (!file.open(QIODevice::WriteOnly)) + break; + case ActionsManager::ReloadImageAction: + if (!hitResult.imageUrl.isEmpty()) + { + m_networkManager->addContentBlockingException(hitResult.imageUrl, NetworkManager::ImageType); + + m_page->settings()->setAttribute(QWebSettings::AutoLoadImages, true); + + if (getUrl().matches(hitResult.imageUrl, (QUrl::NormalizePathSegments | QUrl::RemoveFragment | QUrl::StripTrailingSlash))) { - QMessageBox::critical(this, tr("Error"), tr("Failed to open file for writing."), QMessageBox::Close); + triggerAction(ActionsManager::ReloadAndBypassCacheAction, {}, trigger); } + else + { + QWebElement element(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element()); + const QUrl url(hitResult.imageUrl); + const QString src(element.attribute(QLatin1String("src"))); + NetworkCache *cache(NetworkManagerFactory::getCache()); - file.write(device->readAll()); - file.close(); + element.setAttribute(QLatin1String("src"), {}); - device->deleteLater(); + if (cache) + { + cache->remove(url); + } - return; - } + element.setAttribute(QLatin1String("src"), src); - if (device) - { - device->deleteLater(); + m_page->mainFrame()->documentElement().evaluateJavaScript(QStringLiteral("var images = document.querySelectorAll('img[src=\"%1\"]'); for (var i = 0; i < images.length; ++i) { images[i].src = ''; images[i].src = '%1'; }").arg(src)); + } } - } - else if (!hitResult.imageUrl.isEmpty() && hitResult.imageUrl.scheme() == QLatin1String("data") && hitResult.imageUrl.url().contains(QLatin1String(";base64,"))) - { - const QString imageUrl(hitResult.imageUrl.url()); - const QString imageType(imageUrl.mid(11, (imageUrl.indexOf(QLatin1Char(';')) - 11))); - const QString path(Utils::getSavePath(tr("file") + QLatin1Char('.') + imageType).path); - if (!path.isEmpty()) + break; + case ActionsManager::ImagePropertiesAction: { - QImageWriter writer(path); + QVariantMap properties({{QLatin1String("alternativeText"), hitResult.alternateText}, {QLatin1String("longDescription"), hitResult.longDescription}}); + const QPixmap pixmap(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).pixmap()); - if (!writer.write(QImage::fromData(QByteArray::fromBase64(imageUrl.mid(imageUrl.indexOf(QLatin1String(";base64,")) + 7).toUtf8()), imageType.toStdString().c_str()))) + if (!pixmap.isNull()) { - Console::addMessage(tr("Failed to save image: %1").arg(writer.errorString()), Console::OtherCategory, Console::ErrorLevel, path, -1, getWindowIdentifier()); + properties[QLatin1String("width")] = pixmap.width(); + properties[QLatin1String("height")] = pixmap.height(); + properties[QLatin1String("depth")] = pixmap.depth(); } - } - - return; - } - QNetworkRequest mutableRequest(request); - mutableRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + ImagePropertiesDialog *imagePropertiesDialog(new ImagePropertiesDialog(hitResult.imageUrl, properties, (m_networkManager->cache() ? m_networkManager->cache()->data(hitResult.imageUrl) : nullptr), this)); + imagePropertiesDialog->setButtonsVisible(false); - TransfersManager::startTransfer(m_networkManager->get(mutableRequest), {}, (Transfer::CanAskForPathOption | Transfer::CanAutoDeleteOption | Transfer::IsPrivateOption)); - } - else - { - startDelayedTransfer(TransfersManager::startTransfer(request, {}, (Transfer::CanNotifyOption | (isPrivate() ? Transfer::IsPrivateOption : Transfer::NoOption)))); - } -} + ContentsDialog *dialog(new ContentsDialog(ThemesManager::createIcon(QLatin1String("dialog-information")), imagePropertiesDialog->windowTitle(), {}, {}, QDialogButtonBox::Close, imagePropertiesDialog, this)); -void QtWebKitWebWidget::handleUnsupportedContent(QNetworkReply *reply) -{ - m_networkManager->registerTransfer(reply); + connect(this, &QtWebKitWebWidget::aboutToReload, dialog, &ContentsDialog::close); + connect(imagePropertiesDialog, &ImagePropertiesDialog::finished, dialog, &ContentsDialog::close); - startDelayedTransfer(TransfersManager::startTransfer(reply, {}, (Transfer::CanNotifyOption | (isPrivate() ? Transfer::IsPrivateOption : Transfer::NoOption)))); -} + showDialog(dialog, false); + } -void QtWebKitWebWidget::handleOptionChanged(int identifier, const QVariant &value) -{ - switch (identifier) - { - case SettingsManager::Content_BackgroundColorOption: + break; + case ActionsManager::SaveMediaToDiskAction: + if (hitResult.mediaUrl.isValid()) { - QPalette palette(m_page->palette()); - palette.setColor(QPalette::Base, QColor(value.toString())); - - m_page->setPalette(palette); + handleDownloadRequested(QNetworkRequest(hitResult.mediaUrl)); } break; - case SettingsManager::History_BrowsingLimitAmountWindowOption: - m_page->history()->setMaximumItemCount(value.toInt()); + case ActionsManager::CopyMediaUrlToClipboardAction: + if (!hitResult.mediaUrl.isEmpty()) + { + Application::clipboard()->setText(hitResult.mediaUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); + } break; - case SettingsManager::Permissions_ScriptsCanShowStatusMessagesOption: - disconnect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); + case ActionsManager::MediaControlsAction: + m_page->triggerAction(QWebPage::ToggleMediaControls, parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool()); - if (value.toBool() || SettingsManager::getOption(identifier, Utils::extractHost(getUrl())).toBool()) - { - connect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); - } - else - { - setStatusMessage({}); - } + break; + case ActionsManager::MediaLoopAction: + m_page->triggerAction(QWebPage::ToggleMediaLoop, parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool()); break; - default: + case ActionsManager::MediaPlayPauseAction: + m_page->triggerAction(QWebPage::ToggleMediaPlayPause); + break; - } -} + case ActionsManager::MediaMuteAction: + m_page->triggerAction(QWebPage::ToggleMediaMute); -void QtWebKitWebWidget::handleLoadStarted() -{ - if (m_loadingState == OngoingLoadingState) - { - return; - } + break; + case ActionsManager::MediaPlaybackRateAction: + m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element().evaluateJavaScript(QStringLiteral("this.playbackRate = %1").arg(parameters.value(QLatin1String("rate"), 1).toReal())); - m_thumbnail = {}; - m_messageToken = QUuid::createUuid().toString(); - m_canLoadPlugins = (getOption(SettingsManager::Permissions_EnablePluginsOption, getUrl()).toString() == QLatin1String("enabled")); - m_loadingState = OngoingLoadingState; + break; + case ActionsManager::GoBackAction: + m_page->triggerAction(QWebPage::Back); - setStatusMessage({}); - setStatusMessageOverride({}); + break; + case ActionsManager::GoForwardAction: + m_page->triggerAction(QWebPage::Forward); - emit geometryChanged(); - emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory}); - emit loadingStateChanged(OngoingLoadingState); -} + break; + case ActionsManager::GoToHistoryIndexAction: + if (parameters.contains(QLatin1String("index"))) + { + const int index(parameters[QLatin1String("index")].toInt()); -void QtWebKitWebWidget::handleLoadProgress(int progress) -{ - m_networkManager->setPageInformation(TotalLoadingProgressInformation, progress); -} + if (index >= 0 && index < m_page->history()->count()) + { + m_page->history()->goToItem(m_page->history()->itemAt(index)); + } + } -void QtWebKitWebWidget::handleLoadFinished(bool result) -{ - if (m_isAudioMuted) - { - muteAudio(m_page->mainFrame(), true); - } + break; + case ActionsManager::RewindAction: + m_page->history()->goToItem(m_page->history()->itemAt(0)); - if (m_loadingState != OngoingLoadingState) - { - return; - } - - m_networkManager->handleLoadFinished(result); - - m_thumbnail = {}; - m_loadingState = FinishedLoadingState; - - updateAmountOfDeferredPlugins(); - handleHistory(); - startReloadTimer(); - - emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory}); - emit contentStateChanged(getContentState()); - emit loadingStateChanged(FinishedLoadingState); - emit watchedDataChanged(FeedsWatcher); - emit watchedDataChanged(LinksWatcher); - emit watchedDataChanged(MetaDataWatcher); - emit watchedDataChanged(SearchEnginesWatcher); - emit watchedDataChanged(StylesheetsWatcher); -} - -void QtWebKitWebWidget::handleViewSourceReplyFinished() -{ - QNetworkReply *reply(qobject_cast(sender())); - - if (reply) - { - if (reply->error() == QNetworkReply::NoError && m_viewSourceReplies.contains(reply) && m_viewSourceReplies[reply]) - { - m_viewSourceReplies[reply]->setContents(reply->readAll(), reply->header(QNetworkRequest::ContentTypeHeader).toString()); - } - - m_viewSourceReplies.remove(reply); - - reply->deleteLater(); - } -} - -void QtWebKitWebWidget::handlePrintRequest(QWebFrame *frame) -{ - QPrintPreviewDialog printPreviewDialog(this); - printPreviewDialog.setWindowFlags(printPreviewDialog.windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint); - printPreviewDialog.setWindowTitle(tr("Print Preview")); - - if (Application::getActiveWindow()) - { - printPreviewDialog.resize(Application::getActiveWindow()->size()); - } - - connect(&printPreviewDialog, &QPrintPreviewDialog::paintRequested, frame, &QWebFrame::print); - - printPreviewDialog.exec(); -} - -void QtWebKitWebWidget::handleHistory() -{ - if (isPrivate() || m_page->history()->count() == 0) - { - return; - } - - const QUrl url(m_page->history()->currentItem().url()); - const QVariant state(m_page->history()->currentItem().userData()); - - if (state.isValid()) - { - const quint64 identifier(state.toList().value(IdentifierEntryData).toULongLong()); + break; + case ActionsManager::FastForwardAction: + { + const QUrl url(m_page->mainFrame()->evaluateJavaScript(getFastForwardScript(true)).toUrl()); - if (identifier > 0) - { - HistoryManager::updateEntry(identifier, url, getTitle(), m_page->mainFrame()->icon()); - } - } - else - { - m_page->history()->currentItem().setUserData(QVariantList({(Utils::isUrlEmpty(url) ? 0 : HistoryManager::addEntry(url, getTitle(), m_page->mainFrame()->icon(), m_isTypedIn)), getZoom(), QPoint(0, 0), QDateTime::currentDateTimeUtc()})); + if (url.isValid()) + { + setUrl(url); + } + else if (canGoForward()) + { + m_page->triggerAction(QWebPage::Forward); + } + } - if (m_isTypedIn) - { - m_isTypedIn = false; - } + break; + case ActionsManager::RemoveHistoryIndexAction: + if (parameters.contains(QLatin1String("index"))) + { + const int index(parameters[QLatin1String("index")].toInt()); - SessionsManager::markSessionAsModified(); - BookmarksManager::updateVisits(url.toString()); - } -} + if (index >= 0 && index < m_page->history()->count()) + { + if (parameters.value(QLatin1String("clearGlobalHistory"), false).toBool()) + { + const quint64 entryIdentifier(m_page->history()->itemAt(index).userData().toList().value(IdentifierEntryData).toULongLong()); -void QtWebKitWebWidget::handleNavigationRequest(const QUrl &url, QWebPage::NavigationType type) -{ - if (type != QWebPage::NavigationTypeBackOrForward && (type != QWebPage::NavigationTypeLinkClicked || !getUrl().matches(url, QUrl::RemoveFragment))) - { - handleLoadStarted(); - handleHistory(); + if (entryIdentifier > 0) + { + HistoryManager::removeEntry(entryIdentifier); + } + } - m_networkManager->resetStatistics(); - } + Session::Window::History history(getHistory()); + history.entries.removeAt(index); - updateOptions(url); + if (history.index >= index) + { + history.index = (history.index - 1); + } - m_isNavigating = true; + setHistory(history); + } + } - emit aboutToNavigate(); -} + break; + case ActionsManager::StopAction: + m_page->triggerAction(QWebPage::Stop); -void QtWebKitWebWidget::handleFullScreenRequest(QWebFullScreenRequest request) -{ - request.accept(); + break; + case ActionsManager::StopScheduledReloadAction: + m_page->triggerAction(QWebPage::StopScheduledPageRefresh); - if (request.toggleOn()) - { - const QString value(SettingsManager::getOption(SettingsManager::Permissions_EnableFullScreenOption, Utils::extractHost(request.origin())).toString()); + break; + case ActionsManager::ReloadAction: + emit aboutToReload(); - if (value == QLatin1String("allow")) - { - MainWindow *mainWindow(MainWindow::findMainWindow(this)); + m_page->triggerAction(QWebPage::Stop); + m_page->triggerAction(QWebPage::Reload); - if (mainWindow && !mainWindow->isFullScreen()) + break; + case ActionsManager::ReloadOrStopAction: + if (m_loadingState == OngoingLoadingState) { - mainWindow->triggerAction(ActionsManager::FullScreenAction); + triggerAction(ActionsManager::StopAction, {}, trigger); + } + else + { + triggerAction(ActionsManager::ReloadAction, {}, trigger); } - } - else if (value == QLatin1String("ask")) - { - emit requestedPermission(FullScreenFeature, request.origin(), false); - } - } - else - { - MainWindow *mainWindow(MainWindow::findMainWindow(this)); - - if (mainWindow && mainWindow->isFullScreen()) - { - mainWindow->triggerAction(ActionsManager::FullScreenAction); - } - - emit requestedPermission(FullScreenFeature, request.origin(), true); - } - - m_isFullScreen = request.toggleOn(); - - emit isFullScreenChanged(m_isFullScreen); -} - -void QtWebKitWebWidget::handlePermissionRequest(QWebFrame *frame, QWebPage::Feature feature) -{ - notifyPermissionRequested(frame, feature, false); -} - -void QtWebKitWebWidget::handlePermissionCancel(QWebFrame *frame, QWebPage::Feature feature) -{ - notifyPermissionRequested(frame, feature, true); -} - -void QtWebKitWebWidget::notifyTitleChanged() -{ - emit titleChanged(getTitle()); - - handleHistory(); -} -void QtWebKitWebWidget::notifyUrlChanged(const QUrl &url) -{ - m_isNavigating = false; + break; + case ActionsManager::ReloadAndBypassCacheAction: + m_page->triggerAction(QWebPage::ReloadAndBypassCache); - updateOptions(url); + break; + case ActionsManager::ContextMenuAction: + if (parameters.contains(QLatin1String("context")) && parameters[QLatin1String("context")].toInt() == QContextMenuEvent::Keyboard) + { + const QWebElement element(m_page->mainFrame()->findFirstElement(QLatin1String(":focus"))); - emit urlChanged(url); - emit arbitraryActionsStateChanged({ActionsManager::InspectPageAction, ActionsManager::InspectElementAction}); - emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory, ActionsManager::ActionDefinition::PageCategory}); + if (element.isNull()) + { + setClickPosition(m_webView->mapFromGlobal(QCursor::pos())); + } + else + { + QPoint clickPosition(element.geometry().center()); + QWebFrame *frame(element.webFrame()); - SessionsManager::markSessionAsModified(); -} + while (frame) + { + clickPosition -= frame->scrollPosition(); -void QtWebKitWebWidget::notifyIconChanged() -{ - emit iconChanged(getIcon()); -} + frame = frame->parentFrame(); + } -void QtWebKitWebWidget::notifyPermissionRequested(QWebFrame *frame, QWebPage::Feature nativeFeature, bool cancel) -{ - FeaturePermission feature(UnknownFeature); + setClickPosition(clickPosition); + } + } + else + { + setClickPosition(m_webView->mapFromGlobal(QCursor::pos())); + } - switch (nativeFeature) - { - case QWebPage::Geolocation: - feature = GeolocationFeature; + showContextMenu(getClickPosition()); break; - case QWebPage::Notifications: - feature = NotificationsFeature; + case ActionsManager::UndoAction: + m_page->triggerAction(QWebPage::Undo); break; - default: - return; - } - - const QUrl url(frame->url().isValid() ? frame->url() : frame->requestedUrl()); - - if (cancel) - { - emit requestedPermission(feature, url, true); - } - else - { - switch (getPermission(feature, url)) - { - case GrantedPermission: - m_page->setFeaturePermission(frame, nativeFeature, QWebPage::PermissionGrantedByUser); + case ActionsManager::RedoAction: + m_page->triggerAction(QWebPage::Redo); - break; - case DeniedPermission: - m_page->setFeaturePermission(frame, nativeFeature, QWebPage::PermissionDeniedByUser); + break; + case ActionsManager::CutAction: + m_page->triggerAction(QWebPage::Cut); - break; - default: - emit requestedPermission(feature, url, false); + break; + case ActionsManager::CopyAction: + if (parameters.value(QLatin1String("mode")) == QLatin1String("plainText")) + { + const QString text(getSelectedText()); - break; - } - } -} + if (!text.isEmpty()) + { + Application::clipboard()->setText(text); + } + } + else + { + m_page->triggerAction(QWebPage::Copy); + } -void QtWebKitWebWidget::notifySavePasswordRequested(const PasswordsManager::PasswordInformation &password, bool isUpdate) -{ - emit requestedSavePassword(password, isUpdate); -} + break; + case ActionsManager::CopyPlainTextAction: + triggerAction(ActionsManager::CopyAction, {{QLatin1String("mode"), QLatin1String("plainText")}}, trigger); -void QtWebKitWebWidget::updateAmountOfDeferredPlugins() -{ - const int amountOfDeferredPlugins(m_canLoadPlugins ? 0 : findChildren().count()); + break; + case ActionsManager::CopyAddressAction: + Application::clipboard()->setText(getUrl().toString()); - if (amountOfDeferredPlugins != m_amountOfDeferredPlugins) - { - const bool needsActionUpdate(amountOfDeferredPlugins == 0 || m_amountOfDeferredPlugins == 0); + break; + case ActionsManager::CopyToNoteAction: + NotesManager::addNote(BookmarksModel::UrlBookmark, {{BookmarksModel::UrlRole, getUrl()}, {BookmarksModel::DescriptionRole, getSelectedText()}}); - m_amountOfDeferredPlugins = amountOfDeferredPlugins; + break; + case ActionsManager::PasteAction: + if (parameters.contains(QLatin1String("note"))) + { + const BookmarksModel::Bookmark *bookmark(NotesManager::getModel()->getBookmark(parameters[QLatin1String("note")].toULongLong())); - if (needsActionUpdate) - { - emit arbitraryActionsStateChanged({ActionsManager::LoadPluginsAction}); - } - } -} + if (bookmark) + { + triggerAction(ActionsManager::PasteAction, {{QLatin1String("text"), bookmark->getDescription()}}, trigger); + } + } + else if (parameters.contains(QLatin1String("text"))) + { + QMimeData *mimeData(new QMimeData()); + const QStringList mimeTypes(Application::clipboard()->mimeData()->formats()); -void QtWebKitWebWidget::updateOptions(const QUrl &url) -{ - const QString encoding(getOption(SettingsManager::Content_DefaultCharacterEncodingOption, url).toString()); - const bool arePluginsEnabled(getOption(SettingsManager::Permissions_EnablePluginsOption, url).toString() != QLatin1String("disabled")); - QWebSettings *settings(m_page->settings()); - settings->setAttribute(QWebSettings::AutoLoadImages, (getOption(SettingsManager::Permissions_EnableImagesOption, url).toString() != QLatin1String("onlyCached"))); - settings->setAttribute(QWebSettings::DnsPrefetchEnabled, getOption(SettingsManager::Network_EnableDnsPrefetchOption, url).toBool()); - settings->setAttribute(QWebSettings::PluginsEnabled, arePluginsEnabled); - settings->setAttribute(QWebSettings::JavaEnabled, arePluginsEnabled); - settings->setAttribute(QWebSettings::JavascriptEnabled, (m_page->isDisplayingErrorPage() || m_page->isViewingMedia() || getOption(SettingsManager::Permissions_EnableJavaScriptOption, url).toBool())); - settings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, getOption(SettingsManager::Permissions_ScriptsCanAccessClipboardOption, url).toBool()); - settings->setAttribute(QWebSettings::JavascriptCanOpenWindows, (getOption(SettingsManager::Permissions_ScriptsCanOpenWindowsOption, url).toString() != QLatin1String("blockAll"))); - settings->setAttribute(QWebSettings::WebGLEnabled, getOption(SettingsManager::Permissions_EnableWebglOption, url).toBool()); - settings->setAttribute(QWebSettings::LocalStorageEnabled, getOption(SettingsManager::Permissions_EnableLocalStorageOption, url).toBool()); - settings->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, getOption(SettingsManager::Permissions_EnableOfflineStorageDatabaseOption, url).toBool()); - settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, getOption(SettingsManager::Permissions_EnableOfflineWebApplicationCacheOption, url).toBool()); - settings->setAttribute(QWebSettings::AllowRunningInsecureContent, getOption(SettingsManager::Security_AllowMixedContentOption, url).toBool()); - settings->setAttribute(QWebSettings::MediaEnabled, getOption(QtWebKitWebBackend::getOptionIdentifier(QtWebKitWebBackend::QtWebKitBackend_EnableMediaOption), url).toBool()); - settings->setAttribute(QWebSettings::MediaSourceEnabled, getOption(QtWebKitWebBackend::getOptionIdentifier(QtWebKitWebBackend::QtWebKitBackend_EnableMediaSourceOption), url).toBool()); - settings->setAttribute(QWebSettings::WebSecurityEnabled, getOption(QtWebKitWebBackend::getOptionIdentifier(QtWebKitWebBackend::QtWebKitBackend_EnableWebSecurityOption), url).toBool()); - settings->setDefaultTextEncoding((encoding == QLatin1String("auto")) ? QString() : encoding); + for (int i = 0; i < mimeTypes.count(); ++i) + { + mimeData->setData(mimeTypes.at(i), Application::clipboard()->mimeData()->data(mimeTypes.at(i))); + } - disconnect(m_page, &QtWebKitPage::geometryChangeRequested, this, &QtWebKitWebWidget::requestedGeometryChange); - disconnect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); + Application::clipboard()->setText(parameters[QLatin1String("text")].toString()); - if (getOption(SettingsManager::Permissions_ScriptsCanChangeWindowGeometryOption, url).toBool()) - { - connect(m_page, &QtWebKitPage::geometryChangeRequested, this, &QtWebKitWebWidget::requestedGeometryChange); - } + m_page->triggerAction(QWebPage::Paste); - if (getOption(SettingsManager::Permissions_ScriptsCanShowStatusMessagesOption, url).toBool()) - { - connect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); - } - else - { - setStatusMessage({}); - } + Application::clipboard()->setMimeData(mimeData); + } + else + { + m_page->triggerAction(QWebPage::Paste); + } - m_page->updateStyleSheets(url); + break; + case ActionsManager::DeleteAction: + m_page->triggerAction(QWebPage::DeleteEndOfWord); - m_networkManager->updateOptions(url); + break; + case ActionsManager::SelectAllAction: + m_page->triggerAction(QWebPage::SelectAll); - m_canLoadPlugins = (getOption(SettingsManager::Permissions_EnablePluginsOption, url).toString() == QLatin1String("enabled")); -} + break; + case ActionsManager::UnselectAction: + m_page->triggerAction(QWebPage::Unselect); -void QtWebKitWebWidget::clearOptions() -{ - WebWidget::clearOptions(); + break; + case ActionsManager::ClearAllAction: + m_page->triggerAction(QWebPage::SelectAll); + m_page->triggerAction(QWebPage::DeleteEndOfWord); - updateOptions(getUrl()); -} + break; + case ActionsManager::CheckSpellingAction: + { + QWebElement element(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element()); + element.evaluateJavaScript(QStringLiteral("this.spellcheck = %1").arg(parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool() ? QLatin1String("true") : QLatin1String("false"))); -void QtWebKitWebWidget::fillPassword(const PasswordsManager::PasswordInformation &password) -{ - QFile file(QLatin1String(":/modules/backends/web/qtwebkit/resources/formFiller.js")); + if (parameters.contains(QLatin1String("dictionary"))) + { + setOption(SettingsManager::Browser_SpellCheckDictionaryOption, parameters.value(QLatin1String("dictionary"))); + } + else + { + resetSpellCheck(element); + } - if (!file.open(QIODevice::ReadOnly)) - { - return; - } + emit arbitraryActionsStateChanged({ActionsManager::CheckSpellingAction}); + } - QJsonArray fieldsArray; + break; + case ActionsManager::CreateSearchAction: + { + const QWebElement element(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element()); + QWebElement parentElement(element.parent()); - for (int i = 0; i < password.fields.count(); ++i) - { - fieldsArray.append(QJsonObject({{QLatin1String("name"), password.fields.at(i).name}, {QLatin1String("value"), password.fields.at(i).value}, {QLatin1String("type"), ((password.fields.at(i).type == PasswordsManager::PasswordField) ? QLatin1String("password") : QLatin1String("text"))}})); - } + while (!parentElement.isNull() && parentElement.tagName().toLower() != QLatin1String("form")) + { + parentElement = parentElement.parent(); + } - const QString script(QString::fromLatin1(file.readAll()).arg(QString::fromLatin1(QJsonDocument(fieldsArray).toJson(QJsonDocument::Indented)))); + if (!parentElement.hasAttribute(QLatin1String("action"))) + { + break; + } - file.close(); + QList inputElements(parentElement.findAll(QLatin1String("button:not([disabled])[name][type='submit'], input:not([disabled])[name], select:not([disabled])[name], textarea:not([disabled])[name]")).toList()); - QList frames({m_page->mainFrame()}); + if (inputElements.isEmpty()) + { + break; + } - while (!frames.isEmpty()) - { - const QWebFrame *frame(frames.takeFirst()); - frame->documentElement().evaluateJavaScript(script); + QWebElement searchTermsElement; + const QString tagName(element.tagName().toLower()); + const QUrl url(parentElement.attribute(QLatin1String("action"))); + const QIcon icon(m_page->mainFrame()->icon()); + SearchEnginesManager::SearchEngineDefinition searchEngine; + searchEngine.title = getTitle(); + searchEngine.formUrl = getUrl(); + searchEngine.icon = (icon.isNull() ? ThemesManager::createIcon(QLatin1String("edit-find")) : icon); + searchEngine.resultsUrl.url = (url.isEmpty() ? getUrl() : resolveUrl(parentElement.webFrame(), url)).toString(); + searchEngine.resultsUrl.enctype = parentElement.attribute(QLatin1String("enctype")); + searchEngine.resultsUrl.method = ((parentElement.attribute(QLatin1String("method"), QLatin1String("get")).toLower() == QLatin1String("post")) ? QLatin1String("post") : QLatin1String("get")); - frames.append(frame->childFrames()); - } -} + if (tagName != QLatin1String("select")) + { + const QString type(element.attribute(QLatin1String("type"))); -void QtWebKitWebWidget::triggerAction(int identifier, const QVariantMap ¶meters, ActionsManager::TriggerType trigger) -{ - const HitTestResult hitResult(getCurrentHitTestResult()); + if (!inputElements.contains(element) && (type == QLatin1String("image") || type == QLatin1String("submit"))) + { + inputElements.append(element); + } - switch (identifier) - { - case ActionsManager::SaveAction: - if (m_page->isViewingMedia()) - { - const SaveInformation information(Utils::getSavePath(suggestSaveFileName(SingleFileSaveFormat))); + if (tagName == QLatin1String("textarea") || type == QLatin1String("email") || type == QLatin1String("password") || type == QLatin1String("search") || type == QLatin1String("tel") || type == QLatin1String("text") || type == QLatin1String("url")) + { + searchTermsElement = element; + } + } - if (information.canSave) + if (searchTermsElement.isNull()) { - QNetworkRequest request(getUrl()); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - - TransfersManager::startTransfer(m_networkManager->get(request), information.path, (Transfer::CanAskForPathOption | Transfer::CanAutoDeleteOption | Transfer::CanOverwriteOption | Transfer::IsPrivateOption)); + searchTermsElement = parentElement.findFirst(QLatin1String("input:not([disabled])[name][type='search']")); } - } - else - { - SaveFormat format(UnknownSaveFormat); - const QString path(getSavePath({SingleFileSaveFormat, PdfSaveFormat}, &format)); - if (!path.isEmpty()) + for (int i = 0; i < inputElements.count(); ++i) { - switch (format) + const QString name(inputElements.at(i).attribute(QLatin1String("name"))); + + if (inputElements.at(i).tagName().toLower() != QLatin1String("select")) { - case PdfSaveFormat: + const QString type(inputElements.at(i).attribute(QLatin1String("type"))); + const bool isSubmit(type == QLatin1String("image") || type == QLatin1String("submit")); + + if ((isSubmit && inputElements.at(i) != element) || ((type == QLatin1String("checkbox") || type == QLatin1String("radio")) && !inputElements[i].evaluateJavaScript(QLatin1String("this.checked")).toBool())) + { + continue; + } + + if (isSubmit && inputElements.at(i) == element) + { + if (inputElements.at(i).hasAttribute(QLatin1String("formaction"))) { - QPrinter printer; - printer.setOutputFormat(QPrinter::PdfFormat); - printer.setOutputFileName(path); - printer.setCreator(QStringLiteral("Otter Browser %1").arg(Application::getFullVersion())); - printer.setDocName(getTitle()); + searchEngine.resultsUrl.url = resolveUrl(parentElement.webFrame(), inputElements.at(i).attribute(QLatin1String("formaction"))).toString(); + } - m_page->mainFrame()->print(&printer); + if (inputElements.at(i).hasAttribute(QLatin1String("formenctype"))) + { + searchEngine.resultsUrl.enctype = inputElements.at(i).attribute(QLatin1String("formenctype")); } - break; - default: + if (inputElements.at(i).hasAttribute(QLatin1String("formmethod"))) { - QNetworkRequest request(getUrl()); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + searchEngine.resultsUrl.method = inputElements.at(i).attribute(QLatin1String("formmethod")); + } + } + + if (!isSubmit && searchTermsElement.isNull() && type != QLatin1String("hidden")) + { + searchTermsElement = inputElements.at(i); + } - TransfersManager::startTransfer(m_networkManager->get(request), path, (Transfer::CanAskForPathOption | Transfer::CanAutoDeleteOption | Transfer::CanOverwriteOption | Transfer::IsPrivateOption)); - } + if (!name.isEmpty()) + { + searchEngine.resultsUrl.parameters.addQueryItem(name, ((inputElements.at(i) == searchTermsElement) ? QLatin1String("{searchTerms}") : inputElements[i].evaluateJavaScript((inputElements.at(i).tagName().toLower() == QLatin1String("button")) ? QLatin1String("this.innerHTML") : QLatin1String("this.value")).toString())); + } + } + else if (!name.isEmpty()) + { + const QWebElementCollection optionElements(inputElements.at(i).findAll(QLatin1String("option:checked"))); - break; + for (int j = 0; j < optionElements.count(); ++j) + { + searchEngine.resultsUrl.parameters.addQueryItem(name, optionElements.at(j).evaluateJavaScript(QLatin1String("this.value")).toString()); + } } } - } - break; - case ActionsManager::ClearTabHistoryAction: - if (parameters.value(QLatin1String("clearGlobalHistory")).toBool()) - { - for (int i = 0; i < m_page->history()->count(); ++i) - { - const quint64 historyIdentifier(m_page->history()->itemAt(i).userData().toList().value(IdentifierEntryData).toULongLong()); + SearchEnginePropertiesDialog dialog(searchEngine, SearchEnginesManager::getSearchKeywords(), this); - if (historyIdentifier > 0) - { - HistoryManager::removeEntry(historyIdentifier); - } + if (dialog.exec() == QDialog::Accepted) + { + SearchEnginesManager::addSearchEngine(dialog.getSearchEngine()); } } - setUrl(QUrl(QLatin1String("about:blank"))); - - m_page->history()->clear(); + break; + case ActionsManager::ScrollToStartAction: + m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), 0)); - emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory}); + break; + case ActionsManager::ScrollToEndAction: + m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), m_page->mainFrame()->scrollBarMaximum(Qt::Vertical))); break; - case ActionsManager::PurgeTabHistoryAction: - triggerAction(ActionsManager::ClearTabHistoryAction, {{QLatin1String("clearGlobalHistory"), true}}, trigger); + case ActionsManager::ScrollPageUpAction: + m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), qMax(0, (m_page->mainFrame()->scrollPosition().y() - m_webView->height())))); break; - case ActionsManager::MuteTabMediaAction: - m_isAudioMuted = !m_isAudioMuted; + case ActionsManager::ScrollPageDownAction: + m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), qMin(m_page->mainFrame()->scrollBarMaximum(Qt::Vertical), (m_page->mainFrame()->scrollPosition().y() + m_webView->height())))); - muteAudio(m_page->mainFrame(), m_isAudioMuted); + break; + case ActionsManager::ScrollPageLeftAction: + m_page->mainFrame()->setScrollPosition(QPoint(qMax(0, (m_page->mainFrame()->scrollPosition().x() - m_webView->width())), m_page->mainFrame()->scrollPosition().y())); - emit arbitraryActionsStateChanged({ActionsManager::MuteTabMediaAction}); + break; + case ActionsManager::ScrollPageRightAction: + m_page->mainFrame()->setScrollPosition(QPoint(qMin(m_page->mainFrame()->scrollBarMaximum(Qt::Horizontal), (m_page->mainFrame()->scrollPosition().x() + m_webView->width())), m_page->mainFrame()->scrollPosition().y())); break; - case ActionsManager::OpenLinkAction: - case ActionsManager::OpenLinkInCurrentTabAction: - case ActionsManager::OpenLinkInNewTabAction: - case ActionsManager::OpenLinkInNewTabBackgroundAction: - case ActionsManager::OpenLinkInNewWindowAction: - case ActionsManager::OpenLinkInNewWindowBackgroundAction: - case ActionsManager::OpenLinkInNewPrivateTabAction: - case ActionsManager::OpenLinkInNewPrivateTabBackgroundAction: - case ActionsManager::OpenLinkInNewPrivateWindowAction: - case ActionsManager::OpenLinkInNewPrivateWindowBackgroundAction: + case ActionsManager::TakeScreenshotAction: { - const SessionsManager::OpenHints hints((identifier == ActionsManager::OpenLinkAction) ? SessionsManager::calculateOpenHints(parameters) : mapOpenActionToOpenHints(identifier)); + const QString mode(parameters.value(QLatin1String("mode"), QLatin1String("viewport")).toString()); + const QSize viewportSize(m_page->viewportSize()); + const QSize contentsSize((mode == QLatin1String("viewport")) ? viewportSize : m_page->mainFrame()->contentsSize()); + const QRect rectangle((mode == QLatin1String("area")) ? JsonSettings::readRectangle(parameters.value(QLatin1String("geometry"))) : QRect()); + QPixmap pixmap(rectangle.isValid() ? rectangle.size() : contentsSize); + QPainter painter(&pixmap); - if (hints == SessionsManager::DefaultOpen && !hitResult.flags.testFlag(HitTestResult::IsLinkFromSelectionTest)) + m_page->setViewportSize(contentsSize); + + if (rectangle.isValid()) { - m_page->triggerAction(QWebPage::OpenLink); + painter.translate(-rectangle.topLeft()); - setClickPosition({}); + m_page->mainFrame()->render(&painter, {rectangle}); } - else if (hitResult.linkUrl.isValid()) + else { - openUrl(hitResult.linkUrl, hints); + m_page->mainFrame()->render(&painter); + } + + m_page->setViewportSize(viewportSize); + + const QStringList filters({tr("PNG image (*.png)"), tr("JPEG image (*.jpg *.jpeg)")}); + const SaveInformation result(Utils::getSavePath(suggestSaveFileName(QLatin1String(".png")), {}, filters)); + + if (result.canSave) + { + pixmap.save(result.path, ((filters.indexOf(result.filter) == 0) ? "PNG" : "JPEG")); } } break; - case ActionsManager::CopyLinkToClipboardAction: - if (!hitResult.linkUrl.isEmpty()) + case ActionsManager::ActivateContentAction: { - Application::clipboard()->setText(hitResult.linkUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); + m_webView->setFocus(); + + m_page->mainFrame()->setFocus(); + + const QString tagName(m_page->mainFrame()->findFirstElement(QLatin1String(":focus")).tagName().toLower()); + + if (tagName == QLatin1String("textarea") || tagName == QLatin1String("input")) + { + m_page->mainFrame()->documentElement().evaluateJavaScript(QLatin1String("document.activeElement.blur()")); + } } break; - case ActionsManager::BookmarkLinkAction: - if (hitResult.linkUrl.isValid()) + case ActionsManager::LoadPluginsAction: { - const QString title(hitResult.title); + m_canLoadPlugins = true; - Application::triggerAction(ActionsManager::BookmarkPageAction, {{QLatin1String("url"), hitResult.linkUrl}, {QLatin1String("title"), (title.isEmpty() ? m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element().toPlainText() : title)}}, parentWidget(), trigger); + QList frames({m_page->mainFrame()}); + + while (!frames.isEmpty()) + { + const QWebFrame *frame(frames.takeFirst()); + const QWebElementCollection elements(frame->documentElement().findAll(QLatin1String("object, embed"))); + + for (int i = 0; i < elements.count(); ++i) + { + elements.at(i).replace(elements.at(i).clone()); + } + + frames.append(frame->childFrames()); + } + + m_amountOfDeferredPlugins = 0; + + emit arbitraryActionsStateChanged({ActionsManager::LoadPluginsAction}); } break; - case ActionsManager::SaveLinkToDiskAction: - if (hitResult.linkUrl.isValid()) + case ActionsManager::ViewSourceAction: + if (canViewSource()) { - handleDownloadRequested(QNetworkRequest(hitResult.linkUrl)); + const QString defaultEncoding(m_page->settings()->defaultTextEncoding()); + QNetworkRequest request(getUrl()); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + + QNetworkReply *reply(m_networkManager->get(request)); + SourceViewerWebWidget *sourceViewer(new SourceViewerWebWidget(isPrivate())); + sourceViewer->setRequestedUrl(QUrl(QLatin1String("view-source:") + getUrl().toString()), false); + + if (!defaultEncoding.isEmpty()) + { + sourceViewer->setOption(SettingsManager::Content_DefaultCharacterEncodingOption, defaultEncoding); + } + + m_viewSourceReplies[reply] = sourceViewer; + + connect(reply, &QNetworkReply::finished, this, &QtWebKitWebWidget::handleViewSourceReplyFinished); + + emit requestedNewWindow(sourceViewer, SessionsManager::DefaultOpen, {}); } - else + + break; + case ActionsManager::InspectPageAction: { - m_page->triggerAction(QWebPage::DownloadLinkToDisk); + const bool showInspector(parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool()); + + if (showInspector && !m_inspectorWidget) + { + getInspector(); + } + + emit requestedInspectorVisibilityChange(showInspector); + emit arbitraryActionsStateChanged({ActionsManager::InspectPageAction}); } break; - case ActionsManager::SaveLinkToDownloadsAction: - TransfersManager::addTransfer(TransfersManager::startTransfer(hitResult.linkUrl.toString(), {}, (Transfer::CanNotifyOption | Transfer::CanAskForPathOption | Transfer::IsQuickTransferOption | (isPrivate() ? Transfer::IsPrivateOption : Transfer::NoOption)))); + case ActionsManager::InspectElementAction: + triggerAction(ActionsManager::InspectPageAction, {{QLatin1String("isChecked"), true}}, trigger); - break; - case ActionsManager::OpenFrameAction: - case ActionsManager::OpenFrameInCurrentTabAction: - case ActionsManager::OpenFrameInNewTabAction: - case ActionsManager::OpenFrameInNewTabBackgroundAction: - if (hitResult.frameUrl.isValid()) - { - openUrl(hitResult.frameUrl, ((identifier == ActionsManager::OpenFrameAction) ? SessionsManager::calculateOpenHints(parameters) : mapOpenActionToOpenHints(identifier))); - } + m_page->triggerAction(QWebPage::InspectElement); break; - case ActionsManager::CopyFrameLinkToClipboardAction: - if (hitResult.frameUrl.isValid()) + case ActionsManager::FullScreenAction: { - Application::clipboard()->setText(hitResult.frameUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); + const MainWindow *mainWindow(MainWindow::findMainWindow(this)); + + if (mainWindow && !mainWindow->isFullScreen()) + { + m_page->mainFrame()->evaluateJavaScript(QLatin1String("document.webkitExitFullscreen()")); + } } break; - case ActionsManager::ReloadFrameAction: - if (hitResult.frameUrl.isValid()) + case ActionsManager::WebsitePreferencesAction: { - const QUrl url(hitResult.frameUrl); - QWebFrame *frame(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).frame()); + const QUrl url(getUrl()); + CookieJar *cookieJar(m_networkManager->getCookieJar()); + WebsitePreferencesDialog dialog(Utils::extractHost(url), (url.host().isEmpty() ? QVector() : cookieJar->getCookies(url.host())), this); - if (frame) + if (dialog.exec() == QDialog::Accepted) { - m_networkManager->addContentBlockingException(url, NetworkManager::SubFrameType); + updateOptions(url); - frame->setUrl({}); - frame->setUrl(url); + const QVector cookiesToDelete(dialog.getCookiesToDelete()); + const QVector cookiesToInsert(dialog.getCookiesToInsert()); + + for (int i = 0; i < cookiesToDelete.count(); ++i) + { + cookieJar->forceDeleteCookie(cookiesToDelete.at(i)); + } + + for (int i = 0; i < cookiesToInsert.count(); ++i) + { + cookieJar->forceInsertCookie(cookiesToInsert.at(i)); + } } } break; - case ActionsManager::ViewFrameSourceAction: - if (hitResult.frameUrl.isValid()) - { - const QString defaultEncoding(m_page->settings()->defaultTextEncoding()); - QNetworkRequest request(hitResult.frameUrl); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + default: + break; + } +} - QNetworkReply *reply(m_networkManager->get(request)); - SourceViewerWebWidget *sourceViewer(new SourceViewerWebWidget(isPrivate())); - sourceViewer->setRequestedUrl(QUrl(QLatin1String("view-source:") + hitResult.frameUrl.toString()), false); +void QtWebKitWebWidget::findInPage(const QString &text, FindFlags flags) +{ + QWebPage::FindFlags nativeFlags(QWebPage::FindWrapsAroundDocument | QWebPage::FindBeginsInSelection); - if (!defaultEncoding.isEmpty()) - { - sourceViewer->setOption(SettingsManager::Content_DefaultCharacterEncodingOption, defaultEncoding); - } + if (flags.testFlag(BackwardFind)) + { + nativeFlags |= QWebPage::FindBackward; + } + + if (flags.testFlag(CaseSensitiveFind)) + { + nativeFlags |= QWebPage::FindCaseSensitively; + } + + if (flags.testFlag(HighlightAllFind) || text.isEmpty()) + { + m_page->findText({}, QWebPage::HighlightAllOccurrences); + m_page->findText(text, (nativeFlags | QWebPage::HighlightAllOccurrences)); + } - m_viewSourceReplies[reply] = sourceViewer; + const bool hasMatches(m_page->findText(text, nativeFlags)); - connect(reply, &QNetworkReply::finished, this, &QtWebKitWebWidget::handleViewSourceReplyFinished); + emit findInPageResultsChanged(text, (hasMatches ? -1 : 0), (hasMatches ? -1 : 0)); +} - emit requestedNewWindow(sourceViewer, SessionsManager::DefaultOpen, {}); - } +void QtWebKitWebWidget::search(const QString &query, const QString &searchEngine) +{ + QNetworkRequest request; + QNetworkAccessManager::Operation method; + QByteArray body; - break; - case ActionsManager::OpenImageAction: - case ActionsManager::OpenImageInNewTabAction: - case ActionsManager::OpenImageInNewTabBackgroundAction: - if (hitResult.imageUrl.isValid()) - { - openUrl(hitResult.imageUrl, ((identifier == ActionsManager::OpenImageAction) ? SessionsManager::calculateOpenHints(parameters) : mapOpenActionToOpenHints(identifier))); - } + if (SearchEnginesManager::setupSearchQuery(query, searchEngine, &request, &method, &body)) + { + setRequestedUrl(request.url(), false, true); + updateOptions(request.url()); - break; - case ActionsManager::SaveImageToDiskAction: - if (hitResult.imageUrl.isValid()) - { - handleDownloadRequested(QNetworkRequest(hitResult.imageUrl)); - } + m_page->mainFrame()->load(request, method, body); + } +} - break; - case ActionsManager::CopyImageToClipboardAction: - { - const QPixmap pixmap(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).pixmap()); +void QtWebKitWebWidget::print(QPrinter *printer) +{ + m_page->mainFrame()->print(printer); +} - if (!pixmap.isNull()) - { - Application::clipboard()->setPixmap(pixmap); - } - else - { - m_page->triggerAction(QWebPage::CopyImageToClipboard); - } - } +void QtWebKitWebWidget::saveState(QWebFrame *frame, QWebHistoryItem *item) +{ + if (frame == m_page->mainFrame()) + { + QVariantList state(m_page->history()->currentItem().userData().toList()); - break; - case ActionsManager::CopyImageUrlToClipboardAction: - if (!hitResult.imageUrl.isEmpty()) - { - Application::clipboard()->setText(hitResult.imageUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); - } + if (state.isEmpty() || state.count() < 4) + { + state = {0, getZoom(), m_page->mainFrame()->scrollPosition(), QDateTime::currentDateTimeUtc()}; + } + else + { + state[ZoomEntryData] = getZoom(); + state[PositionEntryData] = m_page->mainFrame()->scrollPosition(); + } - break; - case ActionsManager::ReloadImageAction: - if (!hitResult.imageUrl.isEmpty()) - { - m_networkManager->addContentBlockingException(hitResult.imageUrl, NetworkManager::ImageType); + item->setUserData(state); + } +} - m_page->settings()->setAttribute(QWebSettings::AutoLoadImages, true); +void QtWebKitWebWidget::restoreState(QWebFrame *frame) +{ + if (frame == m_page->mainFrame()) + { + const QVariantList state(m_page->history()->currentItem().userData().toList()); - if (getUrl().matches(hitResult.imageUrl, (QUrl::NormalizePathSegments | QUrl::RemoveFragment | QUrl::StripTrailingSlash))) - { - triggerAction(ActionsManager::ReloadAndBypassCacheAction, {}, trigger); - } - else - { - QWebElement element(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element()); - const QUrl url(hitResult.imageUrl); - const QString src(element.attribute(QLatin1String("src"))); - NetworkCache *cache(NetworkManagerFactory::getCache()); + setZoom(state.value(ZoomEntryData, getZoom()).toInt()); - element.setAttribute(QLatin1String("src"), {}); + if (m_page->mainFrame()->scrollPosition().isNull()) + { + m_page->mainFrame()->setScrollPosition(state.value(PositionEntryData).toPoint()); + } + } +} - if (cache) - { - cache->remove(url); - } +void QtWebKitWebWidget::clearPluginToken() +{ + QList frames({m_page->mainFrame()}); - element.setAttribute(QLatin1String("src"), src); + while (!frames.isEmpty()) + { + const QWebFrame *frame(frames.takeFirst()); + QWebElement element(frame->documentElement().findFirst(QStringLiteral("object[data-otter-browser='%1'], embed[data-otter-browser='%1']").arg(m_pluginToken))); - m_page->mainFrame()->documentElement().evaluateJavaScript(QStringLiteral("var images = document.querySelectorAll('img[src=\"%1\"]'); for (var i = 0; i < images.length; ++i) { images[i].src = ''; images[i].src = '%1'; }").arg(src)); - } - } + if (!element.isNull()) + { + element.removeAttribute(QLatin1String("data-otter-browser")); break; - case ActionsManager::ImagePropertiesAction: - { - QVariantMap properties({{QLatin1String("alternativeText"), hitResult.alternateText}, {QLatin1String("longDescription"), hitResult.longDescription}}); - const QPixmap pixmap(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).pixmap()); + } - if (!pixmap.isNull()) - { - properties[QLatin1String("width")] = pixmap.width(); - properties[QLatin1String("height")] = pixmap.height(); - properties[QLatin1String("depth")] = pixmap.depth(); - } + frames.append(frame->childFrames()); + } - ImagePropertiesDialog *imagePropertiesDialog(new ImagePropertiesDialog(hitResult.imageUrl, properties, (m_networkManager->cache() ? m_networkManager->cache()->data(hitResult.imageUrl) : nullptr), this)); - imagePropertiesDialog->setButtonsVisible(false); + emit arbitraryActionsStateChanged({ActionsManager::LoadPluginsAction}); - ContentsDialog *dialog(new ContentsDialog(ThemesManager::createIcon(QLatin1String("dialog-information")), imagePropertiesDialog->windowTitle(), {}, {}, QDialogButtonBox::Close, imagePropertiesDialog, this)); + m_pluginToken.clear(); +} - connect(this, &QtWebKitWebWidget::aboutToReload, dialog, &ContentsDialog::close); - connect(imagePropertiesDialog, &ImagePropertiesDialog::finished, dialog, &ContentsDialog::close); +void QtWebKitWebWidget::resetSpellCheck(QWebElement element) +{ + if (element.isNull()) + { + element = m_page->mainFrame()->findFirstElement(QLatin1String("*:focus")); + } - showDialog(dialog, false); - } + if (!element.isNull()) + { + m_page->runScript(QLatin1String("resetSpellCheck"), element); + } +} - break; - case ActionsManager::SaveMediaToDiskAction: - if (hitResult.mediaUrl.isValid()) - { - handleDownloadRequested(QNetworkRequest(hitResult.mediaUrl)); - } +void QtWebKitWebWidget::muteAudio(QWebFrame *frame, bool isMuted) +{ + if (!frame) + { + return; + } - break; - case ActionsManager::CopyMediaUrlToClipboardAction: - if (!hitResult.mediaUrl.isEmpty()) - { - Application::clipboard()->setText(hitResult.mediaUrl.toString(QUrl::EncodeReserved | QUrl::EncodeSpaces)); - } + const QString script(QLatin1String("this.muted = ") + (isMuted ? QLatin1String("true") : QLatin1String("false"))); + const QWebElementCollection elements(frame->findAllElements(QLatin1String("audio, video"))); - break; - case ActionsManager::MediaControlsAction: - m_page->triggerAction(QWebPage::ToggleMediaControls, parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool()); + for (int i = 0; i < elements.count(); ++i) + { + elements.at(i).evaluateJavaScript(script); + } - break; - case ActionsManager::MediaLoopAction: - m_page->triggerAction(QWebPage::ToggleMediaLoop, parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool()); + const QList frames(frame->childFrames()); - break; - case ActionsManager::MediaPlayPauseAction: - m_page->triggerAction(QWebPage::ToggleMediaPlayPause); + for (int i = 0; i < frames.count(); ++i) + { + muteAudio(frames.at(i), isMuted); + } +} - break; - case ActionsManager::MediaMuteAction: - m_page->triggerAction(QWebPage::ToggleMediaMute); +void QtWebKitWebWidget::openRequest(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, QIODevice *outgoingData) +{ + m_formRequest = request; + m_formRequestOperation = operation; + m_formRequestBody = (outgoingData ? outgoingData->readAll() : QByteArray()); - break; - case ActionsManager::MediaPlaybackRateAction: - m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element().evaluateJavaScript(QStringLiteral("this.playbackRate = %1").arg(parameters.value(QLatin1String("rate"), 1).toReal())); + if (outgoingData) + { + outgoingData->close(); + outgoingData->deleteLater(); + } - break; - case ActionsManager::GoBackAction: - m_page->triggerAction(QWebPage::Back); + setRequestedUrl(m_formRequest.url(), false, true); + updateOptions(m_formRequest.url()); - break; - case ActionsManager::GoForwardAction: - m_page->triggerAction(QWebPage::Forward); + QTimer::singleShot(50, this, [&]() + { + m_page->mainFrame()->load(m_formRequest, m_formRequestOperation, m_formRequestBody); - break; - case ActionsManager::GoToHistoryIndexAction: - if (parameters.contains(QLatin1String("index"))) - { - const int index(parameters[QLatin1String("index")].toInt()); + m_formRequest = QNetworkRequest(); + m_formRequestBody.clear(); + }); +} - if (index >= 0 && index < m_page->history()->count()) - { - m_page->history()->goToItem(m_page->history()->itemAt(index)); - } - } +void QtWebKitWebWidget::openFormRequest(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, QIODevice *outgoingData) +{ + m_page->triggerAction(QWebPage::Stop); - break; - case ActionsManager::RewindAction: - m_page->history()->goToItem(m_page->history()->itemAt(0)); + QtWebKitWebWidget *widget(qobject_cast(clone(false))); + widget->openRequest(request, operation, outgoingData); - break; - case ActionsManager::FastForwardAction: - { - const QUrl url(m_page->mainFrame()->evaluateJavaScript(getFastForwardScript(true)).toUrl()); + emit requestedNewWindow(widget, SessionsManager::calculateOpenHints(SessionsManager::NewTabOpen), {}); +} - if (url.isValid()) - { - setUrl(url); - } - else if (canGoForward()) - { - m_page->triggerAction(QWebPage::Forward); - } - } +void QtWebKitWebWidget::startDelayedTransfer(Transfer *transfer) +{ + m_transfers.enqueue(transfer); - break; - case ActionsManager::RemoveHistoryIndexAction: - if (parameters.contains(QLatin1String("index"))) - { - const int index(parameters[QLatin1String("index")].toInt()); + if (m_transfersTimer == 0) + { + m_transfersTimer = startTimer(250); + } +} - if (index >= 0 && index < m_page->history()->count()) - { - if (parameters.value(QLatin1String("clearGlobalHistory"), false).toBool()) - { - const quint64 entryIdentifier(m_page->history()->itemAt(index).userData().toList().value(IdentifierEntryData).toULongLong()); +void QtWebKitWebWidget::handleDownloadRequested(const QNetworkRequest &request) +{ + const HitTestResult hitResult(getCurrentHitTestResult()); - if (entryIdentifier > 0) - { - HistoryManager::removeEntry(entryIdentifier); - } - } + if ((!hitResult.imageUrl.isEmpty() && request.url() == hitResult.imageUrl) || (!hitResult.mediaUrl.isEmpty() && request.url() == hitResult.mediaUrl)) + { + NetworkCache *cache(NetworkManagerFactory::getCache()); - Session::Window::History history(getHistory()); - history.entries.removeAt(index); + if (cache && cache->metaData(request.url()).isValid()) + { + QIODevice *device(cache->data(request.url())); - if (history.index >= index) - { - history.index = (history.index - 1); - } + if (device && device->size() > 0) + { + const QString path(Utils::getSavePath(request.url().fileName()).path); - setHistory(history); + if (path.isEmpty()) + { + device->deleteLater(); + + return; } - } - break; - case ActionsManager::StopAction: - m_page->triggerAction(QWebPage::Stop); + QFile file(path); - break; - case ActionsManager::StopScheduledReloadAction: - m_page->triggerAction(QWebPage::StopScheduledPageRefresh); + if (!file.open(QIODevice::WriteOnly)) + { + QMessageBox::critical(this, tr("Error"), tr("Failed to open file for writing."), QMessageBox::Close); + } - break; - case ActionsManager::ReloadAction: - emit aboutToReload(); + file.write(device->readAll()); + file.close(); - m_page->triggerAction(QWebPage::Stop); - m_page->triggerAction(QWebPage::Reload); + device->deleteLater(); - break; - case ActionsManager::ReloadOrStopAction: - if (m_loadingState == OngoingLoadingState) - { - triggerAction(ActionsManager::StopAction, {}, trigger); + return; } - else + + if (device) { - triggerAction(ActionsManager::ReloadAction, {}, trigger); + device->deleteLater(); } + } + else if (!hitResult.imageUrl.isEmpty() && hitResult.imageUrl.scheme() == QLatin1String("data") && hitResult.imageUrl.url().contains(QLatin1String(";base64,"))) + { + const QString imageUrl(hitResult.imageUrl.url()); + const QString imageType(imageUrl.mid(11, (imageUrl.indexOf(QLatin1Char(';')) - 11))); + const QString path(Utils::getSavePath(tr("file") + QLatin1Char('.') + imageType).path); - break; - case ActionsManager::ReloadAndBypassCacheAction: - m_page->triggerAction(QWebPage::ReloadAndBypassCache); - - break; - case ActionsManager::ContextMenuAction: - if (parameters.contains(QLatin1String("context")) && parameters[QLatin1String("context")].toInt() == QContextMenuEvent::Keyboard) + if (!path.isEmpty()) { - const QWebElement element(m_page->mainFrame()->findFirstElement(QLatin1String(":focus"))); + QImageWriter writer(path); - if (element.isNull()) + if (!writer.write(QImage::fromData(QByteArray::fromBase64(imageUrl.mid(imageUrl.indexOf(QLatin1String(";base64,")) + 7).toUtf8()), imageType.toStdString().c_str()))) { - setClickPosition(m_webView->mapFromGlobal(QCursor::pos())); + Console::addMessage(tr("Failed to save image: %1").arg(writer.errorString()), Console::OtherCategory, Console::ErrorLevel, path, -1, getWindowIdentifier()); } - else - { - QPoint clickPosition(element.geometry().center()); - QWebFrame *frame(element.webFrame()); + } - while (frame) - { - clickPosition -= frame->scrollPosition(); + return; + } - frame = frame->parentFrame(); - } + QNetworkRequest mutableRequest(request); + mutableRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - setClickPosition(clickPosition); - } - } - else - { - setClickPosition(m_webView->mapFromGlobal(QCursor::pos())); - } + TransfersManager::startTransfer(m_networkManager->get(mutableRequest), {}, (Transfer::CanAskForPathOption | Transfer::CanAutoDeleteOption | Transfer::IsPrivateOption)); + } + else + { + startDelayedTransfer(TransfersManager::startTransfer(request, {}, (Transfer::CanNotifyOption | (isPrivate() ? Transfer::IsPrivateOption : Transfer::NoOption)))); + } +} - showContextMenu(getClickPosition()); +void QtWebKitWebWidget::handleUnsupportedContent(QNetworkReply *reply) +{ + m_networkManager->registerTransfer(reply); - break; - case ActionsManager::UndoAction: - m_page->triggerAction(QWebPage::Undo); + startDelayedTransfer(TransfersManager::startTransfer(reply, {}, (Transfer::CanNotifyOption | (isPrivate() ? Transfer::IsPrivateOption : Transfer::NoOption)))); +} - break; - case ActionsManager::RedoAction: - m_page->triggerAction(QWebPage::Redo); +void QtWebKitWebWidget::handleOptionChanged(int identifier, const QVariant &value) +{ + switch (identifier) + { + case SettingsManager::Content_BackgroundColorOption: + { + QPalette palette(m_page->palette()); + palette.setColor(QPalette::Base, QColor(value.toString())); + + m_page->setPalette(palette); + } break; - case ActionsManager::CutAction: - m_page->triggerAction(QWebPage::Cut); + case SettingsManager::History_BrowsingLimitAmountWindowOption: + m_page->history()->setMaximumItemCount(value.toInt()); break; - case ActionsManager::CopyAction: - if (parameters.value(QLatin1String("mode")) == QLatin1String("plainText")) - { - const QString text(getSelectedText()); + case SettingsManager::Permissions_ScriptsCanShowStatusMessagesOption: + disconnect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); - if (!text.isEmpty()) - { - Application::clipboard()->setText(text); - } + if (value.toBool() || SettingsManager::getOption(identifier, Utils::extractHost(getUrl())).toBool()) + { + connect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); } else { - m_page->triggerAction(QWebPage::Copy); + setStatusMessage({}); } break; - case ActionsManager::CopyPlainTextAction: - triggerAction(ActionsManager::CopyAction, {{QLatin1String("mode"), QLatin1String("plainText")}}, trigger); - + default: break; - case ActionsManager::CopyAddressAction: - Application::clipboard()->setText(getUrl().toString()); + } +} - break; - case ActionsManager::CopyToNoteAction: - NotesManager::addNote(BookmarksModel::UrlBookmark, {{BookmarksModel::UrlRole, getUrl()}, {BookmarksModel::DescriptionRole, getSelectedText()}}); +void QtWebKitWebWidget::handleLoadStarted() +{ + if (m_loadingState == OngoingLoadingState) + { + return; + } - break; - case ActionsManager::PasteAction: - if (parameters.contains(QLatin1String("note"))) - { - const BookmarksModel::Bookmark *bookmark(NotesManager::getModel()->getBookmark(parameters[QLatin1String("note")].toULongLong())); + m_thumbnail = {}; + m_messageToken = QUuid::createUuid().toString(); + m_canLoadPlugins = (getOption(SettingsManager::Permissions_EnablePluginsOption, getUrl()).toString() == QLatin1String("enabled")); + m_loadingState = OngoingLoadingState; - if (bookmark) - { - triggerAction(ActionsManager::PasteAction, {{QLatin1String("text"), bookmark->getDescription()}}, trigger); - } - } - else if (parameters.contains(QLatin1String("text"))) - { - QMimeData *mimeData(new QMimeData()); - const QStringList mimeTypes(Application::clipboard()->mimeData()->formats()); + setStatusMessage({}); + setStatusMessageOverride({}); - for (int i = 0; i < mimeTypes.count(); ++i) - { - mimeData->setData(mimeTypes.at(i), Application::clipboard()->mimeData()->data(mimeTypes.at(i))); - } + emit geometryChanged(); + emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory}); + emit loadingStateChanged(OngoingLoadingState); +} - Application::clipboard()->setText(parameters[QLatin1String("text")].toString()); +void QtWebKitWebWidget::handleLoadProgress(int progress) +{ + m_networkManager->setPageInformation(TotalLoadingProgressInformation, progress); +} - m_page->triggerAction(QWebPage::Paste); +void QtWebKitWebWidget::handleLoadFinished(bool result) +{ + if (m_isAudioMuted) + { + muteAudio(m_page->mainFrame(), true); + } - Application::clipboard()->setMimeData(mimeData); - } - else - { - m_page->triggerAction(QWebPage::Paste); - } + if (m_loadingState != OngoingLoadingState) + { + return; + } - break; - case ActionsManager::DeleteAction: - m_page->triggerAction(QWebPage::DeleteEndOfWord); + m_networkManager->handleLoadFinished(result); - break; - case ActionsManager::SelectAllAction: - m_page->triggerAction(QWebPage::SelectAll); + m_thumbnail = {}; + m_loadingState = FinishedLoadingState; - break; - case ActionsManager::UnselectAction: - m_page->triggerAction(QWebPage::Unselect); + updateAmountOfDeferredPlugins(); + handleHistory(); + startReloadTimer(); + + emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory}); + emit contentStateChanged(getContentState()); + emit loadingStateChanged(FinishedLoadingState); + emit watchedDataChanged(FeedsWatcher); + emit watchedDataChanged(LinksWatcher); + emit watchedDataChanged(MetaDataWatcher); + emit watchedDataChanged(SearchEnginesWatcher); + emit watchedDataChanged(StylesheetsWatcher); +} - break; - case ActionsManager::ClearAllAction: - m_page->triggerAction(QWebPage::SelectAll); - m_page->triggerAction(QWebPage::DeleteEndOfWord); +void QtWebKitWebWidget::handleViewSourceReplyFinished() +{ + QNetworkReply *reply(qobject_cast(sender())); - break; - case ActionsManager::CheckSpellingAction: - { - QWebElement element(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element()); - element.evaluateJavaScript(QStringLiteral("this.spellcheck = %1").arg(parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool() ? QLatin1String("true") : QLatin1String("false"))); + if (reply) + { + if (reply->error() == QNetworkReply::NoError && m_viewSourceReplies.contains(reply) && m_viewSourceReplies[reply]) + { + m_viewSourceReplies[reply]->setContents(reply->readAll(), reply->header(QNetworkRequest::ContentTypeHeader).toString()); + } - if (parameters.contains(QLatin1String("dictionary"))) - { - setOption(SettingsManager::Browser_SpellCheckDictionaryOption, parameters.value(QLatin1String("dictionary"))); - } - else - { - resetSpellCheck(element); - } + m_viewSourceReplies.remove(reply); - emit arbitraryActionsStateChanged({ActionsManager::CheckSpellingAction}); - } + reply->deleteLater(); + } +} - break; - case ActionsManager::CreateSearchAction: - { - const QWebElement element(m_page->mainFrame()->hitTestContent(hitResult.hitPosition).element()); - QWebElement parentElement(element.parent()); +void QtWebKitWebWidget::handlePrintRequest(QWebFrame *frame) +{ + QPrintPreviewDialog printPreviewDialog(this); + printPreviewDialog.setWindowFlags(printPreviewDialog.windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint); + printPreviewDialog.setWindowTitle(tr("Print Preview")); - while (!parentElement.isNull() && parentElement.tagName().toLower() != QLatin1String("form")) - { - parentElement = parentElement.parent(); - } + if (Application::getActiveWindow()) + { + printPreviewDialog.resize(Application::getActiveWindow()->size()); + } - if (!parentElement.hasAttribute(QLatin1String("action"))) - { - break; - } + connect(&printPreviewDialog, &QPrintPreviewDialog::paintRequested, frame, &QWebFrame::print); - QList inputElements(parentElement.findAll(QLatin1String("button:not([disabled])[name][type='submit'], input:not([disabled])[name], select:not([disabled])[name], textarea:not([disabled])[name]")).toList()); + printPreviewDialog.exec(); +} - if (inputElements.isEmpty()) - { - break; - } +void QtWebKitWebWidget::handleHistory() +{ + if (isPrivate() || m_page->history()->count() == 0) + { + return; + } - QWebElement searchTermsElement; - const QString tagName(element.tagName().toLower()); - const QUrl url(parentElement.attribute(QLatin1String("action"))); - const QIcon icon(m_page->mainFrame()->icon()); - SearchEnginesManager::SearchEngineDefinition searchEngine; - searchEngine.title = getTitle(); - searchEngine.formUrl = getUrl(); - searchEngine.icon = (icon.isNull() ? ThemesManager::createIcon(QLatin1String("edit-find")) : icon); - searchEngine.resultsUrl.url = (url.isEmpty() ? getUrl() : resolveUrl(parentElement.webFrame(), url)).toString(); - searchEngine.resultsUrl.enctype = parentElement.attribute(QLatin1String("enctype")); - searchEngine.resultsUrl.method = ((parentElement.attribute(QLatin1String("method"), QLatin1String("get")).toLower() == QLatin1String("post")) ? QLatin1String("post") : QLatin1String("get")); + const QUrl url(m_page->history()->currentItem().url()); + const QVariant state(m_page->history()->currentItem().userData()); - if (tagName != QLatin1String("select")) - { - const QString type(element.attribute(QLatin1String("type"))); + if (state.isValid()) + { + const quint64 identifier(state.toList().value(IdentifierEntryData).toULongLong()); - if (!inputElements.contains(element) && (type == QLatin1String("image") || type == QLatin1String("submit"))) - { - inputElements.append(element); - } + if (identifier > 0) + { + HistoryManager::updateEntry(identifier, url, getTitle(), m_page->mainFrame()->icon()); + } + } + else + { + m_page->history()->currentItem().setUserData(QVariantList({(Utils::isUrlEmpty(url) ? 0 : HistoryManager::addEntry(url, getTitle(), m_page->mainFrame()->icon(), m_isTypedIn)), getZoom(), QPoint(0, 0), QDateTime::currentDateTimeUtc()})); - if (tagName == QLatin1String("textarea") || type == QLatin1String("email") || type == QLatin1String("password") || type == QLatin1String("search") || type == QLatin1String("tel") || type == QLatin1String("text") || type == QLatin1String("url")) - { - searchTermsElement = element; - } - } + if (m_isTypedIn) + { + m_isTypedIn = false; + } - if (searchTermsElement.isNull()) - { - searchTermsElement = parentElement.findFirst(QLatin1String("input:not([disabled])[name][type='search']")); - } + SessionsManager::markSessionAsModified(); + BookmarksManager::updateVisits(url.toString()); + } +} - for (int i = 0; i < inputElements.count(); ++i) - { - const QString name(inputElements.at(i).attribute(QLatin1String("name"))); +void QtWebKitWebWidget::handleNavigationRequest(const QUrl &url, QWebPage::NavigationType type) +{ + if (type != QWebPage::NavigationTypeBackOrForward && (type != QWebPage::NavigationTypeLinkClicked || !getUrl().matches(url, QUrl::RemoveFragment))) + { + handleLoadStarted(); + handleHistory(); - if (inputElements.at(i).tagName().toLower() != QLatin1String("select")) - { - const QString type(inputElements.at(i).attribute(QLatin1String("type"))); - const bool isSubmit(type == QLatin1String("image") || type == QLatin1String("submit")); + m_networkManager->resetStatistics(); + } - if ((isSubmit && inputElements.at(i) != element) || ((type == QLatin1String("checkbox") || type == QLatin1String("radio")) && !inputElements[i].evaluateJavaScript(QLatin1String("this.checked")).toBool())) - { - continue; - } + updateOptions(url); - if (isSubmit && inputElements.at(i) == element) - { - if (inputElements.at(i).hasAttribute(QLatin1String("formaction"))) - { - searchEngine.resultsUrl.url = resolveUrl(parentElement.webFrame(), inputElements.at(i).attribute(QLatin1String("formaction"))).toString(); - } + m_isNavigating = true; - if (inputElements.at(i).hasAttribute(QLatin1String("formenctype"))) - { - searchEngine.resultsUrl.enctype = inputElements.at(i).attribute(QLatin1String("formenctype")); - } + emit aboutToNavigate(); +} - if (inputElements.at(i).hasAttribute(QLatin1String("formmethod"))) - { - searchEngine.resultsUrl.method = inputElements.at(i).attribute(QLatin1String("formmethod")); - } - } +void QtWebKitWebWidget::handleFullScreenRequest(QWebFullScreenRequest request) +{ + request.accept(); - if (!isSubmit && searchTermsElement.isNull() && type != QLatin1String("hidden")) - { - searchTermsElement = inputElements.at(i); - } + if (request.toggleOn()) + { + const QString value(SettingsManager::getOption(SettingsManager::Permissions_EnableFullScreenOption, Utils::extractHost(request.origin())).toString()); - if (!name.isEmpty()) - { - searchEngine.resultsUrl.parameters.addQueryItem(name, ((inputElements.at(i) == searchTermsElement) ? QLatin1String("{searchTerms}") : inputElements[i].evaluateJavaScript((inputElements.at(i).tagName().toLower() == QLatin1String("button")) ? QLatin1String("this.innerHTML") : QLatin1String("this.value")).toString())); - } - } - else if (!name.isEmpty()) - { - const QWebElementCollection optionElements(inputElements.at(i).findAll(QLatin1String("option:checked"))); + if (value == QLatin1String("allow")) + { + MainWindow *mainWindow(MainWindow::findMainWindow(this)); - for (int j = 0; j < optionElements.count(); ++j) - { - searchEngine.resultsUrl.parameters.addQueryItem(name, optionElements.at(j).evaluateJavaScript(QLatin1String("this.value")).toString()); - } - } - } + if (mainWindow && !mainWindow->isFullScreen()) + { + mainWindow->triggerAction(ActionsManager::FullScreenAction); + } + } + else if (value == QLatin1String("ask")) + { + emit requestedPermission(FullScreenFeature, request.origin(), false); + } + } + else + { + MainWindow *mainWindow(MainWindow::findMainWindow(this)); - SearchEnginePropertiesDialog dialog(searchEngine, SearchEnginesManager::getSearchKeywords(), this); + if (mainWindow && mainWindow->isFullScreen()) + { + mainWindow->triggerAction(ActionsManager::FullScreenAction); + } - if (dialog.exec() == QDialog::Accepted) - { - SearchEnginesManager::addSearchEngine(dialog.getSearchEngine()); - } - } + emit requestedPermission(FullScreenFeature, request.origin(), true); + } - break; - case ActionsManager::ScrollToStartAction: - m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), 0)); + m_isFullScreen = request.toggleOn(); - break; - case ActionsManager::ScrollToEndAction: - m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), m_page->mainFrame()->scrollBarMaximum(Qt::Vertical))); + emit isFullScreenChanged(m_isFullScreen); +} - break; - case ActionsManager::ScrollPageUpAction: - m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), qMax(0, (m_page->mainFrame()->scrollPosition().y() - m_webView->height())))); +void QtWebKitWebWidget::handlePermissionRequest(QWebFrame *frame, QWebPage::Feature feature) +{ + notifyPermissionRequested(frame, feature, false); +} - break; - case ActionsManager::ScrollPageDownAction: - m_page->mainFrame()->setScrollPosition(QPoint(m_page->mainFrame()->scrollPosition().x(), qMin(m_page->mainFrame()->scrollBarMaximum(Qt::Vertical), (m_page->mainFrame()->scrollPosition().y() + m_webView->height())))); +void QtWebKitWebWidget::handlePermissionCancel(QWebFrame *frame, QWebPage::Feature feature) +{ + notifyPermissionRequested(frame, feature, true); +} - break; - case ActionsManager::ScrollPageLeftAction: - m_page->mainFrame()->setScrollPosition(QPoint(qMax(0, (m_page->mainFrame()->scrollPosition().x() - m_webView->width())), m_page->mainFrame()->scrollPosition().y())); +void QtWebKitWebWidget::notifyTitleChanged() +{ + emit titleChanged(getTitle()); - break; - case ActionsManager::ScrollPageRightAction: - m_page->mainFrame()->setScrollPosition(QPoint(qMin(m_page->mainFrame()->scrollBarMaximum(Qt::Horizontal), (m_page->mainFrame()->scrollPosition().x() + m_webView->width())), m_page->mainFrame()->scrollPosition().y())); + handleHistory(); +} - break; - case ActionsManager::TakeScreenshotAction: - { - const QString mode(parameters.value(QLatin1String("mode"), QLatin1String("viewport")).toString()); - const QSize viewportSize(m_page->viewportSize()); - const QSize contentsSize((mode == QLatin1String("viewport")) ? viewportSize : m_page->mainFrame()->contentsSize()); - const QRect rectangle((mode == QLatin1String("area")) ? JsonSettings::readRectangle(parameters.value(QLatin1String("geometry"))) : QRect()); - QPixmap pixmap(rectangle.isValid() ? rectangle.size() : contentsSize); - QPainter painter(&pixmap); +void QtWebKitWebWidget::notifyUrlChanged(const QUrl &url) +{ + m_isNavigating = false; - m_page->setViewportSize(contentsSize); + updateOptions(url); - if (rectangle.isValid()) - { - painter.translate(-rectangle.topLeft()); + emit urlChanged(url); + emit arbitraryActionsStateChanged({ActionsManager::InspectPageAction, ActionsManager::InspectElementAction}); + emit categorizedActionsStateChanged({ActionsManager::ActionDefinition::NavigationCategory, ActionsManager::ActionDefinition::PageCategory}); - m_page->mainFrame()->render(&painter, {rectangle}); - } - else - { - m_page->mainFrame()->render(&painter); - } + SessionsManager::markSessionAsModified(); +} - m_page->setViewportSize(viewportSize); +void QtWebKitWebWidget::notifyIconChanged() +{ + emit iconChanged(getIcon()); +} - const QStringList filters({tr("PNG image (*.png)"), tr("JPEG image (*.jpg *.jpeg)")}); - const SaveInformation result(Utils::getSavePath(suggestSaveFileName(QLatin1String(".png")), {}, filters)); +void QtWebKitWebWidget::notifyPermissionRequested(QWebFrame *frame, QWebPage::Feature nativeFeature, bool cancel) +{ + FeaturePermission feature(UnknownFeature); - if (result.canSave) - { - pixmap.save(result.path, ((filters.indexOf(result.filter) == 0) ? "PNG" : "JPEG")); - } - } + switch (nativeFeature) + { + case QWebPage::Geolocation: + feature = GeolocationFeature; break; - case ActionsManager::ActivateContentAction: - { - m_webView->setFocus(); + case QWebPage::Notifications: + feature = NotificationsFeature; - m_page->mainFrame()->setFocus(); + break; + default: + return; + } - const QString tagName(m_page->mainFrame()->findFirstElement(QLatin1String(":focus")).tagName().toLower()); + const QUrl url(frame->url().isValid() ? frame->url() : frame->requestedUrl()); - if (tagName == QLatin1String("textarea") || tagName == QLatin1String("input")) - { - m_page->mainFrame()->documentElement().evaluateJavaScript(QLatin1String("document.activeElement.blur()")); - } - } + if (cancel) + { + emit requestedPermission(feature, url, true); + } + else + { + switch (getPermission(feature, url)) + { + case GrantedPermission: + m_page->setFeaturePermission(frame, nativeFeature, QWebPage::PermissionGrantedByUser); - break; - case ActionsManager::LoadPluginsAction: - { - m_canLoadPlugins = true; + break; + case DeniedPermission: + m_page->setFeaturePermission(frame, nativeFeature, QWebPage::PermissionDeniedByUser); - QList frames({m_page->mainFrame()}); + break; + default: + emit requestedPermission(feature, url, false); - while (!frames.isEmpty()) - { - const QWebFrame *frame(frames.takeFirst()); - const QWebElementCollection elements(frame->documentElement().findAll(QLatin1String("object, embed"))); + break; + } + } +} - for (int i = 0; i < elements.count(); ++i) - { - elements.at(i).replace(elements.at(i).clone()); - } +void QtWebKitWebWidget::notifySavePasswordRequested(const PasswordsManager::PasswordInformation &password, bool isUpdate) +{ + emit requestedSavePassword(password, isUpdate); +} - frames.append(frame->childFrames()); - } +void QtWebKitWebWidget::updateAmountOfDeferredPlugins() +{ + const int amountOfDeferredPlugins(m_canLoadPlugins ? 0 : findChildren().count()); - m_amountOfDeferredPlugins = 0; + if (amountOfDeferredPlugins != m_amountOfDeferredPlugins) + { + const bool needsActionUpdate(amountOfDeferredPlugins == 0 || m_amountOfDeferredPlugins == 0); - emit arbitraryActionsStateChanged({ActionsManager::LoadPluginsAction}); - } + m_amountOfDeferredPlugins = amountOfDeferredPlugins; - break; - case ActionsManager::ViewSourceAction: - if (canViewSource()) - { - const QString defaultEncoding(m_page->settings()->defaultTextEncoding()); - QNetworkRequest request(getUrl()); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + if (needsActionUpdate) + { + emit arbitraryActionsStateChanged({ActionsManager::LoadPluginsAction}); + } + } +} - QNetworkReply *reply(m_networkManager->get(request)); - SourceViewerWebWidget *sourceViewer(new SourceViewerWebWidget(isPrivate())); - sourceViewer->setRequestedUrl(QUrl(QLatin1String("view-source:") + getUrl().toString()), false); +void QtWebKitWebWidget::updateOptions(const QUrl &url) +{ + const QString encoding(getOption(SettingsManager::Content_DefaultCharacterEncodingOption, url).toString()); + const bool arePluginsEnabled(getOption(SettingsManager::Permissions_EnablePluginsOption, url).toString() != QLatin1String("disabled")); + QWebSettings *settings(m_page->settings()); + settings->setAttribute(QWebSettings::AutoLoadImages, (getOption(SettingsManager::Permissions_EnableImagesOption, url).toString() != QLatin1String("onlyCached"))); + settings->setAttribute(QWebSettings::DnsPrefetchEnabled, getOption(SettingsManager::Network_EnableDnsPrefetchOption, url).toBool()); + settings->setAttribute(QWebSettings::PluginsEnabled, arePluginsEnabled); + settings->setAttribute(QWebSettings::JavaEnabled, arePluginsEnabled); + settings->setAttribute(QWebSettings::JavascriptEnabled, (m_page->isDisplayingErrorPage() || m_page->isViewingMedia() || getOption(SettingsManager::Permissions_EnableJavaScriptOption, url).toBool())); + settings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, getOption(SettingsManager::Permissions_ScriptsCanAccessClipboardOption, url).toBool()); + settings->setAttribute(QWebSettings::JavascriptCanOpenWindows, (getOption(SettingsManager::Permissions_ScriptsCanOpenWindowsOption, url).toString() != QLatin1String("blockAll"))); + settings->setAttribute(QWebSettings::WebGLEnabled, getOption(SettingsManager::Permissions_EnableWebglOption, url).toBool()); + settings->setAttribute(QWebSettings::LocalStorageEnabled, getOption(SettingsManager::Permissions_EnableLocalStorageOption, url).toBool()); + settings->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, getOption(SettingsManager::Permissions_EnableOfflineStorageDatabaseOption, url).toBool()); + settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, getOption(SettingsManager::Permissions_EnableOfflineWebApplicationCacheOption, url).toBool()); + settings->setAttribute(QWebSettings::AllowRunningInsecureContent, getOption(SettingsManager::Security_AllowMixedContentOption, url).toBool()); + settings->setAttribute(QWebSettings::MediaEnabled, getOption(QtWebKitWebBackend::getOptionIdentifier(QtWebKitWebBackend::QtWebKitBackend_EnableMediaOption), url).toBool()); + settings->setAttribute(QWebSettings::MediaSourceEnabled, getOption(QtWebKitWebBackend::getOptionIdentifier(QtWebKitWebBackend::QtWebKitBackend_EnableMediaSourceOption), url).toBool()); + settings->setAttribute(QWebSettings::WebSecurityEnabled, getOption(QtWebKitWebBackend::getOptionIdentifier(QtWebKitWebBackend::QtWebKitBackend_EnableWebSecurityOption), url).toBool()); + settings->setDefaultTextEncoding((encoding == QLatin1String("auto")) ? QString() : encoding); - if (!defaultEncoding.isEmpty()) - { - sourceViewer->setOption(SettingsManager::Content_DefaultCharacterEncodingOption, defaultEncoding); - } + disconnect(m_page, &QtWebKitPage::geometryChangeRequested, this, &QtWebKitWebWidget::requestedGeometryChange); + disconnect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); - m_viewSourceReplies[reply] = sourceViewer; + if (getOption(SettingsManager::Permissions_ScriptsCanChangeWindowGeometryOption, url).toBool()) + { + connect(m_page, &QtWebKitPage::geometryChangeRequested, this, &QtWebKitWebWidget::requestedGeometryChange); + } - connect(reply, &QNetworkReply::finished, this, &QtWebKitWebWidget::handleViewSourceReplyFinished); + if (getOption(SettingsManager::Permissions_ScriptsCanShowStatusMessagesOption, url).toBool()) + { + connect(m_page, &QtWebKitPage::statusBarMessage, this, &QtWebKitWebWidget::setStatusMessage); + } + else + { + setStatusMessage({}); + } - emit requestedNewWindow(sourceViewer, SessionsManager::DefaultOpen, {}); - } + m_page->updateStyleSheets(url); - break; - case ActionsManager::InspectPageAction: - { - const bool showInspector(parameters.value(QLatin1String("isChecked"), !getActionState(identifier, parameters).isChecked).toBool()); + m_networkManager->updateOptions(url); - if (showInspector && !m_inspector) - { - getInspector(); - } + m_canLoadPlugins = (getOption(SettingsManager::Permissions_EnablePluginsOption, url).toString() == QLatin1String("enabled")); +} - emit requestedInspectorVisibilityChange(showInspector); - emit arbitraryActionsStateChanged({ActionsManager::InspectPageAction}); - } +void QtWebKitWebWidget::clearOptions() +{ + WebWidget::clearOptions(); - break; - case ActionsManager::InspectElementAction: - triggerAction(ActionsManager::InspectPageAction, {{QLatin1String("isChecked"), true}}, trigger); + updateOptions(getUrl()); +} - m_page->triggerAction(QWebPage::InspectElement); +void QtWebKitWebWidget::fillPassword(const PasswordsManager::PasswordInformation &password) +{ + QFile file(QLatin1String(":/modules/backends/web/qtwebkit/resources/formFiller.js")); - break; - case ActionsManager::FullScreenAction: - { - const MainWindow *mainWindow(MainWindow::findMainWindow(this)); + if (!file.open(QIODevice::ReadOnly)) + { + return; + } - if (mainWindow && !mainWindow->isFullScreen()) - { - m_page->mainFrame()->evaluateJavaScript(QLatin1String("document.webkitExitFullscreen()")); - } - } + QJsonArray fieldsArray; - break; - case ActionsManager::WebsitePreferencesAction: - { - const QUrl url(getUrl()); - CookieJar *cookieJar(m_networkManager->getCookieJar()); - WebsitePreferencesDialog dialog(Utils::extractHost(url), (url.host().isEmpty() ? QVector() : cookieJar->getCookies(url.host())), this); + for (int i = 0; i < password.fields.count(); ++i) + { + fieldsArray.append(QJsonObject({{QLatin1String("name"), password.fields.at(i).name}, {QLatin1String("value"), password.fields.at(i).value}, {QLatin1String("type"), ((password.fields.at(i).type == PasswordsManager::PasswordField) ? QLatin1String("password") : QLatin1String("text"))}})); + } - if (dialog.exec() == QDialog::Accepted) - { - updateOptions(url); + const QString script(QString::fromLatin1(file.readAll()).arg(QString::fromLatin1(QJsonDocument(fieldsArray).toJson(QJsonDocument::Indented)))); - const QVector cookiesToDelete(dialog.getCookiesToDelete()); - const QVector cookiesToInsert(dialog.getCookiesToInsert()); + file.close(); - for (int i = 0; i < cookiesToDelete.count(); ++i) - { - cookieJar->forceDeleteCookie(cookiesToDelete.at(i)); - } + QList frames({m_page->mainFrame()}); - for (int i = 0; i < cookiesToInsert.count(); ++i) - { - cookieJar->forceInsertCookie(cookiesToInsert.at(i)); - } - } - } + while (!frames.isEmpty()) + { + const QWebFrame *frame(frames.takeFirst()); + frame->documentElement().evaluateJavaScript(script); - break; - default: - break; + frames.append(frame->childFrames()); } } @@ -1951,15 +1995,15 @@ WebWidget* QtWebKitWebWidget::clone(bool cloneHistory, bool isPrivate, const QSt QWidget* QtWebKitWebWidget::getInspector() { - if (!m_inspector) + if (!m_inspectorWidget) { m_page->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); - m_inspector = new QtWebKitInspector(this); - m_inspector->setPage(m_page); + m_inspectorWidget = new QtWebKitInspectorWidget(this); + m_inspectorWidget->setPage(m_page); } - return m_inspector; + return m_inspectorWidget; } QWidget* QtWebKitWebWidget::getViewport() @@ -2539,29 +2583,6 @@ int QtWebKitWebWidget::getAmountOfDeferredPlugins() const return m_amountOfDeferredPlugins; } -int QtWebKitWebWidget::findInPage(const QString &text, FindFlags flags) -{ - QWebPage::FindFlags nativeFlags(QWebPage::FindWrapsAroundDocument | QWebPage::FindBeginsInSelection); - - if (flags.testFlag(BackwardFind)) - { - nativeFlags |= QWebPage::FindBackward; - } - - if (flags.testFlag(CaseSensitiveFind)) - { - nativeFlags |= QWebPage::FindCaseSensitively; - } - - if (flags.testFlag(HighlightAllFind) || text.isEmpty()) - { - m_page->findText({}, QWebPage::HighlightAllOccurrences); - m_page->findText(text, (nativeFlags | QWebPage::HighlightAllOccurrences)); - } - - return (m_page->findText(text, nativeFlags) ? -1 : 0); -} - bool QtWebKitWebWidget::canLoadPlugins() const { return m_canLoadPlugins; @@ -2658,7 +2679,7 @@ bool QtWebKitWebWidget::isFullScreen() const bool QtWebKitWebWidget::isInspecting() const { - return (m_inspector && m_inspector->isVisible()); + return (m_inspectorWidget && m_inspectorWidget->isVisible()); } bool QtWebKitWebWidget::isNavigating() const diff --git a/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.h b/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.h index db9ee1b6b1..54e27bbd0e 100644 --- a/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.h +++ b/src/modules/backends/web/qtwebkit/QtWebKitWebWidget.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -32,12 +33,21 @@ namespace Otter { class ContentsDialog; -class QtWebKitInspector; +class QtWebKitInspectorWidget; class QtWebKitNetworkManager; class QtWebKitWebBackend; class QtWebKitPage; class SourceViewerWebWidget; +class QtWebKitInspectorWidget final : public QWebInspector +{ +public: + explicit QtWebKitInspectorWidget(QWidget *parent); + +protected: + void childEvent(QChildEvent *event) override; +}; + class QtWebKitWebWidget final : public WebWidget { Q_OBJECT @@ -78,7 +88,6 @@ class QtWebKitWebWidget final : public WebWidget ContentStates getContentState() const override; LoadingState getLoadingState() const override; int getZoom() const override; - int findInPage(const QString &text, FindFlags flags = NoFlagsFind) override; bool hasSelection() const override; bool hasWatchedChanges(ChangeWatcher watcher) const override; bool isAudible() const override; @@ -89,6 +98,7 @@ class QtWebKitWebWidget final : public WebWidget public slots: void clearOptions() override; + void findInPage(const QString &text, FindFlags flags = NoFlagsFind) override; void fillPassword(const PasswordsManager::PasswordInformation &password) override; void triggerAction(int identifier, const QVariantMap ¶meters = {}, ActionsManager::TriggerType trigger = ActionsManager::UnknownTrigger) override; void setActiveStyleSheet(const QString &styleSheet) override; @@ -170,7 +180,7 @@ protected slots: private: QWebView *m_webView; QtWebKitPage *m_page; - QtWebKitInspector *m_inspector; + QtWebKitInspectorWidget *m_inspectorWidget; QtWebKitNetworkManager *m_networkManager; QString m_messageToken; QString m_pluginToken; diff --git a/src/modules/windows/transfers/TransfersContentsWidget.cpp b/src/modules/windows/transfers/TransfersContentsWidget.cpp index acf187bbeb..faef906d4a 100644 --- a/src/modules/windows/transfers/TransfersContentsWidget.cpp +++ b/src/modules/windows/transfers/TransfersContentsWidget.cpp @@ -227,7 +227,7 @@ void TransfersContentsWidget::clearFinishedTransfers() void TransfersContentsWidget::handleTransferAdded(Transfer *transfer) { QList items({new QStandardItem(), new QStandardItem(QFileInfo(transfer->getTarget()).fileName())}); - items[0]->setData(qVariantFromValue(static_cast(transfer)), InstanceRole); + items[0]->setData(QVariant::fromValue(static_cast(transfer)), InstanceRole); items[0]->setFlags(items[0]->flags() | Qt::ItemNeverHasChildren); items[1]->setFlags(items[1]->flags() | Qt::ItemNeverHasChildren); items.reserve(m_model->columnCount()); diff --git a/src/modules/windows/web/SearchBarWidget.cpp b/src/modules/windows/web/SearchBarWidget.cpp index 025ca2fb99..e71d8f040f 100644 --- a/src/modules/windows/web/SearchBarWidget.cpp +++ b/src/modules/windows/web/SearchBarWidget.cpp @@ -1,6 +1,6 @@ /************************************************************************** * Otter Browser: Web browser controlled by the user, not vice-versa. -* Copyright (C) 2013 - 2018 Michal Dutkiewicz aka Emdek +* Copyright (C) 2013 - 2019 Michal Dutkiewicz aka Emdek * * 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 @@ -104,27 +104,13 @@ void SearchBarWidget::selectAll() m_ui->queryLineEditWidget->selectAll(); } -void SearchBarWidget::setQuery(const QString &query) -{ - m_ui->queryLineEditWidget->setText(query); -} - -void SearchBarWidget::setVisible(bool visible) -{ - QWidget::setVisible(visible); - - if (!visible && parentWidget()) - { - parentWidget()->setFocus(); - } -} - -void SearchBarWidget::setMatchesAmount(int matchesAmount) +void SearchBarWidget::updateResults(const QString &query, int matchesAmount, int activeResult) { + QString resultsText; QPalette palette(this->palette()); const bool hasMatches(matchesAmount != 0); - if (!m_ui->queryLineEditWidget->text().isEmpty()) + if (!query.isEmpty() && m_ui->queryLineEditWidget->text() == query) { //TODO Ensure that text is readable if (hasMatches) @@ -135,13 +121,38 @@ void SearchBarWidget::setMatchesAmount(int matchesAmount) { palette.setColor(QPalette::Base, QColor(0xF1, 0xE7, 0xE4)); } + + if (matchesAmount > 0 && activeResult > 0) + { + resultsText = tr("%1 of %n result(s)", "", matchesAmount).arg(activeResult); + } + else if (matchesAmount == 0) + { + resultsText = tr("Phrase not found"); + } } + m_ui->resultsLabel->setText(resultsText); m_ui->queryLineEditWidget->setPalette(palette); m_ui->nextButton->setEnabled(hasMatches); m_ui->previousButton->setEnabled(hasMatches); } +void SearchBarWidget::setQuery(const QString &query) +{ + m_ui->queryLineEditWidget->setText(query); +} + +void SearchBarWidget::setVisible(bool visible) +{ + QWidget::setVisible(visible); + + if (!visible && parentWidget()) + { + parentWidget()->setFocus(); + } +} + QString SearchBarWidget::getQuery() const { return m_ui->queryLineEditWidget->text(); diff --git a/src/modules/windows/web/SearchBarWidget.h b/src/modules/windows/web/SearchBarWidget.h index 73e046bc65..86a03f50fe 100644 --- a/src/modules/windows/web/SearchBarWidget.h +++ b/src/modules/windows/web/SearchBarWidget.h @@ -1,6 +1,6 @@ /************************************************************************** * Otter Browser: Web browser controlled by the user, not vice-versa. -* Copyright (C) 2013 - 2018 Michal Dutkiewicz aka Emdek +* Copyright (C) 2013 - 2019 Michal Dutkiewicz aka Emdek * * 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 @@ -45,7 +45,7 @@ class SearchBarWidget final : public QWidget WebWidget::FindFlags getFlags() const; public slots: - void setMatchesAmount(int matchesAmount); + void updateResults(const QString &query, int matchesAmount, int activeResult); protected: void changeEvent(QEvent *event) override; diff --git a/src/modules/windows/web/SearchBarWidget.ui b/src/modules/windows/web/SearchBarWidget.ui index 16336ee60a..8505f5ddd3 100644 --- a/src/modules/windows/web/SearchBarWidget.ui +++ b/src/modules/windows/web/SearchBarWidget.ui @@ -56,6 +56,9 @@ + + + diff --git a/src/modules/windows/web/WebContentsWidget.cpp b/src/modules/windows/web/WebContentsWidget.cpp index b2a3afe5ba..d4a57840bd 100644 --- a/src/modules/windows/web/WebContentsWidget.cpp +++ b/src/modules/windows/web/WebContentsWidget.cpp @@ -311,14 +311,7 @@ void WebContentsWidget::search(const QString &search, const QString &query) { if (m_webWidget->getUrl().scheme() == QLatin1String("view-source")) { - QVariantMap parameters; - - if (isPrivate()) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } - - setWidget(nullptr, parameters, (m_webWidget ? m_webWidget->getOptions() : QHash())); + setWidget(nullptr, {{QLatin1String("hints"), (isPrivate() ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}, (m_webWidget ? m_webWidget->getOptions() : QHash())); } m_webWidget->search(search, query); @@ -482,6 +475,7 @@ void WebContentsWidget::triggerAction(int identifier, const QVariantMap ¶met connect(m_searchBarWidget, &SearchBarWidget::requestedSearch, this, &WebContentsWidget::findInPage); connect(m_searchBarWidget, &SearchBarWidget::flagsChanged, this, &WebContentsWidget::updateFindHighlight); + connect(m_webWidget, &WebWidget::findInPageResultsChanged, m_searchBarWidget, &SearchBarWidget::updateResults); if (SettingsManager::getOption(SettingsManager::Search_EnableFindInPageAsYouTypeOption).toBool()) { @@ -693,17 +687,12 @@ void WebContentsWidget::findInPage(WebWidget::FindFlags flags) m_quickFindQuery = (m_searchBarWidget ? m_searchBarWidget->getQuery() : m_sharedQuickFindQuery); - const int matchesAmount(m_webWidget->findInPage(m_quickFindQuery, flags)); + m_webWidget->findInPage(m_quickFindQuery, flags); if (!m_quickFindQuery.isEmpty() && !isPrivate() && SettingsManager::getOption(SettingsManager::Search_ReuseLastQuickFindQueryOption).toBool()) { m_sharedQuickFindQuery = m_quickFindQuery; } - - if (m_searchBarWidget) - { - m_searchBarWidget->setMatchesAmount(matchesAmount); - } } void WebContentsWidget::addInformationBar(QWidget *widget) @@ -1277,12 +1266,7 @@ void WebContentsWidget::setZoom(int zoom) void WebContentsWidget::setUrl(const QUrl &url, bool isTyped) { const QHash options(m_webWidget ? m_webWidget->getOptions() : QHash()); - QVariantMap parameters; - - if (isPrivate()) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } + const QVariantMap parameters({{QLatin1String("hints"), (isPrivate() ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}); if (url.scheme() == QLatin1String("view-source") && m_webWidget->getUrl().scheme() != QLatin1String("view-source")) { @@ -1328,14 +1312,7 @@ void WebContentsWidget::setParent(Window *window) WebContentsWidget* WebContentsWidget::clone(bool cloneHistory) const { - QVariantMap parameters; - - if (m_webWidget->isPrivate()) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } - - WebContentsWidget *webWidget(new WebContentsWidget(parameters, m_webWidget->getOptions(), m_webWidget->clone(cloneHistory), nullptr, nullptr)); + WebContentsWidget *webWidget(new WebContentsWidget({{QLatin1String("hints"), (isPrivate() ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}, m_webWidget->getOptions(), m_webWidget->clone(cloneHistory), nullptr, nullptr)); webWidget->m_webWidget->setRequestedUrl(m_webWidget->getUrl(), false, true); return webWidget; diff --git a/src/ui/ApplicationComboBoxWidget.cpp b/src/ui/ApplicationComboBoxWidget.cpp index 11fcd0885a..116290528a 100644 --- a/src/ui/ApplicationComboBoxWidget.cpp +++ b/src/ui/ApplicationComboBoxWidget.cpp @@ -70,6 +70,8 @@ void ApplicationComboBoxWidget::handleIndexChanged(int index) insertItem(m_previousIndex, QFileInfo(path).baseName(), path); setCurrentIndex(m_previousIndex); + + emit currentCommandChanged(); } connect(this, static_cast(&ApplicationComboBoxWidget::currentIndexChanged), this, &ApplicationComboBoxWidget::handleIndexChanged); @@ -77,6 +79,8 @@ void ApplicationComboBoxWidget::handleIndexChanged(int index) else { m_previousIndex = index; + + emit currentCommandChanged(); } } diff --git a/src/ui/ApplicationComboBoxWidget.h b/src/ui/ApplicationComboBoxWidget.h index e9522c2688..5bb945c466 100644 --- a/src/ui/ApplicationComboBoxWidget.h +++ b/src/ui/ApplicationComboBoxWidget.h @@ -47,6 +47,9 @@ protected slots: private: int m_previousIndex; bool m_alwaysShowDefaultApplication; + +signals: + void currentCommandChanged(); }; } diff --git a/src/ui/FilePathWidget.cpp b/src/ui/FilePathWidget.cpp index 82d8c938ac..282802f0c7 100644 --- a/src/ui/FilePathWidget.cpp +++ b/src/ui/FilePathWidget.cpp @@ -79,9 +79,20 @@ void FilePathWidget::focusInEvent(QFocusEvent *event) { QWidget::focusInEvent(event); + m_initialPath = getPath(); m_lineEditWidget->setFocus(); } +void FilePathWidget::focusOutEvent(QFocusEvent *event) +{ + QWidget::focusOutEvent(event); + + if (m_initialPath != getPath()) + { + emit pathChanged(getPath()); + } +} + void FilePathWidget::selectPath() { QString path(m_lineEditWidget->text().isEmpty() ? QStandardPaths::standardLocations(QStandardPaths::HomeLocation).value(0) : m_lineEditWidget->text()); diff --git a/src/ui/FilePathWidget.h b/src/ui/FilePathWidget.h index b5e523de92..097370a4f9 100644 --- a/src/ui/FilePathWidget.h +++ b/src/ui/FilePathWidget.h @@ -62,6 +62,7 @@ class FilePathWidget final : public QWidget protected: void changeEvent(QEvent *event) override; void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; protected slots: void selectPath(); @@ -72,6 +73,7 @@ protected slots: LineEditWidget *m_lineEditWidget; QCompleter *m_completer; QString m_filter; + QString m_initialPath; OpenMode m_openMode; signals: diff --git a/src/ui/SidebarWidget.cpp b/src/ui/SidebarWidget.cpp index 2abd386969..9d640cb02f 100644 --- a/src/ui/SidebarWidget.cpp +++ b/src/ui/SidebarWidget.cpp @@ -347,7 +347,7 @@ void SidebarWidget::updatePanels() { const ToolBarsManager::ToolBarDefinition definition(m_toolBarWidget->getDefinition()); - if (m_buttons.keys().toSet() == definition.panels.toSet()) + if (m_buttons.keys() == definition.panels) { selectPanel(definition.currentPanel); diff --git a/src/ui/SourceViewerWebWidget.cpp b/src/ui/SourceViewerWebWidget.cpp index 7a933177b1..e60ae34e2a 100644 --- a/src/ui/SourceViewerWebWidget.cpp +++ b/src/ui/SourceViewerWebWidget.cpp @@ -55,6 +55,7 @@ SourceViewerWebWidget::SourceViewerWebWidget(bool isPrivate, ContentsWidget *par setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &SourceViewerWebWidget::customContextMenuRequested, this, &SourceViewerWebWidget::showContextMenu); + connect(m_sourceViewer, &SourceViewerWidget::findTextResultsChanged, this, &SourceViewerWebWidget::findInPageResultsChanged); connect(m_sourceViewer, &SourceViewerWidget::zoomChanged, this, &SourceViewerWebWidget::zoomChanged); connect(m_sourceViewer, &SourceViewerWidget::zoomChanged, this, &SourceViewerWebWidget::handleZoomChanged); connect(m_sourceViewer, &SourceViewerWidget::redoAvailable, this, &SourceViewerWebWidget::notifyRedoActionStateChanged); @@ -257,6 +258,11 @@ void SourceViewerWebWidget::triggerAction(int identifier, const QVariantMap &par } } +void SourceViewerWebWidget::findInPage(const QString &text, WebWidget::FindFlags flags) +{ + m_sourceViewer->findText(text, flags); +} + void SourceViewerWebWidget::print(QPrinter *printer) { m_sourceViewer->print(printer); @@ -522,11 +528,6 @@ int SourceViewerWebWidget::getZoom() const return m_sourceViewer->getZoom(); } -int SourceViewerWebWidget::findInPage(const QString &text, WebWidget::FindFlags flags) -{ - return m_sourceViewer->findText(text, flags); -} - bool SourceViewerWebWidget::canRedo() const { return m_sourceViewer->document()->isRedoAvailable(); diff --git a/src/ui/SourceViewerWebWidget.h b/src/ui/SourceViewerWebWidget.h index 51039b5e9c..8ee3417543 100644 --- a/src/ui/SourceViewerWebWidget.h +++ b/src/ui/SourceViewerWebWidget.h @@ -49,7 +49,6 @@ class SourceViewerWebWidget final : public WebWidget HitTestResult getHitTestResult(const QPoint &position) override; WebWidget::LoadingState getLoadingState() const override; int getZoom() const override; - int findInPage(const QString &text, FindFlags flags = NoFlagsFind) override; bool canRedo() const override; bool canUndo() const override; bool hasSelection() const override; @@ -57,6 +56,7 @@ class SourceViewerWebWidget final : public WebWidget public slots: void triggerAction(int identifier, const QVariantMap ¶meters = {}, ActionsManager::TriggerType trigger = ActionsManager::UnknownTrigger) override; + void findInPage(const QString &text, FindFlags flags = NoFlagsFind) override; void setOption(int identifier, const QVariant &value) override; void setScrollPosition(const QPoint &position) override; void setHistory(const Session::Window::History &history) override; diff --git a/src/ui/SourceViewerWidget.cpp b/src/ui/SourceViewerWidget.cpp index 4ca96cbb7f..47c4a4bd9d 100644 --- a/src/ui/SourceViewerWidget.cpp +++ b/src/ui/SourceViewerWidget.cpp @@ -330,7 +330,6 @@ bool MarginWidget::event(QEvent *event) SourceViewerWidget::SourceViewerWidget(QWidget *parent) : QPlainTextEdit(parent), m_marginWidget(nullptr), m_findFlags(WebWidget::NoFlagsFind), - m_findTextResultsAmount(0), m_zoom(100) { new SyntaxHighlighter(document()); @@ -379,6 +378,72 @@ void SourceViewerWidget::wheelEvent(QWheelEvent *event) QPlainTextEdit::wheelEvent(event); } +void SourceViewerWidget::findText(const QString &text, WebWidget::FindFlags flags) +{ + const bool isTheSame(text == m_findText); + + m_findText = text; + m_findFlags = flags; + + if (!text.isEmpty()) + { + QTextDocument::FindFlags nativeFlags; + + if (flags.testFlag(WebWidget::BackwardFind)) + { + nativeFlags |= QTextDocument::FindBackward; + } + + if (flags.testFlag(WebWidget::CaseSensitiveFind)) + { + nativeFlags |= QTextDocument::FindCaseSensitively; + } + + QTextCursor findTextCursor(m_findTextAnchor); + + if (!isTheSame) + { + findTextCursor = textCursor(); + } + else if (!flags.testFlag(WebWidget::BackwardFind)) + { + findTextCursor.setPosition(findTextCursor.selectionEnd(), QTextCursor::MoveAnchor); + } + + m_findTextAnchor = document()->find(text, findTextCursor, nativeFlags); + + if (m_findTextAnchor.isNull()) + { + m_findTextAnchor = textCursor(); + m_findTextAnchor.setPosition((flags.testFlag(WebWidget::BackwardFind) ? (document()->characterCount() - 1) : 0), QTextCursor::MoveAnchor); + m_findTextAnchor = document()->find(text, m_findTextAnchor, nativeFlags); + } + + if (!m_findTextAnchor.isNull()) + { + const QTextCursor currentTextCursor(textCursor()); + + disconnect(this, &SourceViewerWidget::cursorPositionChanged, this, &SourceViewerWidget::updateTextCursor); + + setTextCursor(m_findTextAnchor); + ensureCursorVisible(); + + const QPoint position(horizontalScrollBar()->value(), verticalScrollBar()->value()); + + setTextCursor(currentTextCursor); + + horizontalScrollBar()->setValue(position.x()); + verticalScrollBar()->setValue(position.y()); + + connect(this, &SourceViewerWidget::cursorPositionChanged, this, &SourceViewerWidget::updateTextCursor); + } + } + + m_findTextSelection = m_findTextAnchor; + + updateSelection(); +} + void SourceViewerWidget::handleOptionChanged(int identifier, const QVariant &value) { switch (identifier) @@ -424,14 +489,13 @@ void SourceViewerWidget::updateSelection() if (m_findText.isEmpty()) { - m_findTextResultsAmount = 0; - setExtraSelections(extraSelections); return; } - int findTextResultsAmount(0); + int findTextMatchesAmount(0); + int findTextActiveResult(0); QTextEdit::ExtraSelection currentResultSelection; currentResultSelection.format.setBackground(QColor(255, 150, 50)); currentResultSelection.format.setProperty(QTextFormat::FullWidthSelection, true); @@ -457,7 +521,11 @@ void SourceViewerWidget::updateSelection() if (!textCursor.isNull()) { - if (textCursor != m_findTextSelection) + if (textCursor == m_findTextSelection) + { + findTextActiveResult = (findTextMatchesAmount + 1); + } + else { QTextEdit::ExtraSelection extraResultSelection; extraResultSelection.format.setBackground(QColor(255, 255, 0)); @@ -466,12 +534,12 @@ void SourceViewerWidget::updateSelection() extraSelections.append(extraResultSelection); } - ++findTextResultsAmount; + ++findTextMatchesAmount; } } } - m_findTextResultsAmount = findTextResultsAmount; + emit findTextResultsChanged(m_findText, findTextMatchesAmount, findTextActiveResult); setExtraSelections(extraSelections); } @@ -501,72 +569,4 @@ int SourceViewerWidget::getZoom() const return m_zoom; } -int SourceViewerWidget::findText(const QString &text, WebWidget::FindFlags flags) -{ - const bool isTheSame(text == m_findText); - - m_findText = text; - m_findFlags = flags; - - if (!text.isEmpty()) - { - QTextDocument::FindFlags nativeFlags; - - if (flags.testFlag(WebWidget::BackwardFind)) - { - nativeFlags |= QTextDocument::FindBackward; - } - - if (flags.testFlag(WebWidget::CaseSensitiveFind)) - { - nativeFlags |= QTextDocument::FindCaseSensitively; - } - - QTextCursor findTextCursor(m_findTextAnchor); - - if (!isTheSame) - { - findTextCursor = textCursor(); - } - else if (!flags.testFlag(WebWidget::BackwardFind)) - { - findTextCursor.setPosition(findTextCursor.selectionEnd(), QTextCursor::MoveAnchor); - } - - m_findTextAnchor = document()->find(text, findTextCursor, nativeFlags); - - if (m_findTextAnchor.isNull()) - { - m_findTextAnchor = textCursor(); - m_findTextAnchor.setPosition((flags.testFlag(WebWidget::BackwardFind) ? (document()->characterCount() - 1) : 0), QTextCursor::MoveAnchor); - m_findTextAnchor = document()->find(text, m_findTextAnchor, nativeFlags); - } - - if (!m_findTextAnchor.isNull()) - { - const QTextCursor currentTextCursor(textCursor()); - - disconnect(this, &SourceViewerWidget::cursorPositionChanged, this, &SourceViewerWidget::updateTextCursor); - - setTextCursor(m_findTextAnchor); - ensureCursorVisible(); - - const QPoint position(horizontalScrollBar()->value(), verticalScrollBar()->value()); - - setTextCursor(currentTextCursor); - - horizontalScrollBar()->setValue(position.x()); - verticalScrollBar()->setValue(position.y()); - - connect(this, &SourceViewerWidget::cursorPositionChanged, this, &SourceViewerWidget::updateTextCursor); - } - } - - m_findTextSelection = m_findTextAnchor; - - updateSelection(); - - return m_findTextResultsAmount; -} - } diff --git a/src/ui/SourceViewerWidget.h b/src/ui/SourceViewerWidget.h index ab5f541905..9d20824049 100644 --- a/src/ui/SourceViewerWidget.h +++ b/src/ui/SourceViewerWidget.h @@ -104,9 +104,9 @@ class SourceViewerWidget final : public QPlainTextEdit public: explicit SourceViewerWidget(QWidget *parent = nullptr); + void findText(const QString &text, WebWidget::FindFlags flags = WebWidget::NoFlagsFind); void setZoom(int zoom); int getZoom() const; - int findText(const QString &text, WebWidget::FindFlags flags = WebWidget::NoFlagsFind); protected: void resizeEvent(QResizeEvent *event) override; @@ -124,10 +124,10 @@ protected slots: QTextCursor m_findTextAnchor; QTextCursor m_findTextSelection; WebWidget::FindFlags m_findFlags; - int m_findTextResultsAmount; int m_zoom; signals: + void findTextResultsChanged(const QString &text, int matchesAmount, int activeResult); void zoomChanged(int zoom); friend class MarginWidget; diff --git a/src/ui/WebWidget.cpp b/src/ui/WebWidget.cpp index e729566590..e6b452eca4 100644 --- a/src/ui/WebWidget.cpp +++ b/src/ui/WebWidget.cpp @@ -650,7 +650,18 @@ void WebWidget::setOption(int identifier, const QVariant &value) void WebWidget::setOptions(const QHash &options, const QStringList &excludedOptions) { - const QList identifiers((m_options.keys() + options.keys()).toSet().toList()); + QList identifiers(m_options.keys()); + identifiers.reserve(identifiers.count() + options.count()); + + QHash::const_iterator iterator; + + for (iterator = options.begin(); iterator != options.end(); ++iterator) + { + if (!identifiers.contains(iterator.key())) + { + identifiers.append(iterator.key()); + } + } m_options = options; @@ -867,7 +878,7 @@ QString WebWidget::getFastForwardScript(bool isSelectingTheBestLink) for (int j = 0; j < keys.count(); ++j) { - tokensArray.append(QJsonObject({{QLatin1Literal("value"), keys.at(j).toUpper()}, {QLatin1Literal("score"), settings.getValue(keys.at(j)).toInt()}})); + tokensArray.append(QJsonObject({{QLatin1String("value"), keys.at(j).toUpper()}, {QLatin1String("score"), settings.getValue(keys.at(j)).toInt()}})); } settings.endGroup(); diff --git a/src/ui/WebWidget.h b/src/ui/WebWidget.h index 974787cf78..83c940a451 100644 --- a/src/ui/WebWidget.h +++ b/src/ui/WebWidget.h @@ -244,7 +244,6 @@ class WebWidget : public QWidget, public ActionExecutor virtual WebWidget::LoadingState getLoadingState() const = 0; quint64 getWindowIdentifier() const; virtual int getZoom() const = 0; - virtual int findInPage(const QString &text, FindFlags flags = NoFlagsFind) = 0; bool hasOption(int identifier) const; virtual bool hasSelection() const; virtual bool hasWatchedChanges(ChangeWatcher watcher) const; @@ -258,6 +257,7 @@ public slots: void triggerAction(int identifier, const QVariantMap ¶meters = {}, ActionsManager::TriggerType trigger = ActionsManager::UnknownTrigger) override; virtual void clearOptions(); virtual void fillPassword(const PasswordsManager::PasswordInformation &password); + virtual void findInPage(const QString &text, FindFlags flags = NoFlagsFind) = 0; virtual void showContextMenu(const QPoint &position = {}); virtual void setActiveStyleSheet(const QString &styleSheet); virtual void setPermission(FeaturePermission feature, const QUrl &url, PermissionPolicies policies); @@ -338,6 +338,7 @@ protected slots: void requestedGeometryChange(const QRect &geometry); void requestedInspectorVisibilityChange(bool isVisible); void geometryChanged(); + void findInPageResultsChanged(const QString &text, int matchesAmount, int activeResult); void statusMessageChanged(const QString &message); void titleChanged(const QString &title); void urlChanged(const QUrl &url); diff --git a/src/ui/Window.cpp b/src/ui/Window.cpp index 2e14075a52..c3dae17dd7 100644 --- a/src/ui/Window.cpp +++ b/src/ui/Window.cpp @@ -224,14 +224,7 @@ void Window::search(const QString &query, const QString &searchEngine) return; } - QVariantMap parameters; - - if (isPrivate()) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } - - widget = new WebContentsWidget(parameters, {}, nullptr, this, this); + widget = new WebContentsWidget({{QLatin1String("hints"), (isPrivate() ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}, {}, nullptr, this, this); setContentsWidget(widget); } @@ -531,14 +524,7 @@ Window* Window::clone(bool cloneHistory, MainWindow *mainWindow) const return nullptr; } - QVariantMap parameters({{QLatin1String("size"), size()}}); - - if (isPrivate()) - { - parameters[QLatin1String("hints")] = SessionsManager::PrivateOpen; - } - - return new Window(parameters, m_contentsWidget->clone(cloneHistory), mainWindow); + return new Window({{QLatin1String("size"), size()}, {QLatin1String("hints"), (isPrivate() ? SessionsManager::PrivateOpen : SessionsManager::DefaultOpen)}}, m_contentsWidget->clone(cloneHistory), mainWindow); } MainWindow* Window::getMainWindow() const diff --git a/src/ui/preferences/PreferencesAdvancedPageWidget.cpp b/src/ui/preferences/PreferencesAdvancedPageWidget.cpp index 5ff284b6a7..f1f5d6925c 100644 --- a/src/ui/preferences/PreferencesAdvancedPageWidget.cpp +++ b/src/ui/preferences/PreferencesAdvancedPageWidget.cpp @@ -398,6 +398,9 @@ PreferencesAdvancedPageWidget::PreferencesAdvancedPageWidget(QWidget *parent) : connect(m_ui->downloadsRemoveMimeTypeButton, &QPushButton::clicked, this, &PreferencesAdvancedPageWidget::removeDownloadsMimeType); connect(m_ui->downloadsButtonGroup, static_cast(&QButtonGroup::buttonToggled), this, &PreferencesAdvancedPageWidget::updateDownloadsOptions); connect(m_ui->downloadsButtonGroup, static_cast(&QButtonGroup::buttonToggled), this, &PreferencesAdvancedPageWidget::updateDownloadsMode); + connect(m_ui->downloadsSaveDirectlyCheckBox, &QCheckBox::toggled, this, &PreferencesAdvancedPageWidget::updateDownloadsOptions); + connect(m_ui->downloadsFilePathWidget, &Otter::FilePathWidget::pathChanged, this, &PreferencesAdvancedPageWidget::updateDownloadsOptions); + connect(m_ui->downloadsApplicationComboBoxWidget, &Otter::ApplicationComboBoxWidget::currentCommandChanged, this, &PreferencesAdvancedPageWidget::updateDownloadsOptions); connect(m_ui->userAgentsViewWidget, &ItemViewWidget::needsActionsUpdate, this, &PreferencesAdvancedPageWidget::updateUserAgentsActions); connect(m_ui->userAgentsAddButton->menu(), &QMenu::triggered, this, &PreferencesAdvancedPageWidget::addUserAgent); connect(m_ui->userAgentsEditButton, &QPushButton::clicked, this, &PreferencesAdvancedPageWidget::editUserAgent); @@ -841,7 +844,7 @@ void PreferencesAdvancedPageWidget::updateUserAgentsActions() m_ui->userAgentsRemoveButton->setEnabled(index.isValid() && index.data(UserAgentsModel::IdentifierRole).toString() != QLatin1String("default")); } -void PreferencesAdvancedPageWidget::saveUsuerAgents(QJsonArray *userAgents, const QStandardItem *parent) +void PreferencesAdvancedPageWidget::saveUserAgents(QJsonArray *userAgents, const QStandardItem *parent) { for (int i = 0; i < parent->rowCount(); ++i) { @@ -859,7 +862,7 @@ void PreferencesAdvancedPageWidget::saveUsuerAgents(QJsonArray *userAgents, cons { QJsonArray userAgentsArray; - saveUsuerAgents(&userAgentsArray, item); + saveUserAgents(&userAgentsArray, item); userAgentObject.insert(QLatin1String("children"), userAgentsArray); } @@ -1672,6 +1675,8 @@ void PreferencesAdvancedPageWidget::save() QFile::remove(SessionsManager::getReadableDataPath(QLatin1String("handlers.ini"))); + updateDownloadsOptions(); + for (int i = 0; i < m_ui->downloadsItemView->getRowCount(); ++i) { const QModelIndex index(m_ui->downloadsItemView->getIndex(i, 0)); @@ -1702,7 +1707,7 @@ void PreferencesAdvancedPageWidget::save() { QJsonArray userAgentsArray; - saveUsuerAgents(&userAgentsArray, m_ui->userAgentsViewWidget->getSourceModel()->invisibleRootItem()); + saveUserAgents(&userAgentsArray, m_ui->userAgentsViewWidget->getSourceModel()->invisibleRootItem()); JsonSettings settings; settings.setArray(userAgentsArray); diff --git a/src/ui/preferences/PreferencesAdvancedPageWidget.h b/src/ui/preferences/PreferencesAdvancedPageWidget.h index b07522d750..16f2eebb98 100644 --- a/src/ui/preferences/PreferencesAdvancedPageWidget.h +++ b/src/ui/preferences/PreferencesAdvancedPageWidget.h @@ -84,7 +84,7 @@ protected slots: void addUserAgent(QAction *action); void editUserAgent(); void updateUserAgentsActions(); - void saveUsuerAgents(QJsonArray *userAgents, const QStandardItem *parent); + void saveUserAgents(QJsonArray *userAgents, const QStandardItem *parent); void addProxy(QAction *action); void editProxy(); void updateProxiesActions();