Use object registry for hintmanager.

This commit is contained in:
Florian Bruhin 2014-09-25 07:44:11 +02:00
parent e8ce45c440
commit 78949a8c1b
6 changed files with 72 additions and 133 deletions

View File

@ -404,13 +404,6 @@ class Application(QApplication):
status.keystring.setText)
tabs.got_cmd.connect(self._commandrunner.run_safely)
# hints
kp[utypes.KeyMode.hint].fire_hint.connect(tabs.fire_hint)
kp[utypes.KeyMode.hint].filter_hints.connect(tabs.filter_hints)
kp[utypes.KeyMode.hint].keystring_updated.connect(tabs.handle_hint_key)
tabs.hint_strings_updated.connect(
kp[utypes.KeyMode.hint].on_hint_strings_updated)
# messages
message_bridge.s_error.connect(status.disp_error)
message_bridge.s_info.connect(status.disp_temp_text)

View File

@ -302,55 +302,6 @@ class CommandDispatcher:
for _ in range(count):
self._current_widget().go_forward()
@cmdutils.register(instance='command-dispatcher')
def hint(self, group=webelem.Group.all, target=hints.Target.normal,
*args: {'nargs': '*'}):
"""Start hinting.
Args:
group: The hinting mode to use.
- `all`: All clickable elements.
- `links`: Only links.
- `images`: Only images.
target: What to do with the selected element.
- `normal`: Open the link in the current tab.
- `tab`: Open the link in a new tab.
- `tab-bg`: Open the link in a new background tab.
- `yank`: Yank the link to the clipboard.
- `yank-primary`: Yank the link to the primary selection.
- `fill`: Fill the commandline with the command given as
argument.
- `rapid`: Open the link in a new tab and stay in hinting mode.
- `download`: Download the link.
- `userscript`: Call an userscript with `$QUTE_URL` set to the
link.
- `spawn`: Spawn a command.
*args: Arguments for spawn/userscript/fill.
- With `spawn`: The executable and arguments to spawn.
`{hint-url}` will get replaced by the selected
URL.
- With `userscript`: The userscript to execute.
- With `fill`: The command to fill the statusbar with.
`{hint-url}` will get replaced by the selected
URL.
"""
widget = self._current_widget()
frame = widget.page().mainFrame()
if frame is None:
raise cmdexc.CommandError("No frame focused!")
widget.hintmanager.start(frame, self._current_url(), group, target,
*args)
@cmdutils.register(instance='command-dispatcher', hide=True)
def follow_hint(self):
"""Follow the currently selected hint."""
self._current_widget().hintmanager.follow_hint()
def _navigate_incdec(self, url, tab, incdec):
"""Helper method for :navigate when `where' is increment/decrement.
@ -424,12 +375,11 @@ class CommandDispatcher:
url = self._current_url()
if frame is None:
raise cmdexc.CommandError("No frame focused!")
hintmanager = objreg.get('hintmanager', scope='tab')
if where == 'prev':
widget.hintmanager.follow_prevnext(frame, url, prev=True,
newtab=tab)
hintmanager.follow_prevnext(frame, url, prev=True, newtab=tab)
elif where == 'next':
widget.hintmanager.follow_prevnext(frame, url, prev=False,
newtab=tab)
hintmanager.follow_prevnext(frame, url, prev=False, newtab=tab)
elif where == 'up':
self._navigate_up(url, tab)
elif where in ('decrement', 'increment'):

View File

@ -30,9 +30,8 @@ from PyQt5.QtWidgets import QApplication
from qutebrowser.config import config
from qutebrowser.keyinput import modeman
from qutebrowser.browser import webelem
from qutebrowser.commands import userscripts, cmdexc
from qutebrowser.utils import (usertypes, log, qtutils, message, objreg,
cmdutils)
from qutebrowser.commands import userscripts, cmdexc, cmdutils
from qutebrowser.utils import usertypes, log, qtutils, message, objreg
ElemTuple = collections.namedtuple('ElemTuple', 'elem, label')
@ -96,13 +95,8 @@ class HintManager(QObject):
_context: The HintContext for the current invocation.
Signals:
hint_strings_updated: Emitted when the possible hint strings changed.
arg: A list of hint strings.
mouse_event: Mouse event to be posted in the web view.
arg: A QMouseEvent
openurl: Open a new URL
arg 0: URL to open as QUrl.
arg 1: True if it should be opened in a new tab, else False.
set_open_target: Set a new target to open the links in.
"""
@ -133,9 +127,7 @@ class HintManager(QObject):
Target.spawn: "Spawn command via hint...",
}
hint_strings_updated = pyqtSignal(list)
mouse_event = pyqtSignal('QMouseEvent')
openurl = pyqtSignal('QUrl', bool)
set_open_target = pyqtSignal(str)
def __init__(self, parent=None):
@ -492,7 +484,8 @@ class HintManager(QObject):
for e, string in zip(elems, strings):
label = self._draw_label(e, string)
self._context.elems[string] = ElemTuple(e, label)
self.hint_strings_updated.emit(strings)
keyparser = objreg.get('keyparsers')[usertypes.KeyMode.hint]
keyparser.update_bindings(strings)
def follow_prevnext(self, frame, baseurl, prev=False, newtab=False):
"""Click a "previous"/"next" element on the page.
@ -511,31 +504,60 @@ class HintManager(QObject):
if url is None:
raise cmdexc.CommandError("No {} links found!".format(
"prev" if prev else "forward"))
self.openurl.emit(url, newtab)
qtutils.ensure_valid(url)
if newtab:
objreg.get('tabbed-browser').tabopen(url, background=False)
else:
objreg.get('webview', scope='tab').openurl(url)
def start(self, mainframe, baseurl, group=webelem.Group.all,
target=Target.normal, *args):
@cmdutils.register(instance='hintmanager', scope='tab', name='hint')
def start(self, group=webelem.Group.all, target=Target.normal,
*args: {'nargs': '*'}):
"""Start hinting.
Args:
mainframe: The main QWebFrame.
baseurl: URL of the current page.
group: Which group of elements to hint.
target: What to do with the link. See attribute docstring.
*args: Arguments for userscript/download
group: The hinting mode to use.
Emit:
hint_strings_updated: Emitted to update keypraser.
- `all`: All clickable elements.
- `links`: Only links.
- `images`: Only images.
target: What to do with the selected element.
- `normal`: Open the link in the current tab.
- `tab`: Open the link in a new tab.
- `tab-bg`: Open the link in a new background tab.
- `yank`: Yank the link to the clipboard.
- `yank-primary`: Yank the link to the primary selection.
- `fill`: Fill the commandline with the command given as
argument.
- `rapid`: Open the link in a new tab and stay in hinting mode.
- `download`: Download the link.
- `userscript`: Call an userscript with `$QUTE_URL` set to the
link.
- `spawn`: Spawn a command.
*args: Arguments for spawn/userscript/fill.
- With `spawn`: The executable and arguments to spawn.
`{hint-url}` will get replaced by the selected
URL.
- With `userscript`: The userscript to execute.
- With `fill`: The command to fill the statusbar with.
`{hint-url}` will get replaced by the selected
URL.
"""
self._check_args(target, *args)
tabbed_browser = objreg.get('tabbed-browser')
widget = tabbed_browser.currentWidget()
if widget is None:
raise cmdexc.CommandError("No WebView available yet!")
mainframe = widget.page().mainFrame()
if mainframe is None:
# This should never happen since we check frame before calling
# start. But since we had a bug where frame is None in
# on_mode_left, we are extra careful here.
raise ValueError("start() was called with frame=None")
raise cmdexc.CommandError("No frame focused!")
self._check_args(target, *args)
self._context = HintContext()
self._context.target = target
self._context.baseurl = baseurl
self._context.baseurl = tabbed_browser.current_url()
self._context.frames = webelem.get_child_frames(mainframe)
self._context.args = args
self._init_elements(mainframe, group)
@ -634,6 +656,7 @@ class HintManager(QObject):
if self._context.target != Target.rapid:
modeman.maybe_leave(usertypes.KeyMode.hint, 'followed')
@cmdutils.register(instance='hintmanager', scope='tab', hide=True)
def follow_hint(self):
"""Follow the currently selected hint."""
if not self._context.to_follow:

View File

@ -23,12 +23,12 @@ Module attributes:
STARTCHARS: Possible chars for starting a commandline input.
"""
from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
from qutebrowser.utils import message
from qutebrowser.config import config
from qutebrowser.keyinput import keyparser
from qutebrowser.utils import usertypes, log
from qutebrowser.utils import usertypes, log, objreg
STARTCHARS = ":/?"
@ -80,25 +80,17 @@ class HintKeyParser(keyparser.CommandKeyParser):
"""KeyChainParser for hints.
Signals:
fire_hint: When a hint keybinding was completed.
Arg: the keystring/hint string pressed.
filter_hints: When the filter text changed.
Arg: the text to filter hints with.
Attributes:
_filtertext: The text to filter with.
_last_press: The nature of the last keypress, a LastPress member.
"""
fire_hint = pyqtSignal(str)
filter_hints = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent, supports_count=False, supports_chains=True)
self._filtertext = ''
self._last_press = LastPress.none
self.read_config('hint')
self.keystring_updated.connect(self.on_keystring_updated)
def _handle_special_key(self, e):
"""Override _handle_special_key to handle string filtering.
@ -112,11 +104,11 @@ class HintKeyParser(keyparser.CommandKeyParser):
True if event has been handled, False otherwise.
Emit:
filter_hints: Emitted when filter string has changed.
keystring_updated: Emitted when keystring has been changed.
"""
log.keyboard.debug("Got special key 0x{:x} text {}".format(
e.key(), e.text()))
hintmanager = objreg.get('hintmanager', scope='tab')
if e.key() == Qt.Key_Backspace:
log.keyboard.debug("Got backspace, mode {}, filtertext '{}', "
"keystring '{}'".format(self._last_press,
@ -124,7 +116,7 @@ class HintKeyParser(keyparser.CommandKeyParser):
self._keystring))
if self._last_press == LastPress.filtertext and self._filtertext:
self._filtertext = self._filtertext[:-1]
self.filter_hints.emit(self._filtertext)
hintmanager.filter_hints(self._filtertext)
return True
elif self._last_press == LastPress.keystring and self._keystring:
self._keystring = self._keystring[:-1]
@ -138,7 +130,7 @@ class HintKeyParser(keyparser.CommandKeyParser):
return super()._handle_special_key(e)
else:
self._filtertext += e.text()
self.filter_hints.emit(self._filtertext)
hintmanager.filter_hints(self._filtertext)
self._last_press = LastPress.filtertext
return True
@ -167,24 +159,25 @@ class HintKeyParser(keyparser.CommandKeyParser):
return self._handle_special_key(e)
def execute(self, cmdstr, keytype, count=None):
"""Handle a completed keychain.
Emit:
fire_hint: Emitted if keytype is chain
"""
"""Handle a completed keychain."""
if not isinstance(keytype, self.Type):
raise TypeError("Type {} is no Type member!".format(keytype))
if keytype == self.Type.chain:
self.fire_hint.emit(cmdstr)
objreg.get('hintmanager', scope='tab').fire(cmdstr)
else:
# execute as command
super().execute(cmdstr, keytype, count)
def on_hint_strings_updated(self, strings):
"""Handler for HintManager's hint_strings_updated.
def update_bindings(self, strings):
"""Update bindings when the hint strings changed.
Args:
strings: A list of hint strings.
"""
self.bindings = {s: s for s in strings}
self._filtertext = ''
@pyqtSlot(str)
def on_keystring_updated(self, keystr):
"""Update hintmanager when the keystring was updated."""
objreg.get('hintmanager', scope='tab').handle_partial_key(keystr)

View File

@ -67,8 +67,6 @@ class TabbedBrowser(tabwidget.TabWidget):
arg 1: x-position in %.
arg 2: y-position in %.
cur_load_status_changed: Loading status of current tab changed.
hint_strings_updated: Hint strings were updated.
arg: A list of hint strings.
quit: The last tab was closed, quit application.
resized: Emitted when the browser window has resized, so the completion
widget can adjust its size to it.
@ -89,7 +87,6 @@ class TabbedBrowser(tabwidget.TabWidget):
cur_scroll_perc_changed = pyqtSignal(int, int)
cur_load_status_changed = pyqtSignal(str)
start_download = pyqtSignal('QNetworkReply*')
hint_strings_updated = pyqtSignal(list)
quit = pyqtSignal()
resized = pyqtSignal('QRect')
got_cmd = pyqtSignal(str)
@ -151,9 +148,6 @@ class TabbedBrowser(tabwidget.TabWidget):
self._filter.create(self.cur_load_status_changed, tab))
tab.url_text_changed.connect(
functools.partial(self.on_url_text_changed, tab))
# hintmanager
tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated)
tab.hintmanager.openurl.connect(self.openurl)
self.cur_load_started.connect(self.on_cur_load_started)
# downloads
page.start_download.connect(self.start_download)
@ -370,21 +364,6 @@ class TabbedBrowser(tabwidget.TabWidget):
# We first want QWebPage to refresh.
QTimer.singleShot(0, check_scroll_pos)
@pyqtSlot(str)
def handle_hint_key(self, keystr):
"""Handle a new hint keypress."""
self.currentWidget().hintmanager.handle_partial_key(keystr)
@pyqtSlot(str)
def fire_hint(self, keystr):
"""Fire a completed hint."""
self.currentWidget().hintmanager.fire(keystr)
@pyqtSlot(str)
def filter_hints(self, filterstr):
"""Filter displayed hints."""
self.currentWidget().hintmanager.filter_hints(filterstr)
@pyqtSlot(str, str)
def on_config_changed(self, section, option):
"""Update tab config when config was changed."""

View File

@ -94,9 +94,10 @@ class WebView(QWebView):
objreg.register('webview', self, registry=self.registry)
page = webpage.BrowserPage(self)
self.setPage(page)
self.hintmanager = hints.HintManager(self)
self.hintmanager.mouse_event.connect(self.on_mouse_event)
self.hintmanager.set_open_target.connect(self.set_force_open_target)
hintmanager = hints.HintManager(self)
hintmanager.mouse_event.connect(self.on_mouse_event)
hintmanager.set_open_target.connect(self.set_force_open_target)
objreg.register('hintmanager', hintmanager, registry=self.registry)
page.linkHovered.connect(self.linkHovered)
page.mainFrame().loadStarted.connect(self.on_load_started)
page.change_title.connect(self.titleChanged)