ui: Make external link behavior configurable (fixes #416)

This commit is contained in:
Oleg Shparber 2018-01-07 16:00:22 +02:00
parent 8fa793a6f6
commit 3b2a395728
9 changed files with 165 additions and 23 deletions

View File

@ -47,6 +47,8 @@ using namespace Zeal::Core;
Settings::Settings(QObject *parent) :
QObject(parent)
{
qRegisterMetaTypeStreamOperators<ExternalLinkPolicy>("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<ExternalLinkPolicy>();
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<std::underlying_type<Settings::ExternalLinkPolicy>::type>(policy);
return out;
}
QDataStream &operator>>(QDataStream &in, Settings::ExternalLinkPolicy &policy)
{
std::underlying_type<Settings::ExternalLinkPolicy>::type value;
in >> value;
policy = static_cast<Settings::ExternalLinkPolicy>(value);
return in;
}

View File

@ -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

View File

@ -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?<br>URL: <b>%1</b>");
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);

View File

@ -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())

View File

@ -313,6 +313,39 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_7">
<property name="title">
<string>External Link Behavior</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<widget class="QRadioButton" name="radioExternalLinkAsk">
<property name="text">
<string>Ask Everytime</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioExternalLinkOpenDesktop">
<property name="text">
<string>Open in Desktop Browser</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioExternalLinkOpen">
<property name="text">
<string>Open in Zeal</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">

View File

@ -27,10 +27,14 @@
#include "../mainwindow.h"
#include <core/application.h>
#include <core/settings.h>
#include <QApplication>
#include <QCheckBox>
#include <QDesktopServices>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
#include <QWheelEvent>
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());
}
@ -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)) {
break;
if (event->button() != Qt::LeftButton && event->button() != Qt::MiddleButton) {
QWebView::mouseReleaseEvent(event);
return;
}
case Qt::MiddleButton:
if (!m_clickedLink.isEmpty() && m_clickedLink == hitTestContent(event->pos()).linkUrl()) {
QWebView *webView = createWindow(QWebPage::WebBrowserWindow);
webView->load(m_clickedLink);
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<QMessageBox> mb(new QMessageBox());
mb->setIcon(QMessageBox::Question);
mb->setText(tr("How do you want to open the external link?<br>URL: <b>%1</b>")
.arg(clickedLink.toString()));
QCheckBox *checkBox = new QCheckBox("Do &not 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 Core::Settings::ExternalLinkPolicy::OpenInSystemBrowser:
QDesktopServices::openUrl(clickedLink);
event->accept();
return;
}
}
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");
}

View File

@ -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();

View File

@ -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);

View File

@ -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);