Make it possible to display warnings in the bar.

Closes #114.
This commit is contained in:
Florian Bruhin 2015-01-15 21:27:36 +01:00
parent 48c83505df
commit 223f8f243e
5 changed files with 100 additions and 34 deletions

View File

@ -159,6 +159,7 @@
|<<colors-statusbar.bg,statusbar.bg>>|Foreground color of the statusbar.
|<<colors-statusbar.fg,statusbar.fg>>|Foreground color of the statusbar.
|<<colors-statusbar.bg.error,statusbar.bg.error>>|Background color of the statusbar if there was an error.
|<<colors-statusbar.bg.warning,statusbar.bg.warning>>|Background color of the statusbar if there is a warning.
|<<colors-statusbar.bg.prompt,statusbar.bg.prompt>>|Background color of the statusbar if there is a prompt.
|<<colors-statusbar.bg.insert,statusbar.bg.insert>>|Background color of the statusbar in insert mode.
|<<colors-statusbar.progress.bg,statusbar.progress.bg>>|Background color of the progress bar.
@ -1207,6 +1208,12 @@ Background color of the statusbar if there was an error.
Default: +pass:[red]+
[[colors-statusbar.bg.warning]]
=== statusbar.bg.warning
Background color of the statusbar if there is a warning.
Default: +pass:[darkorange]+
[[colors-statusbar.bg.prompt]]
=== statusbar.bg.prompt
Background color of the statusbar if there is a prompt.

View File

