First attempt at showing prompts in all windows
This commit is contained in:
parent
d5a1f6d6b5
commit
9ce1180b31
@ -48,7 +48,7 @@ from qutebrowser.config import style, config, websettings, configexc
|
||||
from qutebrowser.browser import urlmarks, adblock, history, browsertab
|
||||
from qutebrowser.browser.webkit import cookies, cache, downloads
|
||||
from qutebrowser.browser.webkit.network import networkmanager
|
||||
from qutebrowser.mainwindow import mainwindow
|
||||
from qutebrowser.mainwindow import mainwindow, prompt
|
||||
from qutebrowser.misc import (readline, ipc, savemanager, sessions,
|
||||
crashsignal, earlyinit)
|
||||
from qutebrowser.misc import utilcmds # pylint: disable=unused-import
|
||||
@ -372,6 +372,9 @@ def _init_modules(args, crash_handler):
|
||||
crash_handler: The CrashHandler instance.
|
||||
"""
|
||||
# pylint: disable=too-many-statements
|
||||
log.init.debug("Initializing prompts...")
|
||||
prompt.init()
|
||||
|
||||
log.init.debug("Initializing save manager...")
|
||||
save_manager = savemanager.SaveManager(qApp)
|
||||
objreg.register('save-manager', save_manager)
|
||||
@ -644,11 +647,8 @@ class Quitter:
|
||||
load_next_time=True)
|
||||
|
||||
deferrer = False
|
||||
for win_id in objreg.window_registry:
|
||||
prompt_container = objreg.get('prompt-container', None,
|
||||
scope='window', window=win_id)
|
||||
if prompt_container is not None and prompt_container.shutdown():
|
||||
deferrer = True
|
||||
if prompt.prompt_queue.shutdown():
|
||||
deferrer = True
|
||||
if deferrer:
|
||||
# If shutdown was called while we were asking a question, we're in
|
||||
# a still sub-eventloop (which gets quit now) and not in the main
|
||||
|
@ -1137,7 +1137,7 @@ class CommandDispatcher:
|
||||
def quickmark_save(self):
|
||||
"""Save the current page as a quickmark."""
|
||||
quickmark_manager = objreg.get('quickmark-manager')
|
||||
quickmark_manager.prompt_save(self._win_id, self._current_url())
|
||||
quickmark_manager.prompt_save(self._current_url())
|
||||
|
||||
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||
maxsplit=0)
|
||||
|
@ -159,11 +159,10 @@ class QuickmarkManager(UrlMarkManager):
|
||||
else:
|
||||
self.marks[key] = url
|
||||
|
||||
def prompt_save(self, win_id, url):
|
||||
def prompt_save(self, url):
|
||||
"""Prompt for a new quickmark name to be added and add it.
|
||||
|
||||
Args:
|
||||
win_id: The current window ID.
|
||||
url: The quickmark url as a QUrl.
|
||||
"""
|
||||
if not url.isValid():
|
||||
@ -171,19 +170,17 @@ class QuickmarkManager(UrlMarkManager):
|
||||
return
|
||||
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
|
||||
message.ask_async(
|
||||
win_id, "Add quickmark:", usertypes.PromptMode.text,
|
||||
functools.partial(self.quickmark_add, win_id, urlstr))
|
||||
"Add quickmark:", usertypes.PromptMode.text,
|
||||
functools.partial(self.quickmark_add, urlstr))
|
||||
|
||||
@cmdutils.register(instance='quickmark-manager')
|
||||
@cmdutils.argument('win_id', win_id=True)
|
||||
def quickmark_add(self, win_id, url, name):
|
||||
def quickmark_add(self, url, name):
|
||||
"""Add a new quickmark.
|
||||
|
||||
You can view all saved quickmarks on the
|
||||
link:qute://bookmarks[bookmarks page].
|
||||
|
||||
Args:
|
||||
win_id: The window ID to display the errors in.
|
||||
url: The url to add as quickmark.
|
||||
name: The name for the new quickmark.
|
||||
"""
|
||||
@ -205,7 +202,7 @@ class QuickmarkManager(UrlMarkManager):
|
||||
|
||||
if name in self.marks:
|
||||
message.confirm_async(
|
||||
win_id, title="Override existing quickmark?",
|
||||
title="Override existing quickmark?",
|
||||
yes_action=set_mark, default=True)
|
||||
else:
|
||||
set_mark()
|
||||
|
@ -231,8 +231,8 @@ class NetworkManager(QNetworkAccessManager):
|
||||
tab=self._tab_id)
|
||||
abort_on.append(tab.load_started)
|
||||
|
||||
return message.ask(win_id=self._win_id, title=title, text=text,
|
||||
mode=mode, abort_on=abort_on, default=default)
|
||||
return message.ask(title=title, text=text, mode=mode,
|
||||
abort_on=abort_on, default=default)
|
||||
|
||||
def shutdown(self):
|
||||
"""Abort all running requests."""
|
||||
|
@ -98,7 +98,7 @@ class BrowserPage(QWebPage):
|
||||
if (self._is_shutting_down or
|
||||
config.get('content', 'ignore-javascript-prompt')):
|
||||
return (False, "")
|
||||
answer = message.ask(self._win_id, 'Javascript prompt', msg,
|
||||
answer = message.ask('Javascript prompt', msg,
|
||||
mode=usertypes.PromptMode.text,
|
||||
default=default,
|
||||
abort_on=[self.loadStarted,
|
||||
@ -139,7 +139,6 @@ class BrowserPage(QWebPage):
|
||||
url = QUrl(info.url)
|
||||
scheme = url.scheme()
|
||||
message.confirm_async(
|
||||
self._win_id,
|
||||
title="Open external application for {}-link?".format(scheme),
|
||||
text="URL: {}".format(url.toDisplayString()),
|
||||
yes_action=functools.partial(QDesktopServices.openUrl, url))
|
||||
@ -453,8 +452,7 @@ class BrowserPage(QWebPage):
|
||||
if (self._is_shutting_down or
|
||||
config.get('content', 'ignore-javascript-alert')):
|
||||
return
|
||||
message.ask(self._win_id, 'Javascript alert', msg,
|
||||
mode=usertypes.PromptMode.alert,
|
||||
message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert,
|
||||
abort_on=[self.loadStarted, self.shutting_down])
|
||||
|
||||
def javaScriptConfirm(self, frame, msg):
|
||||
@ -465,7 +463,7 @@ class BrowserPage(QWebPage):
|
||||
|
||||
if self._is_shutting_down:
|
||||
return False
|
||||
ans = message.ask(self._win_id, 'Javascript confirm', msg,
|
||||
ans = message.ask('Javascript confirm', msg,
|
||||
mode=usertypes.PromptMode.yesno,
|
||||
abort_on=[self.loadStarted, self.shutting_down])
|
||||
return bool(ans)
|
||||
|
@ -397,7 +397,7 @@ class MainWindow(QWidget):
|
||||
mode_manager.entered.connect(status.on_mode_entered)
|
||||
mode_manager.left.connect(status.on_mode_left)
|
||||
mode_manager.left.connect(cmd.on_mode_left)
|
||||
mode_manager.left.connect(self._prompt_container.on_mode_left)
|
||||
mode_manager.left.connect(prompt.prompt_queue.on_mode_left)
|
||||
|
||||
# commands
|
||||
keyparsers[usertypes.KeyMode.normal].keystring_updated.connect(
|
||||
@ -420,8 +420,6 @@ class MainWindow(QWidget):
|
||||
|
||||
message_bridge.s_set_text.connect(status.set_text)
|
||||
message_bridge.s_maybe_reset_text.connect(status.txt.maybe_reset_text)
|
||||
message_bridge.s_question.connect(self._prompt_container.ask_question,
|
||||
Qt.DirectConnection)
|
||||
|
||||
# statusbar
|
||||
tabs.current_tab_changed.connect(status.prog.on_tab_changed)
|
||||
@ -520,8 +518,7 @@ class MainWindow(QWidget):
|
||||
# Process all quit messages that user must confirm
|
||||
if quit_texts or 'always' in confirm_quit:
|
||||
text = '\n'.join(['Really quit?'] + quit_texts)
|
||||
confirmed = message.ask(self.win_id, text,
|
||||
mode=usertypes.PromptMode.yesno,
|
||||
confirmed = message.ask(text, mode=usertypes.PromptMode.yesno,
|
||||
default=True)
|
||||
# Stop asking if the user cancels
|
||||
if not confirmed:
|
||||
|
@ -25,17 +25,20 @@ import collections
|
||||
|
||||
import sip
|
||||
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QTimer, QDir, QModelIndex,
|
||||
QItemSelectionModel)
|
||||
QItemSelectionModel, QObject)
|
||||
from PyQt5.QtWidgets import (QWidget, QGridLayout, QVBoxLayout, QLineEdit,
|
||||
QLabel, QWidgetItem, QFileSystemModel, QTreeView,
|
||||
QSizePolicy)
|
||||
|
||||
from qutebrowser.config import style
|
||||
from qutebrowser.utils import usertypes, log, utils, qtutils, objreg
|
||||
from qutebrowser.utils import usertypes, log, utils, qtutils, objreg, message
|
||||
from qutebrowser.keyinput import modeman
|
||||
from qutebrowser.commands import cmdutils, cmdexc
|
||||
|
||||
|
||||
prompt_queue = None
|
||||
|
||||
|
||||
AuthTuple = collections.namedtuple('AuthTuple', ['user', 'password'])
|
||||
|
||||
|
||||
@ -49,9 +52,9 @@ class UnsupportedOperationError(Exception):
|
||||
"""Raised when the prompt class doesn't support the requested operation."""
|
||||
|
||||
|
||||
class PromptContainer(QWidget):
|
||||
class PromptQueue(QObject):
|
||||
|
||||
"""Container for prompts to be shown above the statusbar.
|
||||
"""Global manager and queue for upcoming prompts.
|
||||
|
||||
The way in which multiple questions are handled deserves some explanation.
|
||||
|
||||
@ -77,43 +80,19 @@ class PromptContainer(QWidget):
|
||||
_loops: A list of local EventLoops to spin in when blocking.
|
||||
_queue: A deque of waiting questions.
|
||||
_prompt: The current prompt object if we're handling a question.
|
||||
_layout: The layout used to show prompts in.
|
||||
_win_id: The window ID this object is associated with.
|
||||
|
||||
Signals:
|
||||
show_prompt: Emitted when a prompt should be shown.
|
||||
"""
|
||||
|
||||
STYLESHEET = """
|
||||
{% set prompt_radius = config.get('ui', 'prompt-radius') %}
|
||||
QWidget#Prompt {
|
||||
{% if config.get('ui', 'status-position') == 'top' %}
|
||||
border-bottom-left-radius: {{ prompt_radius }}px;
|
||||
border-bottom-right-radius: {{ prompt_radius }}px;
|
||||
{% else %}
|
||||
border-top-left-radius: {{ prompt_radius }}px;
|
||||
border-top-right-radius: {{ prompt_radius }}px;
|
||||
{% endif %}
|
||||
}
|
||||
show_prompt = pyqtSignal(object)
|
||||
|
||||
QWidget {
|
||||
font: {{ font['prompts'] }};
|
||||
color: {{ color['prompts.fg'] }};
|
||||
background-color: {{ color['prompts.bg'] }};
|
||||
}
|
||||
"""
|
||||
update_geometry = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._layout = QVBoxLayout(self)
|
||||
self._layout.setContentsMargins(10, 10, 10, 10)
|
||||
self._prompt = None
|
||||
self._shutting_down = False
|
||||
self._loops = []
|
||||
self._queue = collections.deque()
|
||||
self._win_id = win_id
|
||||
|
||||
self.setObjectName('Prompt')
|
||||
self.setAttribute(Qt.WA_StyledBackground, True)
|
||||
style.set_register_stylesheet(self)
|
||||
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self, loops=len(self._loops),
|
||||
@ -134,50 +113,6 @@ class PromptContainer(QWidget):
|
||||
# https://github.com/The-Compiler/qutebrowser/issues/415
|
||||
self.ask_question(question, blocking=False)
|
||||
|
||||
def _show_prompt(self, prompt):
|
||||
"""SHow the given prompt object.
|
||||
|
||||
Args:
|
||||
prompt: A Prompt object or None.
|
||||
|
||||
Return: True if a prompt was shown, False otherwise.
|
||||
"""
|
||||
# Before we set a new prompt, make sure the old one is what we expect
|
||||
# This will also work if self._prompt is None and verify nothing is
|
||||
# displayed.
|
||||
#
|
||||
# Note that we don't delete the old prompt here, as we might be in the
|
||||
# middle of saving/restoring an old prompt object.
|
||||
assert self._layout.count() in [0, 1], self._layout.count()
|
||||
item = self._layout.takeAt(0)
|
||||
if item is None:
|
||||
assert self._prompt is None, self._prompt
|
||||
else:
|
||||
if (not isinstance(item, QWidgetItem) or
|
||||
item.widget() is not self._prompt):
|
||||
raise AssertionError("Expected {} to be in layout but got "
|
||||
"{}!".format(self._prompt, item))
|
||||
item.widget().hide()
|
||||
|
||||
log.prompt.debug("Displaying prompt {}".format(prompt))
|
||||
self._prompt = prompt
|
||||
if prompt is None:
|
||||
self.hide()
|
||||
return False
|
||||
|
||||
prompt.question.aborted.connect(
|
||||
lambda: modeman.maybe_leave(self._win_id, prompt.KEY_MODE,
|
||||
'aborted'))
|
||||
modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')
|
||||
self._prompt = prompt
|
||||
self.setSizePolicy(self._prompt.sizePolicy())
|
||||
self._layout.addWidget(self._prompt)
|
||||
self._prompt.show()
|
||||
self.show()
|
||||
self._prompt.setFocus()
|
||||
self.update_geometry.emit()
|
||||
return True
|
||||
|
||||
def shutdown(self):
|
||||
"""Cancel all blocking questions.
|
||||
|
||||
@ -196,7 +131,7 @@ class PromptContainer(QWidget):
|
||||
else:
|
||||
return False
|
||||
|
||||
@cmdutils.register(instance='prompt-container', hide=True, scope='window',
|
||||
@cmdutils.register(instance='prompt-queue', hide=True,
|
||||
modes=[usertypes.KeyMode.prompt,
|
||||
usertypes.KeyMode.yesno])
|
||||
def prompt_accept(self, value=None):
|
||||
@ -211,42 +146,30 @@ class PromptContainer(QWidget):
|
||||
value: If given, uses this value instead of the entered one.
|
||||
For boolean prompts, "yes"/"no" are accepted as value.
|
||||
"""
|
||||
question = self._prompt.question
|
||||
try:
|
||||
done = self._prompt.accept(value)
|
||||
except Error as e:
|
||||
raise cmdexc.CommandError(str(e))
|
||||
if done:
|
||||
key_mode = self._prompt.KEY_MODE
|
||||
self._prompt.question.done()
|
||||
modeman.maybe_leave(self._win_id, key_mode, ':prompt-accept')
|
||||
message.global_bridge.prompt_done.emit(self._prompt.KEY_MODE)
|
||||
question.done()
|
||||
|
||||
@cmdutils.register(instance='prompt-container', hide=True, scope='window',
|
||||
@cmdutils.register(instance='prompt-queue', hide=True,
|
||||
modes=[usertypes.KeyMode.yesno],
|
||||
deprecated='Use :prompt-accept yes instead!')
|
||||
def prompt_yes(self):
|
||||
"""Answer yes to a yes/no prompt."""
|
||||
self.prompt_accept('yes')
|
||||
|
||||
@cmdutils.register(instance='prompt-container', hide=True, scope='window',
|
||||
@cmdutils.register(instance='prompt-queue', hide=True,
|
||||
modes=[usertypes.KeyMode.yesno],
|
||||
deprecated='Use :prompt-accept no instead!')
|
||||
def prompt_no(self):
|
||||
"""Answer no to a yes/no prompt."""
|
||||
self.prompt_accept('no')
|
||||
|
||||
@pyqtSlot(usertypes.KeyMode)
|
||||
def on_mode_left(self, mode):
|
||||
"""Clear and reset input when the mode was left."""
|
||||
# FIXME when is this not the case?
|
||||
if (self._prompt is not None and
|
||||
mode == self._prompt.KEY_MODE):
|
||||
question = self._prompt.question
|
||||
self._show_prompt(None)
|
||||
# FIXME move this somewhere else?
|
||||
if question.answer is None and not question.is_aborted:
|
||||
question.cancel()
|
||||
|
||||
@cmdutils.register(instance='prompt-container', hide=True, scope='window',
|
||||
@cmdutils.register(instance='prompt-queue', hide=True,
|
||||
modes=[usertypes.KeyMode.prompt], maxsplit=0)
|
||||
def prompt_open_download(self, cmdline: str=None):
|
||||
"""Immediately open a download.
|
||||
@ -265,7 +188,7 @@ class PromptContainer(QWidget):
|
||||
except UnsupportedOperationError:
|
||||
pass
|
||||
|
||||
@cmdutils.register(instance='prompt-container', hide=True, scope='window',
|
||||
@cmdutils.register(instance='prompt-queue', hide=True,
|
||||
modes=[usertypes.KeyMode.prompt])
|
||||
@cmdutils.argument('which', choices=['next', 'prev'])
|
||||
def prompt_item_focus(self, which):
|
||||
@ -323,7 +246,11 @@ class PromptContainer(QWidget):
|
||||
usertypes.PromptMode.alert: AlertPrompt,
|
||||
}
|
||||
klass = classes[question.mode]
|
||||
self._show_prompt(klass(question, self._win_id))
|
||||
|
||||
prompt = klass(question)
|
||||
self._prompt = prompt
|
||||
self.show_prompt.emit(prompt)
|
||||
|
||||
if blocking:
|
||||
loop = qtutils.EventLoop()
|
||||
self._loops.append(loop)
|
||||
@ -331,8 +258,10 @@ class PromptContainer(QWidget):
|
||||
question.completed.connect(loop.quit)
|
||||
question.completed.connect(loop.deleteLater)
|
||||
loop.exec_()
|
||||
self._prompt = prompt
|
||||
# FIXME don't we end up connecting modeman signals twice here now?
|
||||
if not self._show_prompt(old_prompt):
|
||||
self.show_prompt.emit(old_prompt)
|
||||
if old_prompt is None:
|
||||
# Nothing left to restore, so we can go back to popping async
|
||||
# questions.
|
||||
if self._queue:
|
||||
@ -341,6 +270,104 @@ class PromptContainer(QWidget):
|
||||
else:
|
||||
question.completed.connect(self._pop_later)
|
||||
|
||||
@pyqtSlot(usertypes.KeyMode)
|
||||
def on_mode_left(self, mode):
|
||||
"""Clear and reset input when the mode was left."""
|
||||
# FIXME when is this not the case?
|
||||
if (self._prompt is not None and
|
||||
mode == self._prompt.KEY_MODE):
|
||||
question = self._prompt.question
|
||||
self._prompt = None
|
||||
self.show_prompt.emit(None)
|
||||
# FIXME move this somewhere else?
|
||||
if question.answer is None and not question.is_aborted:
|
||||
question.cancel()
|
||||
|
||||
|
||||
class PromptContainer(QWidget):
|
||||
|
||||
"""Container for prompts to be shown above the statusbar.
|
||||
|
||||
This is a per-window object, however each window shows the same prompt.
|
||||
|
||||
Attributes:
|
||||
_layout: The layout used to show prompts in.
|
||||
_win_id: The window ID this object is associated with.
|
||||
|
||||
Signals:
|
||||
update_geometry: Emitted when the geometry should be updated.
|
||||
"""
|
||||
|
||||
STYLESHEET = """
|
||||
{% set prompt_radius = config.get('ui', 'prompt-radius') %}
|
||||
QWidget#PromptContainer {
|
||||
{% if config.get('ui', 'status-position') == 'top' %}
|
||||
border-bottom-left-radius: {{ prompt_radius }}px;
|
||||
border-bottom-right-radius: {{ prompt_radius }}px;
|
||||
{% else %}
|
||||
border-top-left-radius: {{ prompt_radius }}px;
|
||||
border-top-right-radius: {{ prompt_radius }}px;
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
QWidget {
|
||||
font: {{ font['prompts'] }};
|
||||
color: {{ color['prompts.fg'] }};
|
||||
background-color: {{ color['prompts.bg'] }};
|
||||
}
|
||||
"""
|
||||
update_geometry = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
super().__init__(parent)
|
||||
self._layout = QVBoxLayout(self)
|
||||
self._layout.setContentsMargins(10, 10, 10, 10)
|
||||
self._win_id = win_id
|
||||
|
||||
self.setObjectName('PromptContainer')
|
||||
self.setAttribute(Qt.WA_StyledBackground, True)
|
||||
style.set_register_stylesheet(self)
|
||||
|
||||
message.global_bridge.prompt_done.connect(self._on_prompt_done)
|
||||
prompt_queue.show_prompt.connect(self._on_show_prompt)
|
||||
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self, win_id=self._win_id)
|
||||
|
||||
@pyqtSlot(object)
|
||||
def _on_show_prompt(self, prompt):
|
||||
"""Show the given prompt object.
|
||||
|
||||
Args:
|
||||
prompt: A Prompt object or None.
|
||||
"""
|
||||
# Note that we don't delete the old prompt here, as we might be in the
|
||||
# middle of saving/restoring an old prompt object.
|
||||
# FIXME where is it deleted?
|
||||
self._layout.takeAt(0)
|
||||
assert self._layout.count() == 0
|
||||
log.prompt.debug("Displaying prompt {}".format(prompt))
|
||||
if prompt is None:
|
||||
self.hide()
|
||||
return
|
||||
|
||||
prompt.question.aborted.connect(
|
||||
lambda: modeman.maybe_leave(self._win_id, prompt.KEY_MODE,
|
||||
'aborted'))
|
||||
modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')
|
||||
|
||||
self.setSizePolicy(prompt.sizePolicy())
|
||||
self._layout.addWidget(prompt)
|
||||
prompt.show()
|
||||
self.show()
|
||||
prompt.setFocus()
|
||||
self.update_geometry.emit()
|
||||
|
||||
@pyqtSlot(usertypes.KeyMode)
|
||||
def _on_prompt_done(self, key_mode):
|
||||
"""Leave the prompt mode in this window if a question was answered."""
|
||||
modeman.maybe_leave(self._win_id, key_mode, ':prompt-accept')
|
||||
|
||||
|
||||
class LineEdit(QLineEdit):
|
||||
|
||||
@ -379,10 +406,9 @@ class _BasePrompt(QWidget):
|
||||
|
||||
KEY_MODE = usertypes.KeyMode.prompt
|
||||
|
||||
def __init__(self, question, win_id, parent=None):
|
||||
def __init__(self, question, parent=None):
|
||||
super().__init__(parent)
|
||||
self.question = question
|
||||
self._win_id = win_id
|
||||
self._vbox = QVBoxLayout(self)
|
||||
self._vbox.setSpacing(15)
|
||||
self._key_grid = None
|
||||
@ -448,8 +474,8 @@ class LineEditPrompt(_BasePrompt):
|
||||
|
||||
"""A prompt for a single text value."""
|
||||
|
||||
def __init__(self, question, win_id, parent=None):
|
||||
super().__init__(question, win_id, parent)
|
||||
def __init__(self, question, parent=None):
|
||||
super().__init__(question, parent)
|
||||
self._lineedit = LineEdit(self)
|
||||
self._init_title(question)
|
||||
self._vbox.addWidget(self._lineedit)
|
||||
@ -472,8 +498,8 @@ class FilenamePrompt(_BasePrompt):
|
||||
|
||||
"""A prompt for a filename."""
|
||||
|
||||
def __init__(self, question, win_id, parent=None):
|
||||
super().__init__(question, win_id, parent)
|
||||
def __init__(self, question, parent=None):
|
||||
super().__init__(question, parent)
|
||||
self._init_title(question)
|
||||
self._init_fileview()
|
||||
self._set_fileview_root(question.default)
|
||||
@ -584,8 +610,8 @@ class DownloadFilenamePrompt(FilenamePrompt):
|
||||
|
||||
"""A prompt for a filename for downloads."""
|
||||
|
||||
def __init__(self, question, win_id, parent=None):
|
||||
super().__init__(question, win_id, parent)
|
||||
def __init__(self, question, parent=None):
|
||||
super().__init__(question, parent)
|
||||
self._file_model.setFilter(QDir.AllDirs | QDir.Drives | QDir.NoDot)
|
||||
|
||||
def accept(self, value=None):
|
||||
@ -595,8 +621,9 @@ class DownloadFilenamePrompt(FilenamePrompt):
|
||||
|
||||
def download_open(self, cmdline):
|
||||
self.question.answer = usertypes.OpenFileDownloadTarget(cmdline)
|
||||
modeman.maybe_leave(self._win_id, usertypes.KeyMode.prompt,
|
||||
'download open')
|
||||
# FIXME now we don't have a window ID here...
|
||||
# modeman.maybe_leave(self._win_id, usertypes.KeyMode.prompt,
|
||||
# 'download open')
|
||||
self.question.done()
|
||||
|
||||
def _allowed_commands(self):
|
||||
@ -612,8 +639,8 @@ class AuthenticationPrompt(_BasePrompt):
|
||||
|
||||
"""A prompt for username/password."""
|
||||
|
||||
def __init__(self, question, win_id, parent=None):
|
||||
super().__init__(question, win_id, parent)
|
||||
def __init__(self, question, parent=None):
|
||||
super().__init__(question, parent)
|
||||
self._init_title(question)
|
||||
|
||||
user_label = QLabel("Username:", self)
|
||||
@ -672,8 +699,8 @@ class YesNoPrompt(_BasePrompt):
|
||||
|
||||
KEY_MODE = usertypes.KeyMode.yesno
|
||||
|
||||
def __init__(self, question, win_id, parent=None):
|
||||
super().__init__(question, win_id, parent)
|
||||
def __init__(self, question, parent=None):
|
||||
super().__init__(question, parent)
|
||||
self._init_title(question)
|
||||
self._init_key_label()
|
||||
|
||||
@ -709,8 +736,8 @@ class AlertPrompt(_BasePrompt):
|
||||
|
||||
"""A prompt without any answer possibility."""
|
||||
|
||||
def __init__(self, question, win_id, parent=None):
|
||||
super().__init__(question, win_id, parent)
|
||||
def __init__(self, question, parent=None):
|
||||
super().__init__(question, parent)
|
||||
self._init_title(question)
|
||||
self._init_key_label()
|
||||
|
||||
@ -722,3 +749,11 @@ class AlertPrompt(_BasePrompt):
|
||||
|
||||
def _allowed_commands(self):
|
||||
return [('prompt-accept', "Hide")]
|
||||
|
||||
|
||||
def init():
|
||||
global prompt_queue
|
||||
prompt_queue = PromptQueue()
|
||||
objreg.register('prompt-queue', prompt_queue) # for commands
|
||||
message.global_bridge.ask_question.connect(
|
||||
prompt_queue.ask_question, Qt.DirectConnection)
|
||||
|
@ -90,11 +90,10 @@ def _build_question(title, text=None, *, mode, default=None, abort_on=()):
|
||||
return question
|
||||
|
||||
|
||||
def ask(win_id, *args, **kwargs):
|
||||
def ask(*args, **kwargs):
|
||||
"""Ask a modular question in the statusbar (blocking).
|
||||
|
||||
Args:
|
||||
win_id: The ID of the window which is calling this function.
|
||||
message: The message to display to the user.
|
||||
mode: A PromptMode.
|
||||
default: The default value to display.
|
||||
@ -105,18 +104,16 @@ def ask(win_id, *args, **kwargs):
|
||||
The answer the user gave or None if the prompt was cancelled.
|
||||
"""
|
||||
question = _build_question(*args, **kwargs) # pylint: disable=missing-kwoa
|
||||
bridge = objreg.get('message-bridge', scope='window', window=win_id)
|
||||
bridge.ask(question, blocking=True)
|
||||
global_bridge.ask(question, blocking=True)
|
||||
answer = question.answer
|
||||
question.deleteLater()
|
||||
return answer
|
||||
|
||||
|
||||
def ask_async(win_id, text, mode, handler, **kwargs):
|
||||
def ask_async(text, mode, handler, **kwargs):
|
||||
"""Ask an async question in the statusbar.
|
||||
|
||||
Args:
|
||||
win_id: The ID of the window which is calling this function.
|
||||
message: The message to display to the user.
|
||||
mode: A PromptMode.
|
||||
handler: The function to get called with the answer as argument.
|
||||
@ -126,16 +123,14 @@ def ask_async(win_id, text, mode, handler, **kwargs):
|
||||
question = _build_question(text, mode=mode, **kwargs)
|
||||
question.answered.connect(handler)
|
||||
question.completed.connect(question.deleteLater)
|
||||
bridge = objreg.get('message-bridge', scope='window', window=win_id)
|
||||
bridge.ask(question, blocking=False)
|
||||
global_bridge.ask(question, blocking=False)
|
||||
|
||||
|
||||
def confirm_async(win_id, yes_action, no_action=None, cancel_action=None,
|
||||
def confirm_async(yes_action, no_action=None, cancel_action=None,
|
||||
*args, **kwargs):
|
||||
"""Ask a yes/no question to the user and execute the given actions.
|
||||
|
||||
Args:
|
||||
win_id: The ID of the window which is calling this function.
|
||||
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.
|
||||
@ -156,8 +151,7 @@ def confirm_async(win_id, yes_action, no_action=None, cancel_action=None,
|
||||
question.cancelled.connect(cancel_action)
|
||||
|
||||
question.completed.connect(question.deleteLater)
|
||||
bridge = objreg.get('message-bridge', scope='window', window=win_id)
|
||||
bridge.ask(question, blocking=False)
|
||||
global_bridge.ask(question, blocking=False)
|
||||
return question
|
||||
|
||||
|
||||
@ -169,9 +163,32 @@ class GlobalMessageBridge(QObject):
|
||||
show_message: Show a message
|
||||
arg 0: A MessageLevel member
|
||||
arg 1: The text to show
|
||||
prompt_done: Emitted when a prompt was answered somewhere.
|
||||
ask_question: Ask a question to the user.
|
||||
arg 0: The Question object to ask.
|
||||
arg 1: Whether to block (True) or ask async (False).
|
||||
|
||||
IMPORTANT: Slots need to be connected to this signal via
|
||||
a Qt.DirectConnection!
|
||||
"""
|
||||
|
||||
show_message = pyqtSignal(usertypes.MessageLevel, str)
|
||||
prompt_done = pyqtSignal(usertypes.KeyMode)
|
||||
ask_question = pyqtSignal(usertypes.Question, bool)
|
||||
|
||||
def ask(self, question, blocking, *, log_stack=False):
|
||||
"""Ask a question to the user.
|
||||
|
||||
Note this method doesn't return the answer, it only blocks. The caller
|
||||
needs to construct a Question object and get the answer.
|
||||
|
||||
Args:
|
||||
question: A Question object.
|
||||
blocking: Whether to return immediately or wait until the
|
||||
question is answered.
|
||||
log_stack: ignored
|
||||
"""
|
||||
self.ask_question.emit(question, blocking)
|
||||
|
||||
|
||||
class MessageBridge(QObject):
|
||||
@ -183,18 +200,10 @@ class MessageBridge(QObject):
|
||||
arg: The text to set.
|
||||
s_maybe_reset_text: Reset the text if it hasn't been changed yet.
|
||||
arg: The expected text.
|
||||
|
||||
s_question: Ask a question to the user in the statusbar.
|
||||
arg 0: The Question object to ask.
|
||||
arg 1: Whether to block (True) or ask async (False).
|
||||
|
||||
IMPORTANT: Slots need to be connected to this signal via a
|
||||
Qt.DirectConnection!
|
||||
"""
|
||||
|
||||
s_set_text = pyqtSignal(str)
|
||||
s_maybe_reset_text = pyqtSignal(str)
|
||||
s_question = pyqtSignal(usertypes.Question, bool)
|
||||
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self)
|
||||
@ -219,19 +228,5 @@ class MessageBridge(QObject):
|
||||
"""
|
||||
self.s_maybe_reset_text.emit(str(text))
|
||||
|
||||
def ask(self, question, blocking, *, log_stack=False):
|
||||
"""Ask a question to the user.
|
||||
|
||||
Note this method doesn't return the answer, it only blocks. The caller
|
||||
needs to construct a Question object and get the answer.
|
||||
|
||||
Args:
|
||||
question: A Question object.
|
||||
blocking: Whether to return immediately or wait until the
|
||||
question is answered.
|
||||
log_stack: ignored
|
||||
"""
|
||||
self.s_question.emit(question, blocking)
|
||||
|
||||
|
||||
global_bridge = GlobalMessageBridge()
|
||||
|
Loading…
Reference in New Issue
Block a user