Skip to content

Commit

Permalink
Widget: Display page in external browser when link in notebook is cli…
Browse files Browse the repository at this point in the history
…cked

When the user clicks on a link in a notebook, the NotebookWidget calls
createWindow() in order to open a new tab to display the link. This commit
intercepts the call and creates a WebViewInBrowser object. When the URL in
that object is set, the link is opened in an external web browser.
  • Loading branch information
jitseniesen committed Jan 9, 2021
1 parent 37be02a commit 2897f79
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
51 changes: 47 additions & 4 deletions spyder_notebook/widgets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@

"""Qt widgets for the notebook."""

# Standard library imports
import json
import os
import os.path as osp
import json
from string import Template
import sys

Expand All @@ -19,10 +20,8 @@
from qtpy.QtWidgets import (QApplication, QMenu, QVBoxLayout, QWidget,
QMessageBox)

# Notebook imports
from notebook.utils import url_path_join, url_escape

# Third-party imports
from notebook.utils import url_path_join, url_escape
import requests

# Spyder imports
Expand Down Expand Up @@ -55,6 +54,39 @@
# -----------------------------------------------------------------------------
# Widgets
# -----------------------------------------------------------------------------
class WebViewInBrowser(QWebEngineView):
"""
WebView which opens document in an external browser.
This is a subclass of QWebEngineView, which as soon as the URL is set,
opens the web page in an external browser and closes itself. It is used
in NotebookWidget to open links.
"""

def __init__(self, parent):
"""Construct object."""
super().__init__(parent)
self.urlChanged.connect(self.open_in_browser)

def open_in_browser(self, url):
"""
Open web page in external browser and close self.
Parameters
----------
url : QUrl
URL of web page to open in browser
"""
import webbrowser
try:
webbrowser.open(url.toString())
except ValueError:
# See: spyder-ide/spyder#9849
pass
self.stop()
self.close()


class NotebookWidget(DOMWidget):
"""WebView widget for notebooks."""

Expand Down Expand Up @@ -153,6 +185,17 @@ def show_message(self, page):
"""Show a message page with the given .html file."""
self.setHtml(page)

def createWindow(self, webWindowType):
"""
Create new browser window.
This function is called by Qt if the user clicks on a link in the
notebook. The goal is to open the web page in an external browser.
To that end, we create and return an object which will open the browser
when Qt sets the URL.
"""
return WebViewInBrowser(self.parent())


class NotebookClient(QWidget):
"""
Expand Down
15 changes: 15 additions & 0 deletions spyder_notebook/widgets/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

# Third-party imports
import pytest
from qtpy.QtCore import QUrl
from qtpy.QtWidgets import QWidget
import requests

Expand Down Expand Up @@ -47,6 +48,20 @@ def plugin(plugin_without_server):
return plugin_without_server


def test_notebookwidget_create_window(plugin, mocker, qtbot):
"""Test that NotebookWidget.create_window() creates an object that calls
webbrowser.open() when its URL is set."""
widget = plugin.client.notebookwidget
mock_notebook_open = mocker.patch('webbrowser.open')
new_view = widget.createWindow(42)
url = 'https://www.spyder-ide.org/'

with qtbot.waitSignal(new_view.loadFinished):
new_view.setUrl(QUrl(url))

mock_notebook_open.assert_called_once_with(url)


def test_notebookclient_get_kernel_id(plugin, mocker):
"""Basic unit test for NotebookClient.get_kernel_id()."""
response = mocker.Mock()
Expand Down

0 comments on commit 2897f79

Please sign in to comment.