Move private tab API into an own object

This commit is contained in:
Florian Bruhin 2018-11-28 17:59:27 +01:00
parent d60dff2623
commit 5f5f202098
8 changed files with 127 additions and 98 deletions

View File

@ -734,6 +734,67 @@ class AbstractAudio(QObject):
raise NotImplementedError
class AbstractTabPrivate:
"""Tab-related methods which are only needed in the core.
Those methods are not part of the API which is exposed to extensions, and
should ideally be removed at some point in the future.
"""
def __init__(self, mode_manager: modeman.ModeManager,
tab: 'AbstractTab') -> None:
self._widget = None # type: typing.Optional[QWidget]
self._tab = tab
self._mode_manager = mode_manager
def event_target(self) -> QWidget:
"""Return the widget events should be sent to."""
raise NotImplementedError
def handle_auto_insert_mode(self, ok: bool) -> None:
"""Handle `input.insert_mode.auto_load` after loading finished."""
if not config.val.input.insert_mode.auto_load or not ok:
return
cur_mode = self._mode_manager.mode
if cur_mode == usertypes.KeyMode.insert:
return
def _auto_insert_mode_cb(elem: webelem.AbstractWebElement) -> None:
"""Called from JS after finding the focused element."""
if elem is None:
log.webview.debug("No focused element!")
return
if elem.is_editable():
modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
'load finished', only_if_normal=True)
self._tab.elements.find_focused(_auto_insert_mode_cb)
def clear_ssl_errors(self) -> None:
raise NotImplementedError
def networkaccessmanager(self) -> typing.Optional[QNetworkAccessManager]:
"""Get the QNetworkAccessManager for this tab.
This is only implemented for QtWebKit.
For QtWebEngine, always returns None.
"""
raise NotImplementedError
def user_agent(self) -> typing.Optional[str]:
"""Get the user agent for this tab.
This is only implemented for QtWebKit.
For QtWebEngine, always returns None.
"""
raise NotImplementedError
def shutdown(self) -> None:
raise NotImplementedError
class AbstractTab(QWidget):
"""A wrapper over the given widget to hide its API and expose another one.
@ -785,10 +846,7 @@ class AbstractTab(QWidget):
renderer_process_terminated = pyqtSignal(TerminationStatus, int)
predicted_navigation = pyqtSignal(QUrl)
def __init__(self, *,
win_id: int,
mode_manager: modeman.ModeManager,
private: bool,
def __init__(self, *, win_id: int, private: bool,
parent: QWidget = None) -> None:
self.is_private = private
self.win_id = win_id
@ -806,7 +864,6 @@ class AbstractTab(QWidget):
self._widget = None # type: typing.Optional[QWidget]
self._progress = 0
self._has_ssl_errors = False
self._mode_manager = mode_manager
self._load_status = usertypes.LoadStatus.none
self._mouse_event_filter = mouse.MouseEventFilter(
self, parent=self)
@ -833,6 +890,7 @@ class AbstractTab(QWidget):
self.action._widget = widget
self.elements._widget = widget
self.audio._widget = widget
self.private_api._widget = widget
self.settings._settings = widget.settings()
self._install_event_filter()
@ -849,10 +907,6 @@ class AbstractTab(QWidget):
self._load_status = val
self.load_status_changed.emit(val.name)
def event_target(self) -> QWidget:
"""Return the widget events should be sent to."""
raise NotImplementedError
def send_event(self, evt: QEvent) -> None:
"""Send the given event to the underlying widget.
@ -865,7 +919,7 @@ class AbstractTab(QWidget):
raise utils.Unreachable("Can't re-use an event which was already "
"posted!")
recipient = self.event_target()
recipient = self.private_api.event_target()
if recipient is None:
# https://github.com/qutebrowser/qutebrowser/issues/3888
log.webview.warning("Unable to find event target!")
@ -925,26 +979,6 @@ class AbstractTab(QWidget):
navigation.url.errorString()))
navigation.accepted = False
def handle_auto_insert_mode(self, ok: bool) -> None:
"""Handle `input.insert_mode.auto_load` after loading finished."""
if not config.val.input.insert_mode.auto_load or not ok:
return
cur_mode = self._mode_manager.mode
if cur_mode == usertypes.KeyMode.insert:
return
def _auto_insert_mode_cb(elem: webelem.AbstractWebElement) -> None:
"""Called from JS after finding the focused element."""
if elem is None:
log.webview.debug("No focused element!")
return
if elem.is_editable():
modeman.enter(self.win_id, usertypes.KeyMode.insert,
'load finished', only_if_normal=True)
self.elements.find_focused(_auto_insert_mode_cb)
@pyqtSlot(bool)
def _on_load_finished(self, ok: bool) -> None:
assert self._widget is not None
@ -1010,9 +1044,6 @@ class AbstractTab(QWidget):
def stop(self) -> None:
raise NotImplementedError
def clear_ssl_errors(self) -> None:
raise NotImplementedError
def key_press(self,
key: Qt.Key,
modifier: Qt.KeyboardModifier = Qt.NoModifier) -> None:
@ -1048,9 +1079,6 @@ class AbstractTab(QWidget):
"""
raise NotImplementedError
def shutdown(self) -> None:
raise NotImplementedError
def title(self) -> str:
raise NotImplementedError
@ -1060,22 +1088,6 @@ class AbstractTab(QWidget):
def set_html(self, html: str, base_url: QUrl = QUrl()) -> None:
raise NotImplementedError
def networkaccessmanager(self) -> typing.Optional[QNetworkAccessManager]:
"""Get the QNetworkAccessManager for this tab.
This is only implemented for QtWebKit.
For QtWebEngine, always returns None.
"""
raise NotImplementedError
def user_agent(self) -> typing.Optional[str]:
"""Get the user agent for this tab.
This is only implemented for QtWebKit.
For QtWebEngine, always returns None.
"""
raise NotImplementedError
def __repr__(self) -> str:
try:
qurl = self.url()

View File

@ -1516,7 +1516,7 @@ class CommandDispatcher:
else:
download_manager.get_mhtml(tab, target)
else:
qnam = tab.networkaccessmanager()
qnam = tab.private_api.networkaccessmanager()
suggested_fn = downloads.suggested_fn_from_title(
self._current_url().path(), tab.title()
@ -2165,7 +2165,7 @@ class CommandDispatcher:
debug=True, backend=usertypes.Backend.QtWebKit)
def debug_clear_ssl_errors(self):
"""Clear remembered SSL error answers."""
self._current_widget().clear_ssl_errors()
self._current_widget().private_api.clear_ssl_errors()
@cmdutils.register(instance='command-dispatcher', scope='window')
def edit_url(self, url=None, bg=False, tab=False, window=False,

View File

@ -304,7 +304,7 @@ class HintActions:
raise HintingError("No suitable link found for this element.")
prompt = False if context.rapid else None
qnam = context.tab.networkaccessmanager()
qnam = context.tab.private_api.networkaccessmanager()
user_agent = context.tab.user_agent()
# FIXME:qtwebengine do this with QtWebEngine downloads?

View File

@ -240,7 +240,7 @@ class MouseEventFilter(QObject):
evtype = event.type()
if evtype not in self._handlers:
return False
if obj is not self._tab.event_target():
if obj is not self._tab.private_api.event_target():
log.mouse.debug("Ignoring {} to {}".format(
event.__class__.__name__, obj))
return False

View File

@ -1038,6 +1038,28 @@ class _WebEngineScripts(QObject):
page_scripts.insert(new_script)
class WebEngineTabPrivate(browsertab.AbstractTabPrivate):
"""QtWebEngine-related methods which aren't part of the public API."""
def networkaccessmanager(self):
return None
def user_agent(self):
return None
def clear_ssl_errors(self):
raise browsertab.UnsupportedOperationError
def event_target(self):
return self._widget.render_widget()
def shutdown(self):
self._tab.shutting_down.emit()
self._tab.action.exit_fullscreen()
self._widget.shutdown()
class WebEngineTab(browsertab.AbstractTab):
"""A QtWebEngine tab in the browser.
@ -1051,8 +1073,7 @@ class WebEngineTab(browsertab.AbstractTab):
_load_finished_fake = pyqtSignal(bool)
def __init__(self, *, win_id, mode_manager, private, parent=None):
super().__init__(win_id=win_id, mode_manager=mode_manager,
private=private, parent=parent)
super().__init__(win_id=win_id, private=private, parent=parent)
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id,
private=private)
self.history = WebEngineHistory(tab=self)
@ -1065,6 +1086,8 @@ class WebEngineTab(browsertab.AbstractTab):
self.elements = WebEngineElements(tab=self)
self.action = WebEngineAction(tab=self)
self.audio = WebEngineAudio(tab=self, parent=self)
self.private_api = WebEngineTabPrivate(mode_manager=mode_manager,
tab=self)
self._permissions = _WebEnginePermissions(tab=self, parent=self)
self._scripts = _WebEngineScripts(tab=self, parent=self)
# We're assigning settings in _set_widget
@ -1146,11 +1169,6 @@ class WebEngineTab(browsertab.AbstractTab):
else:
self._widget.page().runJavaScript(code, world_id, callback)
def shutdown(self):
self.shutting_down.emit()
self.action.exit_fullscreen()
self._widget.shutdown()
def reload(self, *, force=False):
if force:
action = QWebEnginePage.ReloadAndBypassCache
@ -1175,15 +1193,6 @@ class WebEngineTab(browsertab.AbstractTab):
# percent encoded content is 2 megabytes minus 30 bytes.
self._widget.setHtml(html, base_url)
def networkaccessmanager(self):
return None
def user_agent(self):
return None
def clear_ssl_errors(self):
raise browsertab.UnsupportedOperationError
def key_press(self, key, modifier=Qt.NoModifier):
press_evt = QKeyEvent(QEvent.KeyPress, key, modifier, 0, 0, 0)
release_evt = QKeyEvent(QEvent.KeyRelease, key, modifier,
@ -1485,6 +1494,3 @@ class WebEngineTab(browsertab.AbstractTab):
self.audio._connect_signals()
self._permissions.connect_signals()
self._scripts.connect_signals()
def event_target(self):
return self._widget.render_widget()

View File

@ -657,13 +657,33 @@ class WebKitAudio(browsertab.AbstractAudio):
return False
class WebKitTabPrivate(browsertab.AbstractTabPrivate):
"""QtWebKit-related methods which aren't part of the public API."""
def networkaccessmanager(self):
return self._widget.page().networkAccessManager()
def user_agent(self):
page = self._widget.page()
return page.userAgentForUrl(self._tab.url())
def clear_ssl_errors(self):
self.networkaccessmanager().clear_all_ssl_errors()
def event_target(self):
return self._widget
def shutdown(self):
self._widget.shutdown()
class WebKitTab(browsertab.AbstractTab):
"""A QtWebKit tab in the browser."""
def __init__(self, *, win_id, mode_manager, private, parent=None):
super().__init__(win_id=win_id, mode_manager=mode_manager,
private=private, parent=parent)
super().__init__(win_id=win_id, private=private, parent=parent)
widget = webview.WebView(win_id=win_id, tab_id=self.tab_id,
private=private, tab=self)
if private:
@ -678,6 +698,8 @@ class WebKitTab(browsertab.AbstractTab):
self.elements = WebKitElements(tab=self)
self.action = WebKitAction(tab=self)
self.audio = WebKitAudio(tab=self, parent=self)
self.private_api = WebKitTabPrivate(mode_manager=mode_manager,
tab=self)
# We're assigning settings in _set_widget
self.settings = webkitsettings.WebKitSettings(settings=None)
self._set_widget(widget)
@ -720,9 +742,6 @@ class WebKitTab(browsertab.AbstractTab):
def icon(self):
return self._widget.icon()
def shutdown(self):
self._widget.shutdown()
def reload(self, *, force=False):
if force:
action = QWebPage.ReloadAndBypassCache
@ -736,9 +755,6 @@ class WebKitTab(browsertab.AbstractTab):
def title(self):
return self._widget.title()
def clear_ssl_errors(self):
self.networkaccessmanager().clear_all_ssl_errors()
def key_press(self, key, modifier=Qt.NoModifier):
press_evt = QKeyEvent(QEvent.KeyPress, key, modifier, 0, 0, 0)
release_evt = QKeyEvent(QEvent.KeyRelease, key, modifier,
@ -755,17 +771,11 @@ class WebKitTab(browsertab.AbstractTab):
def set_html(self, html, base_url=QUrl()):
self._widget.setHtml(html, base_url)
def networkaccessmanager(self):
return self._widget.page().networkAccessManager()
def user_agent(self):
page = self._widget.page()
return page.userAgentForUrl(self.url())
@pyqtSlot()
def _on_load_started(self):
super()._on_load_started()
self.networkaccessmanager().netrc_used = False
nam = self._widget.page().networkAccessManager()
nam.netrc_used = False
# Make sure the icon is cleared when navigating to a page without one.
self.icon_changed.emit(QIcon())
@ -847,6 +857,3 @@ class WebKitTab(browsertab.AbstractTab):
frame.contentsSizeChanged.connect(self._on_contents_size_changed)
frame.initialLayoutCompleted.connect(self._on_history_trigger)
page.navigation_request.connect(self._on_navigation_request)
def event_target(self):
return self._widget

View File

@ -753,7 +753,7 @@ class TabbedBrowser(QWidget):
self.widget.update_tab_title(idx)
if idx == self.widget.currentIndex():
self._update_window_title()
tab.handle_auto_insert_mode(ok)
tab.private_api.handle_auto_insert_mode(ok)
@pyqtSlot()
def on_scroll_pos_changed(self):

View File

@ -241,6 +241,12 @@ class FakeWebTabAudio(browsertab.AbstractAudio):
return False
class FakeWebTabPrivate:
def shutdown(self):
pass
class FakeWebTab(browsertab.AbstractTab):
"""Fake AbstractTab to use in tests."""
@ -258,6 +264,7 @@ class FakeWebTab(browsertab.AbstractTab):
can_go_forward=can_go_forward)
self.scroller = FakeWebTabScroller(self, scroll_pos_perc)
self.audio = FakeWebTabAudio(self)
self.private_api = FakeWebTabPrivate()
wrapped = QWidget()
self._layout.wrap(self, wrapped)
@ -274,9 +281,6 @@ class FakeWebTab(browsertab.AbstractTab):
def load_status(self):
return self._load_status
def shutdown(self):
pass
def icon(self):
return QIcon()