@ -642,6 +642,10 @@ DATA = collections.OrderedDict([
SettingValue(typ.QssColor(), 'red'),
"Background color of the statusbar if there was an error."),
('statusbar.bg.warning',
SettingValue(typ.QssColor(), 'darkorange'),
"Background color of the statusbar if there is a warning."),
('statusbar.bg.prompt',
SettingValue(typ.QssColor(), 'darkblue'),
"Background color of the statusbar if there is a prompt."),

View File

@ -224,6 +224,7 @@ class MainWindow(QWidget):
# messages
message_bridge.s_error.connect(status.disp_error)
message_bridge.s_warning.connect(status.disp_warning)
message_bridge.s_info.connect(status.disp_temp_text)
message_bridge.s_set_text.connect(status.set_text)
message_bridge.s_maybe_reset_text.connect(status.txt.maybe_reset_text)

View File

@ -33,6 +33,7 @@ from qutebrowser.mainwindow.statusbar import text as textwidget
PreviousWidget = usertypes.enum('PreviousWidget', ['none', 'prompt',
'command'])
Severity = usertypes.enum('Severity', ['normal', 'warning', 'error'])
class StatusBar(QWidget):
@ -59,11 +60,10 @@ class StatusBar(QWidget):
_win_id: The window ID the statusbar is associated with.
Class attributes:
_error: If there currently is an error, accessed through the error
property.
_severity: The severity of the current message, a Severity member.
For some reason we need to have this as class attribute so
pyqtProperty works correctly.
For some reason we need to have this as class attribute so
pyqtProperty works correctly.
_prompt_active: If we're currently in prompt-mode.
@ -86,7 +86,7 @@ class StatusBar(QWidget):
resized = pyqtSignal('QRect')
moved = pyqtSignal('QPoint')
_error = False
_severity = None
_prompt_active = False
_insert_active = False
@ -103,10 +103,14 @@ class StatusBar(QWidget):
{{ color['statusbar.bg.prompt'] }}
}
QWidget#StatusBar[error="true"] {
QWidget#StatusBar[severity="error"] {
{{ color['statusbar.bg.error'] }}
}
QWidget#StatusBar[severity="warning"] {
{{ color['statusbar.bg.warning'] }}
}
QLabel, QLineEdit {
{{ color['statusbar.fg'] }}
{{ font['statusbar'] }}
@ -178,27 +182,37 @@ class StatusBar(QWidget):
def __repr__(self):
return utils.get_repr(self)
@pyqtProperty(bool)
def error(self):
"""Getter for self.error, so it can be used as Qt property."""
# pylint: disable=method-hidden
return self._error
@pyqtProperty(str)
def severity(self):
"""Getter for self.severity, so it can be used as Qt property.
def _set_error(self, val):
"""Setter for self.error, so it can be used as Qt property.
Return:
The severity as a string (!)
"""
# pylint: disable=method-hidden
if self._severity is None:
return ""
else:
return self._severity.name
def _set_severity(self, severity):
"""Set the severity for the current message.
Re-set the stylesheet after setting the value, so everything gets
updated by Qt properly.
Args:
severity: A Severity member.
"""
if self._error == val:
if self._severity == severity:
# This gets called a lot (e.g. if the completion selection was
# changed), and setStyleSheet is relatively expensive, so we ignore
# this if there's nothing to change.
return
log.statusbar.debug("Setting error to {}".format(val))
self._error = val
log.statusbar.debug("Setting severity to {}".format(severity))
self._severity = severity
self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
if val:
if severity != Severity.normal:
# If we got an error while command/prompt was shown, raise the text
# widget.
self._stack.setCurrentWidget(self.txt)
@ -243,9 +257,9 @@ class StatusBar(QWidget):
def _pop_text(self):
"""Display a text in the statusbar and pop it from _text_queue."""
try:
error, text = self._text_queue.popleft()
severity, text = self._text_queue.popleft()
except IndexError:
self._set_error(False)
self._set_severity(Severity.normal)
self.txt.set_text(self.txt.Text.temp, '')
self._text_pop_timer.stop()
# If a previous widget was interrupted by an error, restore it.
@ -258,15 +272,15 @@ class StatusBar(QWidget):
else:
raise AssertionError("Unknown _previous_widget!")
return
log.statusbar.debug("Displaying {} message: {}".format(
'error' if error else 'text', text))
log.statusbar.debug("Displaying message: {} (severity {})".format(
text, severity))
log.statusbar.debug("Remaining: {}".format(self._text_queue))
self._set_error(error)
self._set_severity(severity)
self.txt.set_text(self.txt.Text.temp, text)
def _show_cmd_widget(self):
"""Show command widget instead of temporary text."""
self._set_error(False)
self._set_severity(Severity.normal)
self._previous_widget = PreviousWidget.prompt
if self._text_pop_timer.isActive():
self._timer_was_active = True
@ -289,7 +303,7 @@ class StatusBar(QWidget):
"""Show prompt widget instead of temporary text."""
if self._stack.currentWidget() is self.prompt:
return
self._set_error(False)
self._set_severity(Severity.normal)
self._set_prompt_active(True)
self._previous_widget = PreviousWidget.prompt
if self._text_pop_timer.isActive():
@ -310,17 +324,17 @@ class StatusBar(QWidget):
self._timer_was_active = False
self._stack.setCurrentWidget(self.txt)
def _disp_text(self, text, error, immediately=False):
def _disp_text(self, text, severity, immediately=False):
"""Inner logic for disp_error and disp_temp_text.
Args:
text: The message to display.
error: Whether it's an error message (True) or normal text (False)
severity: The severity of the messages.
immediately: If set, message gets displayed immediately instead of
queued.
"""
log.statusbar.debug("Displaying text: {} (error={})".format(
text, error))
log.statusbar.debug("Displaying text: {} (severity={})".format(
text, severity))
mindelta = config.get('ui', 'message-timeout')
if self._stopwatch.isNull():
delta = None
@ -335,10 +349,10 @@ class StatusBar(QWidget):
# immediately. We then start the pop_timer only to restore the
# normal state in 2 seconds.
log.statusbar.debug("Displaying immediately")
self._set_error(error)
self._set_severity(severity)
self.txt.set_text(self.txt.Text.temp, text)
self._text_pop_timer.start()
elif self._text_queue and self._text_queue[-1] == (error, text):
elif self._text_queue and self._text_queue[-1] == (severity, text):
# If we get the same message multiple times in a row and we're
# still displaying it *anyways* we ignore the new one
log.statusbar.debug("ignoring")
@ -348,14 +362,14 @@ class StatusBar(QWidget):
# We display this immediately and restart the timer.to clear it and
# display the rest of the queue later.
log.statusbar.debug("Moving to beginning of queue")
self._set_error(error)
self._set_severity(severity)
self.txt.set_text(self.txt.Text.temp, text)
self._text_pop_timer.start()
else:
# There are still some messages to be displayed, so we queue this
# up.
log.statusbar.debug("queueing")
self._text_queue.append((error, text))
self._text_queue.append((severity, text))
self._text_pop_timer.start()
@pyqtSlot(str, bool)
@ -367,7 +381,18 @@ class StatusBar(QWidget):
immediately: If set, message gets displayed immediately instead of
queued.
"""
self._disp_text(text, True, immediately)
self._disp_text(text, Severity.error, immediately)
@pyqtSlot(str, bool)
def disp_warning(self, text, immediately=False):
"""Display a warning in the statusbar.
Args:
text: The message to display.
immediately: If set, message gets displayed immediately instead of
queued.
"""
self._disp_text(text, Severity.warning, immediately)
@pyqtSlot(str, bool)
def disp_temp_text(self, text, immediately):
@ -378,7 +403,7 @@ class StatusBar(QWidget):
immediately: If set, message gets displayed immediately instead of
queued.
"""
self._disp_text(text, False, immediately)
self._disp_text(text, Severity.normal, immediately)
@pyqtSlot(str)
def set_text(self, val):

View File

@ -40,6 +40,17 @@ def error(win_id, message, immediately=False):
0, lambda: _get_bridge(win_id).error(message, immediately))
def warning(win_id, message, immediately=False):
"""Convienience function to display a warning message in the statusbar.
Args:
win_id: The ID of the window which is calling this function.
others: See MessageBridge.warning.
"""
QTimer.singleShot(
0, lambda: _get_bridge(win_id).warning(message, immediately))
def info(win_id, message, immediately=True):
"""Convienience function to display an info message in the statusbar.
@ -146,6 +157,8 @@ class MessageBridge(QObject):
(False).
s_info: Display an info message.
args: See s_error.
s_warning: Display a warning message.
args: See s_error.
s_set_text: Set a persistent text in the statusbar.
arg: The text to set.
s_maybe_reset_text: Reset the text if it hasn't been changed yet.
@ -162,6 +175,7 @@ class MessageBridge(QObject):
"""
s_error = pyqtSignal(str, bool)
s_warning = pyqtSignal(str, bool)
s_info = pyqtSignal(str, bool)
s_set_text = pyqtSignal(str)
s_maybe_reset_text = pyqtSignal(str)
@ -199,6 +213,21 @@ class MessageBridge(QObject):
log.misc.error(msg)
self._emit_later(self.s_error, msg, immediately)
def warning(self, msg, immediately=False):
"""Display an warning in the statusbar.
Args:
msg: The message to show.
immediately: Whether to display the message immediately (True) or
queue it for displaying when all other messages are
displayed (False). Messages resulting from direct user
input should be displayed immediately, all other
messages should be queued.
"""
msg = str(msg)
log.misc.warning(msg)
self._emit_later(self.s_warning, msg, immediately)
def info(self, msg, immediately=True):
"""Display an info text in the statusbar.