Fix mode handling with multi-window questions

When the prompt mode is left in any window, we need to take care of:

- Cancelling the question if needed (exactly once)
- Leaving the prompt mode in all other windows too
This commit is contained in:
Florian Bruhin 2016-10-28 07:34:45 +02:00
parent 4a360ba185
commit 1b3e9613ea
3 changed files with 24 additions and 7 deletions

View File

@ -175,6 +175,9 @@ class MainWindow(QWidget):
self._init_completion() self._init_completion()
log.init.debug("Initializing modes...")
modeman.init(self.win_id, self)
self._commandrunner = runners.CommandRunner(self.win_id, self._commandrunner = runners.CommandRunner(self.win_id,
partial_match=True) partial_match=True)
@ -191,9 +194,6 @@ class MainWindow(QWidget):
scope='window', window=self.win_id) scope='window', window=self.win_id)
self._prompt_container.hide() self._prompt_container.hide()
log.init.debug("Initializing modes...")
modeman.init(self.win_id, self)
if geometry is not None: if geometry is not None:
self._load_geometry(geometry) self._load_geometry(geometry)
elif self.win_id == 0: elif self.win_id == 0:
@ -397,7 +397,7 @@ class MainWindow(QWidget):
mode_manager.entered.connect(status.on_mode_entered) mode_manager.entered.connect(status.on_mode_entered)
mode_manager.left.connect(status.on_mode_left) mode_manager.left.connect(status.on_mode_left)
mode_manager.left.connect(cmd.on_mode_left) mode_manager.left.connect(cmd.on_mode_left)
mode_manager.left.connect(prompt.prompt_queue.on_mode_left) mode_manager.left.connect(message.global_bridge.mode_left)
# commands # commands
keyparsers[usertypes.KeyMode.normal].keystring_updated.connect( keyparsers[usertypes.KeyMode.normal].keystring_updated.connect(

View File

@ -93,6 +93,7 @@ class PromptQueue(QObject):
self._shutting_down = False self._shutting_down = False
self._loops = [] self._loops = []
self._queue = collections.deque() self._queue = collections.deque()
message.global_bridge.mode_left.connect(self._on_mode_left)
def __repr__(self): def __repr__(self):
return utils.get_repr(self, loops=len(self._loops), return utils.get_repr(self, loops=len(self._loops),
@ -198,14 +199,15 @@ class PromptQueue(QObject):
question.completed.connect(self._pop_later) question.completed.connect(self._pop_later)
@pyqtSlot(usertypes.KeyMode) @pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode): def _on_mode_left(self, mode):
"""Clear and reset input when the mode was left.""" """Abort question when a mode was left."""
if self._question is not None: if self._question is not None:
log.prompt.debug("Left mode {}, hiding {}".format( log.prompt.debug("Left mode {}, hiding {}".format(
mode, self._question)) mode, self._question))
self.show_prompts.emit(None) self.show_prompts.emit(None)
# FIXME move this somewhere else?
if self._question.answer is None and not self._question.is_aborted: if self._question.answer is None and not self._question.is_aborted:
log.prompt.debug("Cancelling {} because {} was left".format(
self._question, mode))
self._question.cancel() self._question.cancel()
self._question = None self._question = None
@ -257,6 +259,7 @@ class PromptContainer(QWidget):
message.global_bridge.prompt_done.connect(self._on_prompt_done) message.global_bridge.prompt_done.connect(self._on_prompt_done)
prompt_queue.show_prompts.connect(self._on_show_prompts) prompt_queue.show_prompts.connect(self._on_show_prompts)
message.global_bridge.mode_left.connect(self._on_global_mode_left)
def __repr__(self): def __repr__(self):
return utils.get_repr(self, win_id=self._win_id) return utils.get_repr(self, win_id=self._win_id)
@ -308,6 +311,18 @@ class PromptContainer(QWidget):
"""Leave the prompt mode in this window if a question was answered.""" """Leave the prompt mode in this window if a question was answered."""
modeman.maybe_leave(self._win_id, key_mode, ':prompt-accept') modeman.maybe_leave(self._win_id, key_mode, ':prompt-accept')
@pyqtSlot(usertypes.KeyMode)
def _on_global_mode_left(self, mode):
"""Leave prompt/yesno mode in this window if it was left elsewhere.
PromptQueue takes care of getting rid of the question if a mode was
left, but if that happens in a different window, this window will still
be stuck in prompt mode. Here we make sure to leave that if it was left
anywhere else.
"""
if mode in [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]:
modeman.maybe_leave(self._win_id, mode, 'left in other window')
@cmdutils.register(instance='prompt-container', hide=True, scope='window', @cmdutils.register(instance='prompt-container', hide=True, scope='window',
modes=[usertypes.KeyMode.prompt, modes=[usertypes.KeyMode.prompt,
usertypes.KeyMode.yesno]) usertypes.KeyMode.yesno])

View File

@ -170,11 +170,13 @@ class GlobalMessageBridge(QObject):
IMPORTANT: Slots need to be connected to this signal via IMPORTANT: Slots need to be connected to this signal via
a Qt.DirectConnection! a Qt.DirectConnection!
mode_left: Emitted when a keymode was left in any window.
""" """
show_message = pyqtSignal(usertypes.MessageLevel, str) show_message = pyqtSignal(usertypes.MessageLevel, str)
prompt_done = pyqtSignal(usertypes.KeyMode) prompt_done = pyqtSignal(usertypes.KeyMode)
ask_question = pyqtSignal(usertypes.Question, bool) ask_question = pyqtSignal(usertypes.Question, bool)
mode_left = pyqtSignal(usertypes.KeyMode)
def ask(self, question, blocking, *, log_stack=False): def ask(self, question, blocking, *, log_stack=False):
"""Ask a question to the user. """Ask a question to the user.