Add key hints

This commit is contained in:
Florian Bruhin 2016-10-03 21:27:13 +02:00
parent f0ed43ec20
commit d74b0109c7

View File

@ -19,15 +19,16 @@
"""Showing prompts above the statusbar.""" """Showing prompts above the statusbar."""
import sip import html
import collections import collections
import sip
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QTimer from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QTimer
from PyQt5.QtWidgets import (QWidget, QGridLayout, QVBoxLayout, QLineEdit, from PyQt5.QtWidgets import (QWidget, QGridLayout, QVBoxLayout, QLineEdit,
QLabel, QSpacerItem, QWidgetItem) QLabel, QSpacerItem, QWidgetItem)
from qutebrowser.config import style, config from qutebrowser.config import style, config
from qutebrowser.utils import usertypes, log, utils, qtutils from qutebrowser.utils import usertypes, log, utils, qtutils, objreg
from qutebrowser.keyinput import modeman from qutebrowser.keyinput import modeman
from qutebrowser.commands import cmdutils from qutebrowser.commands import cmdutils
@ -338,6 +339,7 @@ class _BasePrompt(QWidget):
self.question = question self.question = question
self._vbox = QVBoxLayout(self) self._vbox = QVBoxLayout(self)
self._vbox.setSpacing(15) self._vbox.setSpacing(15)
self._key_grid = None
def __repr__(self): def __repr__(self):
return utils.get_repr(self, question=self.question, constructor=True) return utils.get_repr(self, question=self.question, constructor=True)
@ -350,12 +352,49 @@ class _BasePrompt(QWidget):
text_label = QLabel(question.text) text_label = QLabel(question.text)
self._vbox.addWidget(text_label) self._vbox.addWidget(text_label)
def _init_key_label(self):
# Remove old grid
if self._key_grid is not None:
self._key_grid.hide()
self._vbox.removeWidget(self._key_grid)
self._key_grid = QGridLayout()
self._key_grid.setVerticalSpacing(0)
key_config = objreg.get('key-config')
all_bindings = key_config.get_reverse_bindings_for(self.KEY_MODE.name)
labels = []
for cmd, text in self._allowed_commands():
bindings = all_bindings.get(cmd, [])
if bindings:
binding = None
preferred = ['<enter>', '<escape>']
for pref in preferred:
if pref in bindings:
binding = pref
if binding is None:
binding = bindings[0]
key_label = QLabel('<b>{}</b>'.format(html.escape(binding)))
text_label = QLabel(text)
labels.append((key_label, text_label))
for i, (key_label, text_label) in enumerate(labels):
self._key_grid.addWidget(key_label, i, 0)
self._key_grid.addWidget(text_label, i, 1)
self._vbox.addLayout(self._key_grid)
def accept(self, value=None): def accept(self, value=None):
raise NotImplementedError raise NotImplementedError
def open_download(self, _cmdline): def open_download(self, _cmdline):
raise UnsupportedOperationError raise UnsupportedOperationError
def _allowed_commands(self):
"""Get the commands we could run as response to this message."""
raise NotImplementedError
class LineEditPrompt(_BasePrompt): class LineEditPrompt(_BasePrompt):
@ -367,28 +406,22 @@ class LineEditPrompt(_BasePrompt):
if question.default: if question.default:
self._lineedit.setText(question.default) self._lineedit.setText(question.default)
self.setFocusProxy(self._lineedit) self.setFocusProxy(self._lineedit)
self._init_key_label()
def accept(self, value=None): def accept(self, value=None):
text = value if value is not None else self._lineedit.text() text = value if value is not None else self._lineedit.text()
self.question.answer = text self.question.answer = text
return True return True
def _allowed_commands(self):
"""Get the commands we could run as response to this message."""
return [('prompt-accept', 'Accept'), ('leave-mode', 'Abort')]
class DownloadFilenamePrompt(LineEditPrompt): class DownloadFilenamePrompt(LineEditPrompt):
# FIXME have a FilenamePrompt # FIXME have a FilenamePrompt
def __init__(self, question, parent=None):
super().__init__(question, parent)
# FIXME show :prompt-open-download keybinding
# key_mode = self.KEY_MODES[self.question.mode]
# key_config = objreg.get('key-config')
# all_bindings = key_config.get_reverse_bindings_for(key_mode.name)
# bindings = all_bindings.get('prompt-open-download', [])
# if bindings:
# text += ' ({} to open)'.format(bindings[0])
def accept(self, value=None): def accept(self, value=None):
text = value if value is not None else self._lineedit.text() text = value if value is not None else self._lineedit.text()
self.question.answer = usertypes.FileDownloadTarget(text) self.question.answer = usertypes.FileDownloadTarget(text)
@ -400,6 +433,14 @@ class DownloadFilenamePrompt(LineEditPrompt):
'download open') 'download open')
self.question.done() self.question.done()
def _allowed_commands(self):
cmds = [
('prompt-accept', 'Accept'),
('leave-mode', 'Abort'),
('prompt-open-download', "Open download"),
]
return cmds
class AuthenticationPrompt(_BasePrompt): class AuthenticationPrompt(_BasePrompt):
@ -420,6 +461,7 @@ class AuthenticationPrompt(_BasePrompt):
grid.addWidget(password_label, 2, 0) grid.addWidget(password_label, 2, 0)
grid.addWidget(self._password_lineedit, 2, 1) grid.addWidget(self._password_lineedit, 2, 1)
self._vbox.addLayout(grid) self._vbox.addLayout(grid)
self._init_key_label()
assert not question.default, question.default assert not question.default, question.default
self.setFocusProxy(self._user_lineedit) self.setFocusProxy(self._user_lineedit)
@ -437,12 +479,21 @@ class AuthenticationPrompt(_BasePrompt):
# Earlier, tab was bound to :prompt-accept, so to still support that # Earlier, tab was bound to :prompt-accept, so to still support that
# we simply switch the focus when tab was pressed. # we simply switch the focus when tab was pressed.
self._password_lineedit.setFocus() self._password_lineedit.setFocus()
self._init_key_label()
return False return False
else: else:
self.question.answer = AuthTuple(self._user_lineedit.text(), self.question.answer = AuthTuple(self._user_lineedit.text(),
self._password_lineedit.text()) self._password_lineedit.text())
return True return True
def _allowed_commands(self):
if self._user_lineedit.hasFocus():
cmds = [('prompt-accept', "Switch to password field")]
else:
cmds = [('prompt-accept', "Accept")]
cmds.append(('leave-mode', "Abort"))
return cmds
class YesNoPrompt(_BasePrompt): class YesNoPrompt(_BasePrompt):
@ -451,10 +502,7 @@ class YesNoPrompt(_BasePrompt):
def __init__(self, question, parent=None): def __init__(self, question, parent=None):
super().__init__(question, parent) super().__init__(question, parent)
self._init_title(question) self._init_title(question)
# FIXME self._init_key_label()
# "Enter/y: yes"
# "n: no"
# (depending on default)
def accept(self, value=None): def accept(self, value=None):
if value is None: if value is None:
@ -467,17 +515,29 @@ class YesNoPrompt(_BasePrompt):
raise Error("Invalid value {} - expected yes/no!".format(value)) raise Error("Invalid value {} - expected yes/no!".format(value))
return True return True
def _allowed_commands(self):
cmds = [
('prompt-accept',
"Use default ({})".format(self.question.default)),
('prompt-accept yes', "Yes"),
('prompt-accept no', "No"),
('leave-mode', "Abort"),
]
return cmds
class AlertPrompt(_BasePrompt): class AlertPrompt(_BasePrompt):
def __init__(self, question, parent=None): def __init__(self, question, parent=None):
super().__init__(question, parent) super().__init__(question, parent)
self._init_title(question) self._init_title(question)
# FIXME self._init_key_label()
# Enter: acknowledge
def accept(self, value=None): def accept(self, value=None):
if value is not None: if value is not None:
raise Error("No value is permitted with alert prompts!") raise Error("No value is permitted with alert prompts!")
# Doing nothing otherwise # Doing nothing otherwise
return True return True
def _allowed_commands(self):
return [('prompt-accept', "Hide")]