Lock mode while prompting.

This commit is contained in:
Florian Bruhin 2014-08-04 03:14:14 +02:00
parent 40acc5c6ff
commit 3dc7a1b735
5 changed files with 47 additions and 11 deletions

View File

@ -167,6 +167,14 @@ class HintManager(QObject):
modeman.instance().left.connect(self.on_mode_left) modeman.instance().left.connect(self.on_mode_left)
modeman.instance().entered.connect(self.on_mode_entered) modeman.instance().entered.connect(self.on_mode_entered)
def _cleanup(self):
"""Clean up after hinting."""
for elem in self._context.elems.values():
if not elem.label.isNull():
elem.label.removeFromDocument()
self._context = None
message.instance().set_text('')
def _hint_strings(self, elems): def _hint_strings(self, elems):
"""Calculate the hint strings for elems. """Calculate the hint strings for elems.
@ -507,7 +515,10 @@ class HintManager(QObject):
self._context = ctx self._context = ctx
self._connect_frame_signals() self._connect_frame_signals()
self.hint_strings_updated.emit(strings) self.hint_strings_updated.emit(strings)
modeman.enter(KeyMode.hint, 'HintManager.start') try:
modeman.enter(KeyMode.hint, 'HintManager.start')
except modeman.ModeLockedError:
self._cleanup()
def handle_partial_key(self, keystr): def handle_partial_key(self, keystr):
"""Handle a new partial keypress.""" """Handle a new partial keypress."""
@ -630,8 +641,4 @@ class HintManager(QObject):
# self._context might be None, because the current tab is not # self._context might be None, because the current tab is not
# hinting. # hinting.
return return
for elem in self._context.elems.values(): self._cleanup()
if not elem.label.isNull():
elem.label.removeFromDocument()
self._context = None
message.instance().set_text('')

View File

@ -34,6 +34,11 @@ from qutebrowser.utils.usertypes import KeyMode
from qutebrowser.commands.exceptions import CommandError from qutebrowser.commands.exceptions import CommandError
class ModeLockedError(Exception):
"""Exception raised when the mode is currently locked."""
def instance(): def instance():
"""Get the global modeman instance.""" """Get the global modeman instance."""
return QApplication.instance().modeman return QApplication.instance().modeman
@ -49,6 +54,14 @@ def leave(mode, reason=None):
instance().leave(mode, reason) instance().leave(mode, reason)
def maybe_enter(mode, reason=None):
"""Convenience method to enter 'mode' without exceptions."""
try:
instance().enter(mode, reason)
except ModeLockedError as e:
pass
def maybe_leave(mode, reason=None): def maybe_leave(mode, reason=None):
"""Convenience method to leave 'mode' without exceptions.""" """Convenience method to leave 'mode' without exceptions."""
try: try:
@ -65,6 +78,9 @@ class ModeManager(QObject):
mode: The current mode (readonly property). mode: The current mode (readonly property).
passthrough: A list of modes in which to pass through events. passthrough: A list of modes in which to pass through events.
mainwindow: The mainwindow object mainwindow: The mainwindow object
locked: Whether current mode is locked. This means the current mode can
still be left (then locked will be reset), but no new mode can
be entered while the current mode is active.
_handlers: A dictionary of modes and their handlers. _handlers: A dictionary of modes and their handlers.
_mode_stack: A list of the modes we're currently in, with the active _mode_stack: A list of the modes we're currently in, with the active
one on the right. one on the right.
@ -86,6 +102,7 @@ class ModeManager(QObject):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.mainwindow = None self.mainwindow = None
self.locked = False
self._handlers = {} self._handlers = {}
self.passthrough = [] self.passthrough = []
self._mode_stack = [] self._mode_stack = []
@ -200,6 +217,11 @@ class ModeManager(QObject):
""" """
if not isinstance(mode, KeyMode): if not isinstance(mode, KeyMode):
raise TypeError("Mode {} is no KeyMode member!".format(mode)) raise TypeError("Mode {} is no KeyMode member!".format(mode))
if self.locked:
logger.debug("Not entering mode {} because mode is locked to "
"{}.".format(mode, self.mode))
raise ModeLockedError("Mode is currently locked to {}".format(
self.mode))
logger.debug("Entering mode {}{}".format( logger.debug("Entering mode {}{}".format(
mode, '' if reason is None else ' (reason: {})'.format(reason))) mode, '' if reason is None else ' (reason: {})'.format(reason)))
if mode not in self._handlers: if mode not in self._handlers:
@ -238,6 +260,7 @@ class ModeManager(QObject):
self._mode_stack.remove(mode) self._mode_stack.remove(mode)
except ValueError: except ValueError:
raise ValueError("Mode {} not on mode stack!".format(mode)) raise ValueError("Mode {} not on mode stack!".format(mode))
self.locked = False
logger.debug("Leaving mode {}{}, new mode stack {}".format( logger.debug("Leaving mode {}{}, new mode stack {}".format(
mode, '' if reason is None else ' (reason: {})'.format(reason), mode, '' if reason is None else ' (reason: {})'.format(reason),
self._mode_stack)) self._mode_stack))

