Use message module as API for most questions

This commit is contained in:
Florian Bruhin 2016-10-03 20:57:33 +02:00
parent 756564ebff
commit f0ed43ec20
5 changed files with 85 additions and 112 deletions

View File

@ -150,7 +150,7 @@ def ask_for_filename(suggested_filename, win_id, *, parent=None,
suggested_filename = utils.force_encoding(suggested_filename, encoding)
q = usertypes.Question(parent)
q.text = "Save file to:"
q.title = "Save file to:"
q.mode = usertypes.PromptMode.text
q.completed.connect(q.deleteLater)
q.default = _path_suggestion(suggested_filename)
@ -382,20 +382,13 @@ class DownloadItem(QObject):
else:
self.set_fileobj(fileobj)
def _ask_confirm_question(self, msg):
def _ask_confirm_question(self, title, msg):
"""Create a Question object to be asked."""
q = usertypes.Question(self)
q.text = msg
q.mode = usertypes.PromptMode.yesno
q.answered_yes.connect(self._create_fileobj)
q.answered_no.connect(functools.partial(self.cancel,
remove_data=False))
q.cancelled.connect(functools.partial(self.cancel, remove_data=False))
self.cancelled.connect(q.abort)
self.error.connect(q.abort)
message_bridge = objreg.get('message-bridge', scope='window',
window=self._win_id)
message_bridge.ask(q, blocking=False)
no_action = functools.partial(self.cancel, remove_data=False)
message.confirm_async(self._win_id, title=title, text=msg,
yes_action=self._create_fileobj,
no_action=no_action, cancel_action=no_action,
abort_on=[self.cancelled, self.error])
def _die(self, msg):
"""Abort the download and emit an error."""
@ -615,13 +608,13 @@ class DownloadItem(QObject):
# The file already exists, so ask the user if it should be
# overwritten.
txt = self._filename + " already exists. Overwrite?"
self._ask_confirm_question(txt)
self._ask_confirm_question("Overwrite existing file?", txt)
# FIFO, device node, etc. Make sure we want to do this
elif (os.path.exists(self._filename) and
not os.path.isdir(self._filename)):
txt = (self._filename + " already exists and is a special file. "
"Write to this?")
self._ask_confirm_question(txt)
self._ask_confirm_question("Overwrite special file?", txt)
else:
self._create_fileobj()

View File

@ -220,25 +220,19 @@ class NetworkManager(QNetworkAccessManager):
Return:
The answer the user gave or None if the prompt was cancelled.
"""
q = usertypes.Question()
q.title = title
q.text = text
q.mode = mode
self.shutting_down.connect(q.abort)
abort_on = [self.shutting_down]
if owner is not None:
owner.destroyed.connect(q.abort)
abort_on.append(owner.destroyed)
# This might be a generic network manager, e.g. one belonging to a
# DownloadManager. In this case, just skip the webview thing.
if self._tab_id is not None:
tab = objreg.get('tab', scope='tab', window=self._win_id,
tab=self._tab_id)
tab.load_started.connect(q.abort)
bridge = objreg.get('message-bridge', scope='window',
window=self._win_id)
bridge.ask(q, blocking=True)
q.deleteLater()
return q.answer
abort_on.append(tab.load_started)
return message.ask(win_id=self._win_id, title=title, text=text, mode=mode,
abort_on=abort_on)
def shutdown(self):
"""Abort all running requests."""

View File

@ -98,8 +98,10 @@ class BrowserPage(QWebPage):
if (self._is_shutting_down or
config.get('content', 'ignore-javascript-prompt')):
return (False, "")
answer = self._ask('Javascript prompt', msg,
usertypes.PromptMode.text, default)
answer = message.ask(self._win_id, 'Javascript prompt', msg,
usertypes.PromptMode.text, default=default,
abort_on=[self.loadStarted,
self.shutting_down])
if answer is None:
return (False, "")
else:
@ -196,31 +198,6 @@ class BrowserPage(QWebPage):
suggested_file)
return True
def _ask(self, title, text, mode, default=None):
"""Ask a blocking question in the statusbar.
Args:
title: The title to display.
text: The text to display to the user.
mode: A PromptMode.
default: The default value to display.
Return:
The answer the user gave or None if the prompt was cancelled.
"""
q = usertypes.Question()
q.title = title
q.text = text
q.mode = mode
q.default = default
self.loadStarted.connect(q.abort)
self.shutting_down.connect(q.abort)
bridge = objreg.get('message-bridge', scope='window',
window=self._win_id)
bridge.ask(q, blocking=True)
q.deleteLater()
return q.answer
def _show_pdfjs(self, reply):
"""Show the reply with pdfjs."""
try:
@ -335,11 +312,6 @@ class BrowserPage(QWebPage):
}
config_val = config.get(*options[feature])
if config_val == 'ask':
bridge = objreg.get('message-bridge', scope='window',
window=self._win_id)
q = usertypes.Question(bridge)
q.mode = usertypes.PromptMode.yesno
msgs = {
QWebPage.Notifications: 'show notifications',
QWebPage.Geolocation: 'access your location',
@ -347,30 +319,28 @@ class BrowserPage(QWebPage):
host = frame.url().host()
if host:
q.text = "Allow the website at {} to {}?".format(
text = "Allow the website at {} to {}?".format(
frame.url().host(), msgs[feature])
else:
q.text = "Allow the website to {}?".format(msgs[feature])
text = "Allow the website to {}?".format(msgs[feature])
yes_action = functools.partial(
self.setFeaturePermission, frame, feature,
QWebPage.PermissionGrantedByUser)
q.answered_yes.connect(yes_action)
no_action = functools.partial(
self.setFeaturePermission, frame, feature,
QWebPage.PermissionDeniedByUser)
q.answered_no.connect(no_action)
q.cancelled.connect(no_action)
self.shutting_down.connect(q.abort)
q.completed.connect(q.deleteLater)
question = message.confirm_async(self._win_id,
yes_action=yes_action,
no_action=no_action,
cancel_action=cancel_action,
abort_on=[self.shutting_down,
self.loadStarted],
title='Permission request',
text=text)
self.featurePermissionRequestCanceled.connect(functools.partial(
self.on_feature_permission_cancelled, q, frame, feature))
self.loadStarted.connect(q.abort)
bridge.ask(q, blocking=False)
self.on_feature_permission_cancelled, question, frame, feature))
elif config_val:
self.setFeaturePermission(frame, feature,
QWebPage.PermissionGrantedByUser)
@ -480,7 +450,9 @@ class BrowserPage(QWebPage):
if (self._is_shutting_down or
config.get('content', 'ignore-javascript-alert')):
return
self._ask('Javascript alert', msg, usertypes.PromptMode.alert)
message.ask(self._win_id, 'Javascript alert', msg,
usertypes.PromptMode.alert,
abort_on=[self.loadStarted, self.shutting_down])
def javaScriptConfirm(self, frame, msg):
"""Override javaScriptConfirm to use the statusbar."""
@ -490,7 +462,9 @@ class BrowserPage(QWebPage):
if self._is_shutting_down:
return False
ans = self._ask('Javascript confirm', msg, usertypes.PromptMode.yesno)
ans = message.ask(self._win_id, 'Javascript confirm', msg,
usertypes.PromptMode.yesno,
abort_on=[self.loadStarted, self.shutting_down])
return bool(ans)
def javaScriptConsoleMessage(self, msg, line, source):

View File

@ -343,17 +343,11 @@ class _BasePrompt(QWidget):
return utils.get_repr(self, question=self.question, constructor=True)
def _init_title(self, question):
if question.title is None:
title = question.text
text = None
else:
title = question.title
text = question.text
title_label = QLabel('<b>{}</b>'.format(title), self)
assert question.title is not None, question
title_label = QLabel('<b>{}</b>'.format(question.title), self)
self._vbox.addWidget(title_label)
if text is not None:
text_label = QLabel(text)
if question.text is not None:
text_label = QLabel(question.text)
self._vbox.addWidget(text_label)
def accept(self, value=None):

View File

@ -76,7 +76,21 @@ def info(message):
global_bridge.show_message.emit(usertypes.MessageLevel.info, message)
def ask(win_id, message, mode, default=None):
def _build_question(title, mode, *, default=None, text=None, abort_on=()):
"""Common function for ask/ask_async."""
if not isinstance(mode, usertypes.PromptMode):
raise TypeError("Mode {} is no PromptMode member!".format(mode))
question = usertypes.Question()
question.title = title
question.text = text
question.mode = mode
question.default = default
for sig in abort_on:
sig.connect(question.abort)
return question
def ask(win_id, *args, **kwargs):
"""Ask a modular question in the statusbar (blocking).
Args:
@ -84,21 +98,21 @@ def ask(win_id, message, mode, default=None):
message: The message to display to the user.
mode: A PromptMode.
default: The default value to display.
text: Additional text to show
abort_on: A list of signals which abort the question if emitted.
Return:
The answer the user gave or None if the prompt was cancelled.
"""
q = usertypes.Question()
q.text = message
q.mode = mode
q.default = default
question = _build_question(*args, **kwargs)
bridge = objreg.get('message-bridge', scope='window', window=win_id)
bridge.ask(q, blocking=True)
q.deleteLater()
return q.answer
bridge.ask(question, blocking=True)
answer = question.answer
question.deleteLater()
return answer
def ask_async(win_id, message, mode, handler, default=None):
def ask_async(win_id, text, mode, handler, **kwargs):
"""Ask an async question in the statusbar.
Args:
@ -107,20 +121,17 @@ def ask_async(win_id, message, mode, handler, default=None):
mode: A PromptMode.
handler: The function to get called with the answer as argument.
default: The default value to display.
text: Additional text to show.
"""
if not isinstance(mode, usertypes.PromptMode):
raise TypeError("Mode {} is no PromptMode member!".format(mode))
q = usertypes.Question()
q.text = message
q.mode = mode
q.default = default
q.answered.connect(handler)
q.completed.connect(q.deleteLater)
question = _build_question(text, mode, **kwargs)
question.answered.connect(handler)
question.completed.connect(question.deleteLater)
bridge = objreg.get('message-bridge', scope='window', window=win_id)
bridge.ask(q, blocking=False)
bridge.ask(question, blocking=False)
def confirm_async(win_id, message, yes_action, no_action=None, default=None):
def confirm_async(win_id, yes_action, no_action=None, cancel_action=None,
*args, **kwargs):
"""Ask a yes/no question to the user and execute the given actions.
Args:
@ -128,18 +139,25 @@ def confirm_async(win_id, message, yes_action, no_action=None, default=None):
message: The message to display to the user.
yes_action: Callable to be called when the user answered yes.
no_action: Callable to be called when the user answered no.
cancel_action: Callable to be called when the user cancelled the
question.
default: True/False to set a default value, or None.
text: Additional text to show.
Return:
The question object.
"""
q = usertypes.Question()
q.text = message
q.mode = usertypes.PromptMode.yesno
q.default = default
q.answered_yes.connect(yes_action)
question = self._build_question(*args, **kwargs)
question.answered_yes.connect(yes_action)
if no_action is not None:
q.answered_no.connect(no_action)
q.completed.connect(q.deleteLater)
question.answered_no.connect(no_action)
if cancel_action is not None:
question.cancelled.connect(cancel_action)
question.completed.connect(q.deleteLater)
bridge = objreg.get('message-bridge', scope='window', window=win_id)
bridge.ask(q, blocking=False)
bridge.ask(question, blocking=False)
return question
class GlobalMessageBridge(QObject):