Making it so I can track states in the log
[gc-dialer] / src / util / qui_utils.py
index 59f8802..251e571 100644 (file)
@@ -1,4 +1,5 @@
 import sys
+import contextlib
 import logging
 
 from PyQt4 import QtCore
@@ -10,6 +11,33 @@ import misc
 _moduleLogger = logging.getLogger(__name__)
 
 
+@contextlib.contextmanager
+def notify_error(log):
+       try:
+               yield
+       except:
+               log.push_exception()
+
+
+class ErrorMessage(object):
+
+       LEVEL_BUSY = "busy"
+       LEVEL_INFO = "info"
+       LEVEL_ERROR = "error"
+
+       def __init__(self, message, level):
+               self._message = message
+               self._level = level
+
+       @property
+       def level(self):
+               return self._level
+
+       @property
+       def message(self):
+               return self._message
+
+
 class QErrorLog(QtCore.QObject):
 
        messagePushed = QtCore.pyqtSignal()
@@ -19,49 +47,90 @@ class QErrorLog(QtCore.QObject):
                QtCore.QObject.__init__(self)
                self._messages = []
 
+       def push_busy(self, message):
+               _moduleLogger.info("Entering state: %s" % message)
+               self._push_message(message, ErrorMessage.LEVEL_BUSY)
+
        def push_message(self, message):
-               self._messages.append(message)
-               self.messagePushed.emit()
+               self._push_message(message, ErrorMessage.LEVEL_INFO)
+
+       def push_error(self, message):
+               self._push_message(message, ErrorMessage.LEVEL_ERROR)
 
        def push_exception(self):
                userMessage = str(sys.exc_info()[1])
                _moduleLogger.exception(userMessage)
-               self.push_message(userMessage)
+               self.push_error(userMessage)
 
-       def pop_message(self):
-               del self._messages[0]
+       def pop(self, message = None):
+               if message is None:
+                       del self._messages[0]
+               else:
+                       _moduleLogger.info("Exiting state: %s" % message)
+                       messageIndex = [
+                               i
+                               for (i, error) in enumerate(self._messages)
+                               if error.message == message
+                       ]
+                       # Might be removed out of order
+                       if messageIndex:
+                               del self._messages[messageIndex[0]]
                self.messagePopped.emit()
 
        def peek_message(self):
                return self._messages[0]
 
+       def _push_message(self, message, level):
+               self._messages.append(ErrorMessage(message, level))
+               self.messagePushed.emit()
+
        def __len__(self):
                return len(self._messages)
 
 
 class ErrorDisplay(object):
 
+       _SENTINEL_ICON = QtGui.QIcon()
+
        def __init__(self, errorLog):
                self._errorLog = errorLog
                self._errorLog.messagePushed.connect(self._on_message_pushed)
                self._errorLog.messagePopped.connect(self._on_message_popped)
 
-               errorIcon = get_theme_icon(("dialog-error", "app_install_error", "gtk-dialog-error"))
-               self._severityIcon = errorIcon.pixmap(32, 32)
+               self._icons = {
+                       ErrorMessage.LEVEL_BUSY:
+                               get_theme_icon(
+                                       #("process-working", "gtk-refresh")
+                                       ("gtk-refresh", )
+                               ).pixmap(32, 32),
+                       ErrorMessage.LEVEL_INFO:
+                               get_theme_icon(
+                                       ("dialog-information", "general_notes", "gtk-info")
+                               ).pixmap(32, 32),
+                       ErrorMessage.LEVEL_ERROR:
+                               get_theme_icon(
+                                       ("dialog-error", "app_install_error", "gtk-dialog-error")
+                               ).pixmap(32, 32),
+               }
                self._severityLabel = QtGui.QLabel()
-               self._severityLabel.setPixmap(self._severityIcon)
+               self._severityLabel.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
 
                self._message = QtGui.QLabel()
                self._message.setText("Boo")
+               self._message.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
+               self._message.setWordWrap(True)
 
-               closeIcon = get_theme_icon(("window-close", "general_close", "gtk-close"))
-               self._closeLabel = QtGui.QPushButton(closeIcon, "")
+               closeIcon = get_theme_icon(("window-close", "general_close", "gtk-close"), self._SENTINEL_ICON)
+               if closeIcon is not self._SENTINEL_ICON:
+                       self._closeLabel = QtGui.QPushButton(closeIcon, "")
+               else:
+                       self._closeLabel = QtGui.QPushButton("X")
                self._closeLabel.clicked.connect(self._on_close)
 
                self._controlLayout = QtGui.QHBoxLayout()
-               self._controlLayout.addWidget(self._severityLabel)
-               self._controlLayout.addWidget(self._message)
-               self._controlLayout.addWidget(self._closeLabel)
+               self._controlLayout.addWidget(self._severityLabel, 1, QtCore.Qt.AlignCenter)
+               self._controlLayout.addWidget(self._message, 1000)
+               self._controlLayout.addWidget(self._closeLabel, 1, QtCore.Qt.AlignCenter)
 
                self._topLevelLayout = QtGui.QHBoxLayout()
                self._topLevelLayout.addLayout(self._controlLayout)
@@ -77,13 +146,15 @@ class ErrorDisplay(object):
        @QtCore.pyqtSlot(bool)
        @misc.log_exception(_moduleLogger)
        def _on_close(self, checked = False):
-               self._errorLog.pop_message()
+               self._errorLog.pop()
 
        @QtCore.pyqtSlot()
        @misc.log_exception(_moduleLogger)
        def _on_message_pushed(self):
                if 1 <= len(self._errorLog) and self._widget.isHidden():
-                       self._message.setText(self._errorLog.peek_message())
+                       error = self._errorLog.peek_message()
+                       self._message.setText(error.message)
+                       self._severityLabel.setPixmap(self._icons[error.level])
                        self._widget.show()
 
        @QtCore.pyqtSlot()
@@ -93,12 +164,13 @@ class ErrorDisplay(object):
                        self._message.setText("")
                        self._widget.hide()
                else:
-                       self._message.setText(self._errorLog.peek_message())
+                       error = self._errorLog.peek_message()
+                       self._message.setText(error.message)
+                       self._severityLabel.setPixmap(self._icons[error.level])
 
 
 class QHtmlDelegate(QtGui.QStyledItemDelegate):
 
-       # @bug Doesn't show properly with dark themes (Maemo)
        # @bug Not showing all of a message
 
        def paint(self, painter, option, index):
@@ -125,6 +197,14 @@ class QHtmlDelegate(QtGui.QStyledItemDelegate):
                                        QtGui.QPalette.HighlightedText
                                )
                        )
+               else:
+                       ctx.palette.setColor(
+                               QtGui.QPalette.Text,
+                               newOption.palette.color(
+                                       QtGui.QPalette.Active,
+                                       QtGui.QPalette.Text
+                               )
+                       )
 
                textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, newOption)
                painter.save()