mirror of
https://github.com/zealdocs/zeal.git
synced 2026-08-30 09:00:52 +08:00
276 lines
6.7 KiB
C++
276 lines
6.7 KiB
C++
// Copyright (C) Oleg Shparber, et al. <https://zealdocs.org>
|
|
// Copyright (C) 2013-2014 Jerzy Kozera
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include "webview.h"
|
|
|
|
#include "webcontrol.h"
|
|
#include "webpage.h"
|
|
|
|
#include <core/application.h>
|
|
#include <ui/browsertab.h>
|
|
#include <ui/mainwindow.h>
|
|
|
|
#include <QApplication>
|
|
#include <QCheckBox>
|
|
#include <QDesktopServices>
|
|
#include <QMenu>
|
|
#include <QMessageBox>
|
|
#include <QPushButton>
|
|
#include <QVector>
|
|
#include <QWebEngineProfile>
|
|
#include <QWebEngineSettings>
|
|
#include <QWheelEvent>
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
#include <QWebEngineContextMenuData>
|
|
#else
|
|
#include <QWebEngineContextMenuRequest>
|
|
#endif
|
|
|
|
#include <algorithm>
|
|
|
|
namespace Zeal::Browser {
|
|
|
|
WebView::WebView(QWidget *parent)
|
|
: QWebEngineView(parent)
|
|
{
|
|
setPage(new WebPage(this));
|
|
setZoomLevel(defaultZoomLevel());
|
|
|
|
// Enable plugins for PDF support.
|
|
settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
|
|
|
|
settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
|
|
|
|
QApplication::instance()->installEventFilter(this);
|
|
}
|
|
|
|
int WebView::zoomLevel() const
|
|
{
|
|
return m_zoomLevel;
|
|
}
|
|
|
|
void WebView::setZoomLevel(int level)
|
|
{
|
|
if (level == m_zoomLevel) {
|
|
return;
|
|
}
|
|
|
|
level = qMax(0, level);
|
|
level = qMin(level, availableZoomLevels().size() - 1);
|
|
|
|
m_zoomLevel = level;
|
|
|
|
// Scale the webview relative to the DPI of the screen.
|
|
// Only scale up for HiDPI displays (>96 DPI), never scale down.
|
|
const double dpiZoomFactor = std::max(1.0, logicalDpiY() / 96.0);
|
|
|
|
setZoomFactor(availableZoomLevels().at(level) / 100.0 * dpiZoomFactor);
|
|
emit zoomLevelChanged();
|
|
}
|
|
|
|
const QVector<int> &WebView::availableZoomLevels()
|
|
{
|
|
// clang-format off
|
|
static const QVector<int> zoomLevels = {30, 40, 50, 67, 80, 90, 100,
|
|
110, 120, 133, 150, 170, 200,
|
|
220, 233, 250, 270, 285, 300};
|
|
// clang-format on
|
|
|
|
return zoomLevels;
|
|
}
|
|
|
|
int WebView::defaultZoomLevel()
|
|
{
|
|
static const int level = availableZoomLevels().indexOf(100);
|
|
return level;
|
|
}
|
|
|
|
void WebView::zoomIn()
|
|
{
|
|
setZoomLevel(m_zoomLevel + 1);
|
|
}
|
|
|
|
void WebView::zoomOut()
|
|
{
|
|
setZoomLevel(m_zoomLevel - 1);
|
|
}
|
|
|
|
void WebView::resetZoom()
|
|
{
|
|
setZoomLevel(defaultZoomLevel());
|
|
}
|
|
|
|
QWebEngineView *WebView::createWindow(QWebEnginePage::WebWindowType type)
|
|
{
|
|
const bool activate = (type != QWebEnginePage::WebBrowserBackgroundTab);
|
|
return Core::Application::instance()
|
|
->mainWindow()
|
|
->createTab(QUrl(QStringLiteral("about:blank")), activate)
|
|
->webControl()
|
|
->m_webView;
|
|
}
|
|
|
|
void WebView::contextMenuEvent(QContextMenuEvent *event)
|
|
{
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
const QWebEngineContextMenuData &contextData = page()->contextMenuData();
|
|
|
|
if (!contextData.isValid()) {
|
|
QWebEngineView::contextMenuEvent(event);
|
|
return;
|
|
}
|
|
#else
|
|
QWebEngineContextMenuRequest *contextMenuRequest = lastContextMenuRequest();
|
|
if (contextMenuRequest == nullptr) {
|
|
QWebEngineView::contextMenuEvent(event);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
event->accept();
|
|
|
|
if (m_contextMenu) {
|
|
m_contextMenu->deleteLater();
|
|
}
|
|
|
|
m_contextMenu = new QMenu(this);
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
QUrl linkUrl = contextData.linkUrl();
|
|
#else
|
|
QUrl linkUrl = contextMenuRequest->linkUrl();
|
|
#endif
|
|
|
|
if (linkUrl.isValid()) {
|
|
const QString scheme = linkUrl.scheme();
|
|
|
|
if (scheme != QLatin1String("javascript")) {
|
|
m_contextMenu->addAction(tr("Open Link in New Tab"), this, [this]() {
|
|
triggerPageAction(QWebEnginePage::WebAction::OpenLinkInNewWindow);
|
|
});
|
|
}
|
|
|
|
if (scheme != QLatin1String("qrc")) {
|
|
if (scheme != QLatin1String("javascript")) {
|
|
m_contextMenu->addAction(tr("Open Link in Desktop Browser"), this, [linkUrl]() {
|
|
QDesktopServices::openUrl(linkUrl);
|
|
});
|
|
}
|
|
|
|
m_contextMenu->addAction(pageAction(QWebEnginePage::CopyLinkToClipboard));
|
|
}
|
|
}
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
const QString selectedText = contextData.selectedText();
|
|
#else
|
|
const QString selectedText = contextMenuRequest->selectedText();
|
|
#endif
|
|
|
|
if (!selectedText.isEmpty()) {
|
|
if (!m_contextMenu->isEmpty()) {
|
|
m_contextMenu->addSeparator();
|
|
}
|
|
|
|
m_contextMenu->addAction(pageAction(QWebEnginePage::Copy));
|
|
}
|
|
|
|
if (!linkUrl.isValid() && url().scheme() != QLatin1String("qrc")) {
|
|
if (!m_contextMenu->isEmpty()) {
|
|
m_contextMenu->addSeparator();
|
|
}
|
|
|
|
m_contextMenu->addAction(pageAction(QWebEnginePage::Back));
|
|
m_contextMenu->addAction(pageAction(QWebEnginePage::Forward));
|
|
m_contextMenu->addSeparator();
|
|
|
|
m_contextMenu->addAction(tr("Open Page in Desktop Browser"), this, [this]() {
|
|
QDesktopServices::openUrl(url());
|
|
});
|
|
}
|
|
|
|
if (m_contextMenu->isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
m_contextMenu->popup(event->globalPos());
|
|
}
|
|
|
|
bool WebView::handleMouseReleaseEvent(QMouseEvent *event)
|
|
{
|
|
switch (event->button()) {
|
|
case Qt::BackButton:
|
|
// Check if cursor is still inside webview.
|
|
if (rect().contains(event->pos())) {
|
|
back();
|
|
}
|
|
|
|
event->accept();
|
|
return true;
|
|
|
|
case Qt::ForwardButton:
|
|
if (rect().contains(event->pos())) {
|
|
forward();
|
|
}
|
|
|
|
event->accept();
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool WebView::handleWheelEvent(QWheelEvent *event)
|
|
{
|
|
if (event->modifiers() & Qt::ControlModifier) {
|
|
const QPoint angleDelta = event->angleDelta();
|
|
int delta = qAbs(angleDelta.x()) > qAbs(angleDelta.y()) ? angleDelta.x() : angleDelta.y();
|
|
const int direction = delta > 0 ? 1 : -1;
|
|
|
|
int levelDelta = 0;
|
|
while (delta * direction >= 120) {
|
|
levelDelta += direction;
|
|
delta -= 120 * direction;
|
|
}
|
|
|
|
setZoomLevel(m_zoomLevel + levelDelta);
|
|
event->accept();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool WebView::eventFilter(QObject *watched, QEvent *event)
|
|
{
|
|
if (watched->parent() == this) {
|
|
switch (event->type()) {
|
|
case QEvent::MouseButtonRelease:
|
|
if (handleMouseReleaseEvent(static_cast<QMouseEvent *>(event))) {
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
|
|
case QEvent::Wheel:
|
|
if (handleWheelEvent(static_cast<QWheelEvent *>(event))) {
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return QWebEngineView::eventFilter(watched, event);
|
|
}
|
|
|
|
} // namespace Zeal::Browser
|