View File

@ -299,7 +299,7 @@ class Command(MinimalLineEdit):
def focusInEvent(self, e): def focusInEvent(self, e):
"""Extend focusInEvent to enter command mode.""" """Extend focusInEvent to enter command mode."""
modeman.enter(KeyMode.command, 'cmd focus') modeman.maybe_enter(KeyMode.command, 'cmd focus')
super().focusInEvent(e) super().focusInEvent(e)

View File

@ -279,7 +279,13 @@ class Prompter:
self.question = question self.question = question
mode = self._display_question() mode = self._display_question()
question.aborted.connect(lambda: modeman.maybe_leave(mode, 'aborted')) question.aborted.connect(lambda: modeman.maybe_leave(mode, 'aborted'))
modeman.enter(mode, 'question asked') try:
modeman.enter(mode, 'question asked')
except modeman.ModeLockedError:
if modeman.instance().mode != KeyMode.prompt:
question.abort()
return None
modeman.instance().locked = True
if blocking: if blocking:
loop = EventLoop() loop = EventLoop()
self._loops.append(loop) self._loops.append(loop)

View File

@ -233,7 +233,7 @@ class WebView(QWebView):
elif ((hitresult.isContentEditable() and webelem.is_writable(elem)) or elif ((hitresult.isContentEditable() and webelem.is_writable(elem)) or
webelem.is_editable(elem)): webelem.is_editable(elem)):
log.mouse.debug("Clicked editable element!") log.mouse.debug("Clicked editable element!")
modeman.enter(KeyMode.insert, 'click') modeman.maybe_enter(KeyMode.insert, 'click')
else: else:
log.mouse.debug("Clicked non-editable element!") log.mouse.debug("Clicked non-editable element!")
if config.get('input', 'auto-leave-insert-mode'): if config.get('input', 'auto-leave-insert-mode'):
@ -247,7 +247,7 @@ class WebView(QWebView):
elem = webelem.focus_elem(self.page().currentFrame()) elem = webelem.focus_elem(self.page().currentFrame())
if webelem.is_editable(elem): if webelem.is_editable(elem):
log.mouse.debug("Clicked editable element (delayed)!") log.mouse.debug("Clicked editable element (delayed)!")
modeman.enter(KeyMode.insert, 'click-delayed') modeman.maybe_enter(KeyMode.insert, 'click-delayed')
else: else:
log.mouse.debug("Clicked non-editable element (delayed)!") log.mouse.debug("Clicked non-editable element (delayed)!")
if config.get('input', 'auto-leave-insert-mode'): if config.get('input', 'auto-leave-insert-mode'):
@ -402,7 +402,7 @@ class WebView(QWebView):
if elem.isNull(): if elem.isNull():
log.webview.debug("Focused element is null!") log.webview.debug("Focused element is null!")
elif webelem.is_editable(elem): elif webelem.is_editable(elem):
modeman.enter(KeyMode.insert, 'load finished') modeman.maybe_enter(KeyMode.insert, 'load finished')
@pyqtSlot(str) @pyqtSlot(str)
def set_force_open_target(self, target): def set_force_open_target(self, target):