diff --git a/src/libs/core/settings.cpp b/src/libs/core/settings.cpp index d62bd73..d9551e0 100644 --- a/src/libs/core/settings.cpp +++ b/src/libs/core/settings.cpp @@ -47,6 +47,8 @@ using namespace Zeal::Core; Settings::Settings(QObject *parent) : QObject(parent) { + qRegisterMetaTypeStreamOperators("ExternalLinkPolicy"); + load(); } @@ -88,6 +90,8 @@ void Settings::load() darkModeEnabled = settings->value(QStringLiteral("dark_mode"), false).toBool(); highlightOnNavigateEnabled = settings->value(QStringLiteral("highlight_on_navigate"), true).toBool(); customCssFile = settings->value(QStringLiteral("custom_css_file")).toString(); + externalLinkPolicy = settings->value(QStringLiteral("external_link_policy"), + QVariant::fromValue(ExternalLinkPolicy::Ask)).value(); isAdDisabled = settings->value(QStringLiteral("disable_ad"), false).toBool(); settings->endGroup(); @@ -157,6 +161,7 @@ void Settings::save() settings->setValue(QStringLiteral("dark_mode"), darkModeEnabled); settings->setValue(QStringLiteral("highlight_on_navigate"), highlightOnNavigateEnabled); settings->setValue(QStringLiteral("custom_css_file"), customCssFile); + settings->setValue(QStringLiteral("external_link_policy"), QVariant::fromValue(externalLinkPolicy)); settings->setValue(QStringLiteral("disable_ad"), isAdDisabled); settings->endGroup(); @@ -254,3 +259,17 @@ QSettings *Settings::qsettings(QObject *parent) QSettings::IniFormat, parent); #endif } + +QDataStream &operator<<(QDataStream &out, const Settings::ExternalLinkPolicy &policy) +{ + out << static_cast::type>(policy); + return out; +} + +QDataStream &operator>>(QDataStream &in, Settings::ExternalLinkPolicy &policy) +{ + std::underlying_type::type value; + in >> value; + policy = static_cast(value); + return in; +} diff --git a/src/libs/core/settings.h b/src/libs/core/settings.h index bf2100f..87d57d3 100644 --- a/src/libs/core/settings.h +++ b/src/libs/core/settings.h @@ -60,6 +60,14 @@ public: bool fuzzySearchEnabled; // Content + enum class ExternalLinkPolicy : unsigned int { + Ask = 0, + Open, + OpenInSystemBrowser + }; + Q_ENUM(ExternalLinkPolicy) + ExternalLinkPolicy externalLinkPolicy = ExternalLinkPolicy::Ask; + int minimumFontSize; bool darkModeEnabled; bool highlightOnNavigateEnabled; @@ -118,4 +126,9 @@ private: } // namespace Core } // namespace Zeal +QDataStream &operator<<(QDataStream &out, const Zeal::Core::Settings::ExternalLinkPolicy &policy); +QDataStream &operator>>(QDataStream &in, Zeal::Core::Settings::ExternalLinkPolicy &policy); + +Q_DECLARE_METATYPE(Zeal::Core::Settings::ExternalLinkPolicy) + #endif // ZEAL_CORE_SETTINGS_H diff --git a/src/libs/ui/mainwindow.cpp b/src/libs/ui/mainwindow.cpp index b47773c..1c7de3e 100644 --- a/src/libs/ui/mainwindow.cpp +++ b/src/libs/ui/mainwindow.cpp @@ -604,13 +604,6 @@ void MainWindow::attachTab(TabState *tabState) m_tabBar->setTabToolTip(m_tabBar->currentIndex(), title); }); - connect(tabState->widget, &WebViewTab::linkClicked, this, [this](const QUrl &url) { - const QString message = tr("Do you want to open an external link?
URL: %1"); - int ret = QMessageBox::question(this, QStringLiteral("Zeal"), message.arg(url.toString())); - if (ret == QMessageBox::Yes) - QDesktopServices::openUrl(url); - }); - ui->lineEdit->setText(tabState->searchQuery); ui->tocListView->setModel(tabState->tocModel); diff --git a/src/libs/ui/settingsdialog.cpp b/src/libs/ui/settingsdialog.cpp index 71e1833..efb0a94 100644 --- a/src/libs/ui/settingsdialog.cpp +++ b/src/libs/ui/settingsdialog.cpp @@ -112,6 +112,18 @@ void SettingsDialog::loadSettings() ui->customCssFileEdit->setText(QDir::toNativeSeparators(settings->customCssFile)); ui->disableAdCheckBox->setChecked(settings->isAdDisabled); + switch (settings->externalLinkPolicy) { + case Core::Settings::ExternalLinkPolicy::Ask: + ui->radioExternalLinkAsk->setChecked(true); + break; + case Core::Settings::ExternalLinkPolicy::Open: + ui->radioExternalLinkOpen->setChecked(true); + break; + case Core::Settings::ExternalLinkPolicy::OpenInSystemBrowser: + ui->radioExternalLinkOpenDesktop->setChecked(true); + break; + } + // Network Tab switch (settings->proxyType) { case Core::Settings::ProxyType::None: @@ -161,6 +173,14 @@ void SettingsDialog::saveSettings() settings->customCssFile = QDir::fromNativeSeparators(ui->customCssFileEdit->text()); settings->isAdDisabled = ui->disableAdCheckBox->isChecked(); + if (ui->radioExternalLinkAsk->isChecked()) { + settings->externalLinkPolicy = Core::Settings::ExternalLinkPolicy::Ask; + } else if (ui->radioExternalLinkOpen->isChecked()) { + settings->externalLinkPolicy = Core::Settings::ExternalLinkPolicy::Open; + } else if (ui->radioExternalLinkOpenDesktop->isChecked()) { + settings->externalLinkPolicy = Core::Settings::ExternalLinkPolicy::OpenInSystemBrowser; + } + // Network Tab // Proxy settings if (ui->noProxySettings->isChecked()) diff --git a/src/libs/ui/settingsdialog.ui b/src/libs/ui/settingsdialog.ui index 36fb206..14fdf98 100644 --- a/src/libs/ui/settingsdialog.ui +++ b/src/libs/ui/settingsdialog.ui @@ -313,6 +313,39 @@ + + + + External Link Behavior + + + + + + Ask Everytime + + + true + + + + + + + Open in Desktop Browser + + + + + + + Open in Zeal + + + + + + diff --git a/src/libs/ui/widgets/webview.cpp b/src/libs/ui/widgets/webview.cpp index 752032d..e28a626 100644 --- a/src/libs/ui/widgets/webview.cpp +++ b/src/libs/ui/widgets/webview.cpp @@ -27,10 +27,14 @@ #include "../mainwindow.h" #include +#include #include +#include #include #include +#include +#include #include using namespace Zeal::WidgetUi; @@ -39,7 +43,6 @@ WebView::WebView(QWidget *parent) : QWebView(parent) { setAttribute(Qt::WA_AcceptTouchEvents, false); - page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks); page()->setNetworkAccessManager(Core::Application::instance()->networkManager()); } @@ -107,8 +110,8 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) // Return standard menu for input fields. if (hitTestResult.isContentEditable()) { - QWebView::contextMenuEvent(event); - return; + QWebView::contextMenuEvent(event); + return; } event->accept(); @@ -176,9 +179,6 @@ void WebView::mousePressEvent(QMouseEvent *event) event->accept(); return; case Qt::LeftButton: - if (!(event->modifiers() & Qt::ControlModifier || event->modifiers() & Qt::ShiftModifier)) { - break; - } case Qt::MiddleButton: m_clickedLink = hitTestContent(event->pos()).linkUrl(); if (!m_clickedLink.isValid()) { @@ -196,20 +196,78 @@ void WebView::mousePressEvent(QMouseEvent *event) void WebView::mouseReleaseEvent(QMouseEvent *event) { - switch (event->button()) { - case Qt::LeftButton: - if (!(event->modifiers() & Qt::ControlModifier || event->modifiers() & Qt::ShiftModifier)) { + if (event->button() != Qt::LeftButton && event->button() != Qt::MiddleButton) { + QWebView::mouseReleaseEvent(event); + return; + } + + const QUrl clickedLink = hitTestContent(event->pos()).linkUrl(); + if (!clickedLink.isValid() || clickedLink != m_clickedLink) { + QWebView::mouseReleaseEvent(event); + return; + } + + if (isUrlExternal(clickedLink)) { + switch (Core::Application::instance()->settings()->externalLinkPolicy) { + case Core::Settings::ExternalLinkPolicy::Open: break; + case Core::Settings::ExternalLinkPolicy::Ask: { + QScopedPointer mb(new QMessageBox()); + mb->setIcon(QMessageBox::Question); + mb->setText(tr("How do you want to open the external link?
URL: %1") + .arg(clickedLink.toString())); + + + QCheckBox *checkBox = new QCheckBox("Do ¬ ask again"); + mb->setCheckBox(checkBox); + + QPushButton *openInBrowserButton = mb->addButton(tr("Open in &Desktop Browser"), + QMessageBox::ActionRole); + QPushButton *openInZealButton = mb->addButton(tr("Open in &Zeal"), + QMessageBox::ActionRole); + mb->addButton(QMessageBox::Cancel); + + mb->setDefaultButton(openInBrowserButton); + + if (mb->exec() == QMessageBox::Cancel) { + event->accept(); + return; + } + + if (mb->clickedButton() == openInZealButton) { + if (checkBox->isChecked()) { + Core::Application::instance()->settings()->externalLinkPolicy + = Core::Settings::ExternalLinkPolicy::Open; + Core::Application::instance()->settings()->save(); + } + + break; + } else if (mb->clickedButton() == openInBrowserButton) { + if (checkBox->isChecked()) { + Core::Application::instance()->settings()->externalLinkPolicy + = Core::Settings::ExternalLinkPolicy::OpenInSystemBrowser; + Core::Application::instance()->settings()->save(); + } + } } - case Qt::MiddleButton: - if (!m_clickedLink.isEmpty() && m_clickedLink == hitTestContent(event->pos()).linkUrl()) { - QWebView *webView = createWindow(QWebPage::WebBrowserWindow); - webView->load(m_clickedLink); + case Core::Settings::ExternalLinkPolicy::OpenInSystemBrowser: + QDesktopServices::openUrl(clickedLink); event->accept(); return; } + } - break; + switch (event->button()) { + case Qt::LeftButton: + if (!(event->modifiers() & Qt::ControlModifier || event->modifiers() & Qt::ShiftModifier)) { + load(clickedLink); + event->accept(); + return; + } + case Qt::MiddleButton: + createWindow(QWebPage::WebBrowserWindow)->load(clickedLink); + event->accept(); + return; default: break; } @@ -242,3 +300,9 @@ QWebHitTestResult WebView::hitTestContent(const QPoint &pos) const { return page()->mainFrame()->hitTestContent(pos); } + +bool WebView::isUrlExternal(const QUrl &url) +{ + const QString scheme = url.scheme(); + return !scheme.isEmpty() && scheme != QLatin1String("file") && scheme != QLatin1String("qrc"); +} diff --git a/src/libs/ui/widgets/webview.h b/src/libs/ui/widgets/webview.h index 55c8a5e..72dcdbc 100644 --- a/src/libs/ui/widgets/webview.h +++ b/src/libs/ui/widgets/webview.h @@ -61,6 +61,8 @@ protected: private: QWebHitTestResult hitTestContent(const QPoint &pos) const; + static bool isUrlExternal(const QUrl &url); + QMenu *m_contextMenu = nullptr; QUrl m_clickedLink; int m_zoomLevel = defaultZoomLevel(); diff --git a/src/libs/ui/widgets/webviewtab.cpp b/src/libs/ui/widgets/webviewtab.cpp index dc604dd..50c3792 100644 --- a/src/libs/ui/widgets/webviewtab.cpp +++ b/src/libs/ui/widgets/webviewtab.cpp @@ -52,7 +52,6 @@ WebViewTab::WebViewTab(QWidget *parent) setToolTip(link); }); - connect(m_webView, &QWebView::linkClicked, this, &WebViewTab::linkClicked); connect(m_webView, &QWebView::titleChanged, this, &WebViewTab::titleChanged); connect(m_webView, &QWebView::urlChanged, this, &WebViewTab::urlChanged); diff --git a/src/libs/ui/widgets/webviewtab.h b/src/libs/ui/widgets/webviewtab.h index d951d50..903c641 100644 --- a/src/libs/ui/widgets/webviewtab.h +++ b/src/libs/ui/widgets/webviewtab.h @@ -55,7 +55,6 @@ public: void setZoomLevel(int level); signals: - void linkClicked(const QUrl &url); void titleChanged(const QString &title); void urlChanged(const QUrl &url);