Add tab.caret.follow_selected()

This commit is contained in:
Florian Bruhin 2016-07-04 13:35:38 +02:00
parent 1148184892
commit 4d650c8dfd
4 changed files with 45 additions and 40 deletions

View File

@ -25,7 +25,6 @@ import sys
import shlex import shlex
import posixpath import posixpath
import functools import functools
import xml.etree.ElementTree
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWidgets import QApplication, QTabBar from PyQt5.QtWidgets import QApplication, QTabBar
@ -40,6 +39,7 @@ import pygments.formatters
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
from qutebrowser.config import config, configexc from qutebrowser.config import config, configexc
from qutebrowser.browser import urlmarks from qutebrowser.browser import urlmarks
from qutebrowser.browser import tab as tabmod
from qutebrowser.browser.webkit import webelem, inspector, downloads, mhtml from qutebrowser.browser.webkit import webelem, inspector, downloads, mhtml
from qutebrowser.keyinput import modeman from qutebrowser.keyinput import modeman
from qutebrowser.utils import (message, usertypes, log, qtutils, urlutils, from qutebrowser.utils import (message, usertypes, log, qtutils, urlutils,
@ -1107,30 +1107,10 @@ class CommandDispatcher:
Args: Args:
tab: Load the selected link in a new tab. tab: Load the selected link in a new tab.
""" """
widget = self._current_widget() try:
if not widget.caret.has_selection(): self._current_widget().caret.follow_selected(tab=tab)
return except tabmod.WebTabError as e:
if QWebSettings.globalSettings().testAttribute( raise cmdexc.CommandError(str(e))
QWebSettings.JavascriptEnabled):
if tab:
widget.set_open_target(usertypes.ClickTarget.tab)
widget.run_js_async(
'window.getSelection().anchorNode.parentNode.click()')
else:
selection = widget.caret.selection(html=True)
try:
selected_element = xml.etree.ElementTree.fromstring(
'<html>{}</html>'.format(selection)).find('a')
except xml.etree.ElementTree.ParseError:
raise cmdexc.CommandError('Could not parse selected element!')
if selected_element is not None:
try:
url = selected_element.attrib['href']
except KeyError:
raise cmdexc.CommandError('Anchor element without href!')
url = self._current_url().resolved(QUrl(url))
self._open(url, tab)
@cmdutils.register(instance='command-dispatcher', name='inspector', @cmdutils.register(instance='command-dispatcher', name='inspector',
scope='window') scope='window')

View File

@ -32,6 +32,10 @@ from qutebrowser.utils import utils, objreg, usertypes
tab_id_gen = itertools.count(0) tab_id_gen = itertools.count(0)
class WebTabError(Exception):
"""Base class for various errors."""
class WrapperLayout(QLayout): class WrapperLayout(QLayout):
@ -188,8 +192,9 @@ class AbstractCaret(QObject):
"""Attribute of AbstractTab for caret browsing.""" """Attribute of AbstractTab for caret browsing."""
def __init__(self, win_id, parent=None): def __init__(self, win_id, tab, parent=None):
super().__init__(parent) super().__init__(parent)
self._tab = tab
self._win_id = win_id self._win_id = win_id
self._widget = None self._widget = None
self.selection_enabled = False self.selection_enabled = False
@ -261,6 +266,9 @@ class AbstractCaret(QObject):
def selection(self, html=False): def selection(self, html=False):
raise NotImplementedError raise NotImplementedError
def follow_selected(self, tab=False):
raise NotImplementedError
class AbstractScroller(QObject): class AbstractScroller(QObject):
@ -398,7 +406,7 @@ class AbstractTab(QWidget):
super().__init__(parent) super().__init__(parent)
# self.history = AbstractHistory(self) # self.history = AbstractHistory(self)
# self.scroll = AbstractScroller(parent=self) # self.scroll = AbstractScroller(parent=self)
# self.caret = AbstractCaret(win_id=win_id, parent=self) # self.caret = AbstractCaret(win_id=win_id, tab=self, parent=self)
# self.zoom = AbstractZoom(win_id=win_id) # self.zoom = AbstractZoom(win_id=win_id)
# self.search = AbstractSearch(parent=self) # self.search = AbstractSearch(parent=self)
self._layout = None self._layout = None
@ -462,10 +470,6 @@ class AbstractTab(QWidget):
def icon(self): def icon(self):
raise NotImplementedError raise NotImplementedError
def set_open_target(self, target):
"""Select where the next navigation request should open."""
raise NotImplementedError
def __repr__(self): def __repr__(self):
url = utils.elide(self.cur_url.toDisplayString(QUrl.EncodeUnicode), url = utils.elide(self.cur_url.toDisplayString(QUrl.EncodeUnicode),
100) 100)

View File

@ -102,7 +102,7 @@ class WebEngineViewTab(tab.AbstractTab):
widget = QWebEngineView() widget = QWebEngineView()
self.history = WebEngineHistory(self) self.history = WebEngineHistory(self)
self.scroll = WebEngineScroller() self.scroll = WebEngineScroller()
self.caret = WebEngineCaret(win_id=win_id, parent=self) self.caret = WebEngineCaret(win_id=win_id, tab=self, parent=self)
self.zoom = WebEngineZoom(win_id=win_id, parent=self) self.zoom = WebEngineZoom(win_id=win_id, parent=self)
self.search = WebEngineSearch(parent=self) self.search = WebEngineSearch(parent=self)
self._set_widget(widget) self._set_widget(widget)
@ -155,9 +155,6 @@ class WebEngineViewTab(tab.AbstractTab):
def icon(self): def icon(self):
return self._widget.icon() return self._widget.icon()
def set_open_target(self, target):
raise NotImplementedError
def _connect_signals(self): def _connect_signals(self):
view = self._widget view = self._widget
page = view.page() page = view.page()

View File

@ -20,8 +20,9 @@
"""Wrapper over our (QtWebKit) WebView.""" """Wrapper over our (QtWebKit) WebView."""
import sys import sys
import xml.etree.ElementTree
from PyQt5.QtCore import pyqtSlot, Qt, QEvent from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QUrl
from PyQt5.QtGui import QKeyEvent from PyQt5.QtGui import QKeyEvent
from PyQt5.QtWebKitWidgets import QWebPage from PyQt5.QtWebKitWidgets import QWebPage
from PyQt5.QtWebKit import QWebSettings from PyQt5.QtWebKit import QWebSettings
@ -260,6 +261,32 @@ class WebViewCaret(tab.AbstractCaret):
return self._widget.selectedHtml() return self._widget.selectedHtml()
return self._widget.selectedText() return self._widget.selectedText()
def follow_selected(self, *, tab=False):
if not self.has_selection():
return
if QWebSettings.globalSettings().testAttribute(
QWebSettings.JavascriptEnabled):
if tab:
self._widget.page().open_target = usertypes.ClickTarget.tab
self._tab.run_js_async(
'window.getSelection().anchorNode.parentNode.click()')
else:
selection = self.selection(html=True)
try:
selected_element = xml.etree.ElementTree.fromstring(
'<html>{}</html>'.format(selection)).find('a')
except xml.etree.ElementTree.ParseError:
raise tab.WebTabError('Could not parse selected element!')
if selected_element is not None:
try:
url = selected_element.attrib['href']
except KeyError:
raise tab.WebTabError('Anchor element without href!')
url = self._tab.cur_url.resolved(QUrl(url))
# FIXME(refactoring) does this open in a new tab?
self._tab.openurl(url)
class WebViewZoom(tab.AbstractZoom): class WebViewZoom(tab.AbstractZoom):
@ -411,7 +438,7 @@ class WebViewTab(tab.AbstractTab):
widget = webview.WebView(win_id, self.tab_id, tab=self) widget = webview.WebView(win_id, self.tab_id, tab=self)
self.history = WebViewHistory(self) self.history = WebViewHistory(self)
self.scroll = WebViewScroller(parent=self) self.scroll = WebViewScroller(parent=self)
self.caret = WebViewCaret(win_id=win_id, parent=self) self.caret = WebViewCaret(win_id=win_id, tab=self, parent=self)
self.zoom = WebViewZoom(win_id=win_id, parent=self) self.zoom = WebViewZoom(win_id=win_id, parent=self)
self.search = WebViewSearch(parent=self) self.search = WebViewSearch(parent=self)
self._set_widget(widget) self._set_widget(widget)
@ -464,9 +491,6 @@ class WebViewTab(tab.AbstractTab):
def title(self): def title(self):
return self._widget.title() return self._widget.title()
def set_open_target(self, target):
self._widget.page().open_target = target
def _connect_signals(self): def _connect_signals(self):
view = self._widget view = self._widget
page = view.page() page = view.page()