Implement modes and hint input.
This commit is contained in:
parent
5a3966ca82
commit
d7b87e09c9
@ -57,6 +57,7 @@ from qutebrowser.widgets.mainwindow import MainWindow
|
|||||||
from qutebrowser.widgets.crash import CrashDialog
|
from qutebrowser.widgets.crash import CrashDialog
|
||||||
from qutebrowser.commands.keys import CommandKeyParser
|
from qutebrowser.commands.keys import CommandKeyParser
|
||||||
from qutebrowser.commands.parsers import CommandParser, SearchParser
|
from qutebrowser.commands.parsers import CommandParser, SearchParser
|
||||||
|
from qutebrowser.browser.hints import HintKeyParser
|
||||||
from qutebrowser.utils.appdirs import AppDirs
|
from qutebrowser.utils.appdirs import AppDirs
|
||||||
from qutebrowser.utils.misc import dotted_getattr
|
from qutebrowser.utils.misc import dotted_getattr
|
||||||
from qutebrowser.utils.debug import set_trace # pylint: disable=unused-import
|
from qutebrowser.utils.debug import set_trace # pylint: disable=unused-import
|
||||||
@ -74,13 +75,14 @@ class QuteBrowser(QApplication):
|
|||||||
Attributes:
|
Attributes:
|
||||||
mainwindow: The MainWindow QWidget.
|
mainwindow: The MainWindow QWidget.
|
||||||
commandparser: The main CommandParser instance.
|
commandparser: The main CommandParser instance.
|
||||||
keyparser: The main CommandKeyParser instance.
|
|
||||||
searchparser: The main SearchParser instance.
|
searchparser: The main SearchParser instance.
|
||||||
|
_keyparsers: A mapping from modes to keyparsers.
|
||||||
_dirs: AppDirs instance for config/cache directories.
|
_dirs: AppDirs instance for config/cache directories.
|
||||||
_args: ArgumentParser instance.
|
_args: ArgumentParser instance.
|
||||||
_timers: List of used QTimers so they don't get GCed.
|
_timers: List of used QTimers so they don't get GCed.
|
||||||
_shutting_down: True if we're currently shutting down.
|
_shutting_down: True if we're currently shutting down.
|
||||||
_quit_status: The current quitting status.
|
_quit_status: The current quitting status.
|
||||||
|
_mode: The mode we're currently in.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -88,6 +90,7 @@ class QuteBrowser(QApplication):
|
|||||||
self._quit_status = {}
|
self._quit_status = {}
|
||||||
self._timers = []
|
self._timers = []
|
||||||
self._shutting_down = False
|
self._shutting_down = False
|
||||||
|
self._mode = None
|
||||||
|
|
||||||
sys.excepthook = self._exception_hook
|
sys.excepthook = self._exception_hook
|
||||||
|
|
||||||
@ -108,40 +111,16 @@ class QuteBrowser(QApplication):
|
|||||||
|
|
||||||
self.commandparser = CommandParser()
|
self.commandparser = CommandParser()
|
||||||
self.searchparser = SearchParser()
|
self.searchparser = SearchParser()
|
||||||
self.keyparser = CommandKeyParser(self)
|
self._keyparsers = {
|
||||||
|
"normal": CommandKeyParser(self),
|
||||||
|
"hint": HintKeyParser(self),
|
||||||
|
}
|
||||||
self._init_cmds()
|
self._init_cmds()
|
||||||
self.mainwindow = MainWindow()
|
self.mainwindow = MainWindow()
|
||||||
|
|
||||||
self.setQuitOnLastWindowClosed(False)
|
self.setQuitOnLastWindowClosed(False)
|
||||||
self.lastWindowClosed.connect(self.shutdown)
|
|
||||||
self.mainwindow.tabs.keypress.connect(
|
self._connect_signals()
|
||||||
self.mainwindow.status.keypress)
|
self.set_mode("normal")
|
||||||
self.mainwindow.tabs.keypress.connect(self.keyparser.handle)
|
|
||||||
self.keyparser.set_cmd_text.connect(
|
|
||||||
self.mainwindow.status.cmd.set_cmd_text)
|
|
||||||
self.mainwindow.tabs.set_cmd_text.connect(
|
|
||||||
self.mainwindow.status.cmd.set_cmd_text)
|
|
||||||
self.mainwindow.tabs.quit.connect(self.shutdown)
|
|
||||||
self.mainwindow.status.cmd.got_cmd.connect(self.commandparser.run)
|
|
||||||
self.mainwindow.status.cmd.got_search.connect(self.searchparser.search)
|
|
||||||
self.mainwindow.status.cmd.got_search_rev.connect(
|
|
||||||
self.searchparser.search_rev)
|
|
||||||
self.mainwindow.status.cmd.returnPressed.connect(
|
|
||||||
self.mainwindow.tabs.setFocus)
|
|
||||||
self.searchparser.do_search.connect(
|
|
||||||
self.mainwindow.tabs.cur.search)
|
|
||||||
self.keyparser.keystring_updated.connect(
|
|
||||||
self.mainwindow.status.keystring.setText)
|
|
||||||
message.bridge.error.connect(self.mainwindow.status.disp_error)
|
|
||||||
message.bridge.info.connect(self.mainwindow.status.disp_tmp_text)
|
|
||||||
self.config.style_changed.connect(style.invalidate_caches)
|
|
||||||
self.config.changed.connect(self.mainwindow.tabs.on_config_changed)
|
|
||||||
self.config.changed.connect(
|
|
||||||
self.mainwindow.completion.on_config_changed)
|
|
||||||
self.config.changed.connect(self.mainwindow.on_config_changed)
|
|
||||||
self.config.changed.connect(config.cmd_history.on_config_changed)
|
|
||||||
self.config.changed.connect(websettings.on_config_changed)
|
|
||||||
self.config.changed.connect(self.keyparser.on_config_changed)
|
|
||||||
|
|
||||||
self.mainwindow.show()
|
self.mainwindow.show()
|
||||||
self._python_hacks()
|
self._python_hacks()
|
||||||
@ -241,6 +220,45 @@ class QuteBrowser(QApplication):
|
|||||||
timer.timeout.connect(lambda: None)
|
timer.timeout.connect(lambda: None)
|
||||||
self._timers.append(timer)
|
self._timers.append(timer)
|
||||||
|
|
||||||
|
def _connect_signals(self):
|
||||||
|
"""Connect all signals to their slots."""
|
||||||
|
self.lastWindowClosed.connect(self.shutdown)
|
||||||
|
self.mainwindow.tabs.keypress.connect(
|
||||||
|
self.mainwindow.status.keypress)
|
||||||
|
self._keyparsers["normal"].set_cmd_text.connect(
|
||||||
|
self.mainwindow.status.cmd.set_cmd_text)
|
||||||
|
self.mainwindow.tabs.set_cmd_text.connect(
|
||||||
|
self.mainwindow.status.cmd.set_cmd_text)
|
||||||
|
self.mainwindow.tabs.quit.connect(self.shutdown)
|
||||||
|
self.mainwindow.status.cmd.got_cmd.connect(self.commandparser.run)
|
||||||
|
self.mainwindow.status.cmd.got_search.connect(self.searchparser.search)
|
||||||
|
self.mainwindow.status.cmd.got_search_rev.connect(
|
||||||
|
self.searchparser.search_rev)
|
||||||
|
self.mainwindow.status.cmd.returnPressed.connect(
|
||||||
|
self.mainwindow.tabs.setFocus)
|
||||||
|
self.searchparser.do_search.connect(
|
||||||
|
self.mainwindow.tabs.cur.search)
|
||||||
|
self._keyparsers["normal"].keystring_updated.connect(
|
||||||
|
self.mainwindow.status.keystring.setText)
|
||||||
|
self._keyparsers["hint"].fire_hint.connect(
|
||||||
|
self.mainwindow.tabs.cur.fire_hint)
|
||||||
|
self._keyparsers["hint"].keystring_updated.connect(
|
||||||
|
self.mainwindow.tabs.cur.handle_hint_key)
|
||||||
|
self.mainwindow.tabs.hint_strings_updated.connect(
|
||||||
|
self._keyparsers["hint"].on_hint_strings_updated)
|
||||||
|
self.mainwindow.tabs.set_mode.connect(self.set_mode)
|
||||||
|
message.bridge.error.connect(self.mainwindow.status.disp_error)
|
||||||
|
message.bridge.info.connect(self.mainwindow.status.disp_tmp_text)
|
||||||
|
self.config.style_changed.connect(style.invalidate_caches)
|
||||||
|
self.config.changed.connect(self.mainwindow.tabs.on_config_changed)
|
||||||
|
self.config.changed.connect(
|
||||||
|
self.mainwindow.completion.on_config_changed)
|
||||||
|
self.config.changed.connect(self.mainwindow.on_config_changed)
|
||||||
|
self.config.changed.connect(config.cmd_history.on_config_changed)
|
||||||
|
self.config.changed.connect(websettings.on_config_changed)
|
||||||
|
self.config.changed.connect(
|
||||||
|
self._keyparsers["normal"].on_config_changed)
|
||||||
|
|
||||||
def _recover_pages(self):
|
def _recover_pages(self):
|
||||||
"""Try to recover all open pages.
|
"""Try to recover all open pages.
|
||||||
|
|
||||||
@ -340,6 +358,20 @@ class QuteBrowser(QApplication):
|
|||||||
logging.debug("maybe_quit quitting.")
|
logging.debug("maybe_quit quitting.")
|
||||||
self.quit()
|
self.quit()
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def set_mode(self, mode):
|
||||||
|
"""Set a key input mode.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mode: The new mode to set, as an index for self._keyparsers.
|
||||||
|
"""
|
||||||
|
if self._mode is not None:
|
||||||
|
oldhandler = self._keyparsers[self._mode]
|
||||||
|
self.mainwindow.tabs.keypress.disconnect(oldhandler.handle)
|
||||||
|
handler = self._keyparsers[mode]
|
||||||
|
self.mainwindow.tabs.keypress.connect(handler.handle)
|
||||||
|
self._mode = mode
|
||||||
|
|
||||||
@cmdutils.register(instance='', maxsplit=0)
|
@cmdutils.register(instance='', maxsplit=0)
|
||||||
def pyeval(self, s):
|
def pyeval(self, s):
|
||||||
"""Evaluate a python string and display the results as a webpage.
|
"""Evaluate a python string and display the results as a webpage.
|
||||||
|
@ -175,6 +175,16 @@ class CurCommandDispatcher(QObject):
|
|||||||
"""
|
"""
|
||||||
self._tabs.currentWidget().hintmanager.start(mode)
|
self._tabs.currentWidget().hintmanager.start(mode)
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def handle_hint_key(self, keystr):
|
||||||
|
"""Handle a new hint keypress."""
|
||||||
|
self._tabs.currentWidget().hintmanager.handle_partial_key(keystr)
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def fire_hint(self, keystr):
|
||||||
|
"""Fire a completed hint."""
|
||||||
|
self._tabs.currentWidget().hintmanager.fire(keystr)
|
||||||
|
|
||||||
@pyqtSlot(str, int)
|
@pyqtSlot(str, int)
|
||||||
def search(self, text, flags):
|
def search(self, text, flags):
|
||||||
"""Search for text in the current page.
|
"""Search for text in the current page.
|
||||||
|
@ -19,10 +19,41 @@
|
|||||||
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtSignal, QObject
|
||||||
|
|
||||||
import qutebrowser.config.config as config
|
import qutebrowser.config.config as config
|
||||||
|
from qutebrowser.utils.keyparser import KeyParser
|
||||||
|
|
||||||
|
|
||||||
class HintManager:
|
class HintKeyParser(KeyParser):
|
||||||
|
|
||||||
|
"""KeyParser for hints.
|
||||||
|
|
||||||
|
Class attributes:
|
||||||
|
supports_count: If the keyparser should support counts.
|
||||||
|
|
||||||
|
Signals:
|
||||||
|
fire_hint: When a hint keybinding was completed.
|
||||||
|
Arg: the keystring/hint string pressed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
supports_count = False
|
||||||
|
fire_hint = pyqtSignal(str)
|
||||||
|
|
||||||
|
def execute(self, cmdstr, count=None):
|
||||||
|
"""Handle a completed keychain."""
|
||||||
|
self.fire_hint.emit(cmdstr)
|
||||||
|
|
||||||
|
def on_hint_strings_updated(self, strings):
|
||||||
|
"""Handler for HintManager's hint_strings_updated.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
strings: A list of hint strings.
|
||||||
|
"""
|
||||||
|
self.bindings = {s: s for s in strings}
|
||||||
|
|
||||||
|
|
||||||
|
class HintManager(QObject):
|
||||||
|
|
||||||
"""Manage drawing hints over links or other elements.
|
"""Manage drawing hints over links or other elements.
|
||||||
|
|
||||||
@ -34,6 +65,10 @@ class HintManager:
|
|||||||
_frame: The QWebFrame to use.
|
_frame: The QWebFrame to use.
|
||||||
_elems: The elements we're hinting currently.
|
_elems: The elements we're hinting currently.
|
||||||
_labels: The label elements.
|
_labels: The label elements.
|
||||||
|
|
||||||
|
Signals:
|
||||||
|
hint_strings_updated: Emitted when the possible hint strings changed.
|
||||||
|
set_mode: Emitted when the input mode should be changed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
SELECTORS = {
|
SELECTORS = {
|
||||||
@ -60,12 +95,16 @@ class HintManager:
|
|||||||
top: {top}px;
|
top: {top}px;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
hint_strings_updated = pyqtSignal(list)
|
||||||
|
set_mode = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, frame):
|
def __init__(self, frame):
|
||||||
"""Constructor.
|
"""Constructor.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
frame: The QWebFrame to use for finding elements and drawing.
|
frame: The QWebFrame to use for finding elements and drawing.
|
||||||
"""
|
"""
|
||||||
|
super().__init__(frame)
|
||||||
self._frame = frame
|
self._frame = frame
|
||||||
self._elems = []
|
self._elems = []
|
||||||
self._labels = []
|
self._labels = []
|
||||||
@ -196,6 +235,8 @@ class HintManager:
|
|||||||
strings = self._hint_strings(self._elems)
|
strings = self._hint_strings(self._elems)
|
||||||
for e, string in zip(self._elems, strings):
|
for e, string in zip(self._elems, strings):
|
||||||
self._draw_label(e, string)
|
self._draw_label(e, string)
|
||||||
|
self.hint_strings_updated.emit(strings)
|
||||||
|
self.set_mode.emit("hint")
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stop hinting."""
|
"""Stop hinting."""
|
||||||
@ -203,3 +244,12 @@ class HintManager:
|
|||||||
e.removeFromDocument()
|
e.removeFromDocument()
|
||||||
self._elems = None
|
self._elems = None
|
||||||
self._labels = []
|
self._labels = []
|
||||||
|
self.set_mode.emit("normal")
|
||||||
|
|
||||||
|
def handle_partial_key(self, keystr):
|
||||||
|
"""Handle a new partial keypress."""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def fire(self, keystr):
|
||||||
|
"""Fire a completed hint."""
|
||||||
|
raise NotImplementedError
|
||||||
|
@ -37,9 +37,11 @@ class CommandKeyParser(KeyParser):
|
|||||||
|
|
||||||
"""Keyparser for command bindings.
|
"""Keyparser for command bindings.
|
||||||
|
|
||||||
|
Class attributes:
|
||||||
|
supports_count: If the keyparser should support counts.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
commandparser: Commandparser instance.
|
commandparser: Commandparser instance.
|
||||||
supports_count: If the keyparser should support counts.
|
|
||||||
|
|
||||||
Signals:
|
Signals:
|
||||||
set_cmd_text: Emitted when the statusbar should set a partial command.
|
set_cmd_text: Emitted when the statusbar should set a partial command.
|
||||||
|
@ -67,6 +67,10 @@ class TabbedBrowser(TabWidget):
|
|||||||
cur_scroll_perc_changed: Scroll percentage of current tab changed.
|
cur_scroll_perc_changed: Scroll percentage of current tab changed.
|
||||||
arg 1: x-position in %.
|
arg 1: x-position in %.
|
||||||
arg 2: y-position in %.
|
arg 2: y-position in %.
|
||||||
|
hint_strings_updated: Hint strings were updated.
|
||||||
|
arg: A list of hint strings.
|
||||||
|
set_mode: The input mode should be changed.
|
||||||
|
arg: The new mode as a string.
|
||||||
keypress: A key was pressed.
|
keypress: A key was pressed.
|
||||||
arg: The QKeyEvent leading to the keypress.
|
arg: The QKeyEvent leading to the keypress.
|
||||||
shutdown_complete: The shuttdown is completed.
|
shutdown_complete: The shuttdown is completed.
|
||||||
@ -84,7 +88,9 @@ class TabbedBrowser(TabWidget):
|
|||||||
cur_url_changed = pyqtSignal('QUrl')
|
cur_url_changed = pyqtSignal('QUrl')
|
||||||
cur_link_hovered = pyqtSignal(str, str, str)
|
cur_link_hovered = pyqtSignal(str, str, str)
|
||||||
cur_scroll_perc_changed = pyqtSignal(int, int)
|
cur_scroll_perc_changed = pyqtSignal(int, int)
|
||||||
|
hint_strings_updated = pyqtSignal(list)
|
||||||
set_cmd_text = pyqtSignal(str)
|
set_cmd_text = pyqtSignal(str)
|
||||||
|
set_mode = pyqtSignal(str)
|
||||||
keypress = pyqtSignal('QKeyEvent')
|
keypress = pyqtSignal('QKeyEvent')
|
||||||
shutdown_complete = pyqtSignal()
|
shutdown_complete = pyqtSignal()
|
||||||
quit = pyqtSignal()
|
quit = pyqtSignal()
|
||||||
@ -238,6 +244,8 @@ class TabbedBrowser(TabWidget):
|
|||||||
tab.temp_message.connect(self._filter.create(self.cur_temp_message))
|
tab.temp_message.connect(self._filter.create(self.cur_temp_message))
|
||||||
tab.urlChanged.connect(self._filter.create(self.cur_url_changed))
|
tab.urlChanged.connect(self._filter.create(self.cur_url_changed))
|
||||||
tab.titleChanged.connect(self._titleChanged_handler)
|
tab.titleChanged.connect(self._titleChanged_handler)
|
||||||
|
tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated)
|
||||||
|
tab.hintmanager.set_mode.connect(self.set_mode)
|
||||||
# FIXME sometimes this doesn't load
|
# FIXME sometimes this doesn't load
|
||||||
tab.show()
|
tab.show()
|
||||||
tab.open_tab.connect(self.tabopen)
|
tab.open_tab.connect(self.tabopen)
|
||||||
|
Loading…
Reference in New Issue
Block a user