Save old question correctly

This commit is contained in:
Florian Bruhin 2014-07-01 07:17:28 +02:00
parent 4cdf4fc45f
commit 1b9bcbf56f

View File

@ -19,6 +19,8 @@
"""Prompt shown in the statusbar.""" """Prompt shown in the statusbar."""
from collections import namedtuple
from PyQt5.QtCore import pyqtSignal, pyqtSlot from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit from PyQt5.QtWidgets import QHBoxLayout, QWidget, QLineEdit
@ -28,6 +30,11 @@ from qutebrowser.widgets.statusbar.textbase import TextBase
from qutebrowser.widgets.misc import MinimalLineEdit from qutebrowser.widgets.misc import MinimalLineEdit
from qutebrowser.utils.usertypes import PromptMode, Question from qutebrowser.utils.usertypes import PromptMode, Question
from qutebrowser.utils.qt import EventLoop from qutebrowser.utils.qt import EventLoop
from qutebrowser.utils.log import statusbar as logger
PromptContext = namedtuple('PromptContext', ['question', 'text', 'input_text',
'echo_mode', 'input_visible'])
class Prompt(QWidget): class Prompt(QWidget):
@ -36,10 +43,11 @@ class Prompt(QWidget):
Attributes: Attributes:
question: A Question object with the question to be asked to the user. question: A Question object with the question to be asked to the user.
loops: A list of local EventLoops to spin into in _spin. _loops: A list of local EventLoops to spin in when blocking.
_hbox: The QHBoxLayout used to display the text and prompt. _hbox: The QHBoxLayout used to display the text and prompt.
_txt: The TextBase instance (QLabel) used to display the prompt text. _txt: The TextBase instance (QLabel) used to display the prompt text.
_input: The MinimalLineEdit instance (QLineEdit) used for the input. _input: The MinimalLineEdit instance (QLineEdit) used for the input.
_queue: A queue of waiting questions.
Signals: Signals:
show_prompt: Emitted when the prompt widget wants to be shown. show_prompt: Emitted when the prompt widget wants to be shown.
@ -53,7 +61,8 @@ class Prompt(QWidget):
super().__init__(parent) super().__init__(parent)
self.question = None self.question = None
self.loops = [] self._loops = []
self._queue = []
self._hbox = QHBoxLayout(self) self._hbox = QHBoxLayout(self)
self._hbox.setContentsMargins(0, 0, 0, 0) self._hbox.setContentsMargins(0, 0, 0, 0)
@ -65,23 +74,40 @@ class Prompt(QWidget):
self._input = MinimalLineEdit() self._input = MinimalLineEdit()
self._hbox.addWidget(self._input) self._hbox.addWidget(self._input)
self._old_input = self._input.text()
self._old_echo_mode = self._input.echoMode()
self._old_text = self._txt.text()
self._old_visible = None
self.visible = False self.visible = False
def __repr__(self): def __repr__(self):
return '<{}>'.format(self.__class__.__name__) return '<{}>'.format(self.__class__.__name__)
def _get_ctx(self):
"""Get a PromptContext based on the current state."""
if not self.visible:
# FIXME do we really use visible here?
return None
ctx = PromptContext(question=self.question, text=self._txt.text(),
input_text=self._input.text(),
echo_mode=self._input.echoMode(),
input_visible=self._input.isVisible())
return ctx
def _restore_ctx(self, ctx):
"""Restore state from a PromptContext.
Args:
ctx: A PromptContext previously saved by _get_ctx, or None.
"""
if ctx is None:
self.hide_prompt.emit()
return
self.question = ctx.question
self._txt.setText(ctx.text)
self._input.setText(ctx.input_text)
self._input.setEchoMode(ctx.echo_mode)
self._input.setVisible(ctx.input_visible)
def on_mode_left(self, mode): def on_mode_left(self, mode):
"""Clear and reset input when the mode was left.""" """Clear and reset input when the mode was left."""
if mode in ('prompt', 'yesno'): if mode in ('prompt', 'yesno'):
self._txt.setText(self._old_text)
self._input.setText(self._old_input)
self._input.setEchoMode(self._old_echo_mode)
if not self._old_visible:
self.hide_prompt.emit()
if self.question.answer is None and not self.question.is_aborted: if self.question.answer is None and not self.question.is_aborted:
self.question.cancel() self.question.cancel()
@ -162,11 +188,23 @@ class Prompt(QWidget):
Raise: Raise:
ValueError if the set PromptMode is invalid. ValueError if the set PromptMode is invalid.
""" """
self._old_input = self._input.text() logger.debug("Asking question {}, blocking {}, loops {}, queue "
self._old_echo_mode = self._input.echoMode() "{}".format(question, blocking, self._loops, self._queue))
self._old_text = self._txt.text()
self._old_visible = self.visible if self.visible and not blocking:
# We got an async question, but we're already busy with one, so we
# just queue it up for later.
logger.debug("Adding to queue")
self._queue.append(question)
return
if blocking:
# If we're blocking we save the old state on the stack, so we can
# restore it after exec, if exec gets called multiple times.
context = self._save_ctx()
self.question = question self.question = question
if question.mode == PromptMode.yesno: if question.mode == PromptMode.yesno:
if question.default is None: if question.default is None:
suffix = "" suffix = ""
@ -201,10 +239,10 @@ class Prompt(QWidget):
modeman.enter(mode, 'question asked') modeman.enter(mode, 'question asked')
if blocking: if blocking:
loop = EventLoop() loop = EventLoop()
self.loops.append(loop) self._loops.append(loop)
loop.destroyed.connect(lambda: self.loops.remove(loop)) loop.destroyed.connect(lambda: self._loops.remove(loop))
self.question.answered.connect(loop.quit) question.completed.connect(loop.quit)
self.question.cancelled.connect(loop.quit) question.completed.connect(loop.deleteLater)
self.question.aborted.connect(loop.quit)
loop.exec_() loop.exec_()
self._restore_ctx(context)
return self.question.answer return self.question.answer