Clean up Question objects correctly

This commit is contained in:
Florian Bruhin 2014-06-27 07:56:16 +02:00
parent cb6550debb
commit b79cdbc416
5 changed files with 33 additions and 15 deletions

View File

@ -50,7 +50,6 @@ Downloads
Improvements / minor features
=============================
- Make sure Question objects are deleteLater'ed correctly.
- qutebrowser local_file.foo should open that file in $PWD
- Distinction between :q and :wq, add ZZ and ZQ shortcuts.
- set_toggle to toggle setting between two states

View File

@ -389,11 +389,10 @@ class DownloadManager(QObject):
q.default = suggested_filename
q.answered.connect(download.set_filename)
q.cancelled.connect(download.cancel)
q.answered.connect(q.deleteLater)
q.cancelled.connect(q.deleteLater)
q.completed.connect(q.deleteLater)
q.destroyed.connect(partial(self.questions.remove, q))
self.questions.append(q)
download.cancelled.connect(q.abort)
download.cancelled.connect(q.deleteLater)
message.instance().ask(q, blocking=False)
@pyqtSlot(DownloadItem)

View File

@ -97,6 +97,7 @@ def ask_async(message, mode, handler, default=None):
q.mode = mode
q.default = default
q.answered.connect(handler)
q.completed.connect(q.deleteLater)
bridge.ask(q, blocking=False)
@ -117,6 +118,7 @@ def confirm_async(message, yes_action, no_action=None, default=None):
q.answered_yes.connect(yes_action)
if no_action is not None:
q.answered_no.connect(no_action)
q.completed.connect(q.deleteLater)
bridge.ask(q, blocking=False)

View File

@ -240,6 +240,10 @@ class Question(QObject):
"""A question asked to the user, e.g. via the status bar.
Note the creator is responsible for cleaning up the question after it
doesn't need it anymore, e.g. via connecting Question.completed to
Question.deleteLater.
Attributes:
mode: A PromptMode enum member.
yesno: A question which can be answered with yes/no.
@ -256,8 +260,6 @@ class Question(QObject):
Signals:
answered: Emitted when the question has been answered by the user.
This is emitted from qutebrowser.widgets.statusbar._prompt so
it can be emitted after the mode is left.
arg: The answer to the question.
cancelled: Emitted when the question has been cancelled by the user.
aborted: Emitted when the question was aborted programatically.
@ -266,6 +268,7 @@ class Question(QObject):
answered with yes.
answered_no: Convienience signal emitted when a yesno question was
answered with no.
completed: Emitted when the question was completed in any way.
"""
answered = pyqtSignal(object)
@ -273,6 +276,7 @@ class Question(QObject):
aborted = pyqtSignal()
answered_yes = pyqtSignal()
answered_no = pyqtSignal()
completed = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
@ -286,6 +290,21 @@ class Question(QObject):
def __repr__(self):
return '<{} "{}">'.format(self.__class__.__name__, self.text)
def done(self):
"""Must be called when the queston was answered completely."""
self.answered.emit(self.answer)
if self.mode == PromptMode.yesno:
if self.answer:
self.answered_yes.emit()
else:
self.answered_no.emit()
self.completed.emit()
def cancel(self):
"""Cancel the question (resulting from user-input)."""
self.cancelled.emit()
self.completed.emit()
def abort(self):
"""Abort the question.
@ -295,6 +314,7 @@ class Question(QObject):
self.is_aborted = True
try:
self.aborted.emit()
self.completed.emit()
except TypeError as e:
# FIXME
# We seem to get "pyqtSignal must be bound to a QObject, not

View File

@ -76,7 +76,7 @@ class Prompt(QWidget):
self._input.setEchoMode(QLineEdit.Normal)
self.hide_prompt.emit()
if self.question.answer is None and not self.question.is_aborted:
self.question.cancelled.emit()
self.question.cancel()
@cmdutils.register(instance='mainwindow.status.prompt', hide=True,
modes=['prompt'])
@ -99,22 +99,22 @@ class Prompt(QWidget):
self.question.answer = (self.question.user, password)
modeman.leave('prompt', 'prompt accept')
self.hide_prompt.emit()
self.question.answered.emit(self.question.answer)
self.question.done()
elif self.question.mode == PromptMode.text:
# User just entered text.
self.question.answer = self._input.text()
modeman.leave('prompt', 'prompt accept')
self.question.answered.emit(self.question.answer)
self.question.done()
elif self.question.mode == PromptMode.yesno:
# User wants to accept the default of a yes/no question.
self.question.answer = self.question.default
modeman.leave('yesno', 'yesno accept')
self.question.answered.emit(self.question.answer)
self.question.done()
elif self.question.mode == PromptMode.alert:
# User acknowledged an alert
self.question.answer = None
modeman.leave('prompt', 'alert accept')
self.question.answered.emit(self.question.answer)
self.question.done()
else:
raise ValueError("Invalid question mode!")
@ -127,8 +127,7 @@ class Prompt(QWidget):
return
self.question.answer = True
modeman.leave('yesno', 'yesno accept')
self.question.answered.emit(self.question.answer)
self.question.answered_yes.emit()
self.question.done()
@cmdutils.register(instance='mainwindow.status.prompt', hide=True,
modes=['yesno'])
@ -139,8 +138,7 @@ class Prompt(QWidget):
return
self.question.answer = False
modeman.leave('yesno', 'prompt accept')
self.question.answered.emit(self.question.answer)
self.question.answered_no.emit()
self.question.done()
@pyqtSlot(Question, bool)
def ask_question(self, question, blocking):