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.bg,statusbar.bg>>|Foreground color of the statusbar.
|<<colors-statusbar.fg,statusbar.fg>>|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.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.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.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. |<<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]+ 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]] [[colors-statusbar.bg.prompt]]
=== statusbar.bg.prompt === statusbar.bg.prompt
Background color of the statusbar if there is a prompt. Background color of the statusbar if there is a prompt.

View File

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

View File

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