Forcing a refresh
[gc-dialer] / src / util / qui_utils.py
index 41ed1bd..9e33f88 100644 (file)
@@ -1,5 +1,6 @@
 import sys
 import contextlib
+import datetime
 import logging
 
 from PyQt4 import QtCore
@@ -19,15 +20,25 @@ def notify_error(log):
                log.push_exception()
 
 
+@contextlib.contextmanager
+def notify_busy(log, message):
+       log.push_busy(message)
+       try:
+               yield
+       finally:
+               log.pop(message)
+
+
 class ErrorMessage(object):
 
-       LEVEL_BUSY = "busy"
-       LEVEL_INFO = "info"
-       LEVEL_ERROR = "error"
+       LEVEL_ERROR = 0
+       LEVEL_BUSY = 1
+       LEVEL_INFO = 2
 
        def __init__(self, message, level):
                self._message = message
                self._level = level
+               self._time = datetime.datetime.now()
 
        @property
        def level(self):
@@ -37,6 +48,9 @@ class ErrorMessage(object):
        def message(self):
                return self._message
 
+       def __repr__(self):
+               return "%s.%s(%r, %r)" % (__name__, self.__class__.__name__, self._message, self._level)
+
 
 class QErrorLog(QtCore.QObject):
 
@@ -48,6 +62,7 @@ class QErrorLog(QtCore.QObject):
                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):
@@ -65,6 +80,7 @@ class QErrorLog(QtCore.QObject):
                if message is None:
                        del self._messages[0]
                else:
+                       _moduleLogger.info("Exiting state: %s" % message)
                        messageIndex = [
                                i
                                for (i, error) in enumerate(self._messages)
@@ -80,6 +96,8 @@ class QErrorLog(QtCore.QObject):
 
        def _push_message(self, message, level):
                self._messages.append(ErrorMessage(message, level))
+               # Sort is defined as stable, so this should be fine
+               self._messages.sort(key=lambda x: x.level)
                self.messagePushed.emit()
 
        def __len__(self):
@@ -98,8 +116,8 @@ class ErrorDisplay(object):
                self._icons = {
                        ErrorMessage.LEVEL_BUSY:
                                get_theme_icon(
-                                       #("process-working", "gtk-refresh")
-                                       ("gtk-refresh", )
+                                       #("process-working", "view-refresh", "general_refresh", "gtk-refresh")
+                                       ("view-refresh", "general_refresh", "gtk-refresh", )
                                ).pixmap(32, 32),
                        ErrorMessage.LEVEL_INFO:
                                get_theme_icon(
@@ -116,6 +134,7 @@ class ErrorDisplay(object):
                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._SENTINEL_ICON)
                if closeIcon is not self._SENTINEL_ICON:
@@ -129,16 +148,20 @@ class ErrorDisplay(object):
                self._controlLayout.addWidget(self._message, 1000)
                self._controlLayout.addWidget(self._closeLabel, 1, QtCore.Qt.AlignCenter)
 
-               self._topLevelLayout = QtGui.QHBoxLayout()
-               self._topLevelLayout.addLayout(self._controlLayout)
                self._widget = QtGui.QWidget()
-               self._widget.setLayout(self._topLevelLayout)
+               self._widget.setLayout(self._controlLayout)
                self._widget.hide()
 
        @property
        def toplevel(self):
                return self._widget
 
+       def _show_error(self):
+               error = self._errorLog.peek_message()
+               self._message.setText(error.message)
+               self._severityLabel.setPixmap(self._icons[error.level])
+               self._widget.show()
+
        @QtCore.pyqtSlot()
        @QtCore.pyqtSlot(bool)
        @misc.log_exception(_moduleLogger)
@@ -148,11 +171,7 @@ class ErrorDisplay(object):
        @QtCore.pyqtSlot()
        @misc.log_exception(_moduleLogger)
        def _on_message_pushed(self):
-               if 1 <= len(self._errorLog) and self._widget.isHidden():
-                       error = self._errorLog.peek_message()
-                       self._message.setText(error.message)
-                       self._severityLabel.setPixmap(self._icons[error.level])
-                       self._widget.show()
+               self._show_error()
 
        @QtCore.pyqtSlot()
        @misc.log_exception(_moduleLogger)
@@ -161,14 +180,16 @@ class ErrorDisplay(object):
                        self._message.setText("")
                        self._widget.hide()
                else:
-                       error = self._errorLog.peek_message()
-                       self._message.setText(error.message)
-                       self._severityLabel.setPixmap(self._icons[error.level])
+                       self._show_error()
 
 
 class QHtmlDelegate(QtGui.QStyledItemDelegate):
 
-       # @bug Not showing all of a message
+       UNDEFINED_SIZE = -1
+
+       def __init__(self, *args, **kwd):
+               QtGui.QStyledItemDelegate.__init__(*((self, ) + args), **kwd)
+               self._width = self.UNDEFINED_SIZE
 
        def paint(self, painter, option, index):
                newOption = QtGui.QStyleOptionViewItemV4(option)
@@ -210,17 +231,55 @@ class QHtmlDelegate(QtGui.QStyledItemDelegate):
                doc.documentLayout().draw(painter, ctx)
                painter.restore()
 
+       def setWidth(self, width, model):
+               if self._width == width:
+                       return
+               self._width = width
+               for c in xrange(model.rowCount()):
+                       cItem = model.item(c, 0)
+                       for r in xrange(model.rowCount()):
+                               rItem = cItem.child(r, 0)
+                               rIndex = model.indexFromItem(rItem)
+                               self.sizeHintChanged.emit(rIndex)
+                               return
+
        def sizeHint(self, option, index):
                newOption = QtGui.QStyleOptionViewItemV4(option)
                self.initStyleOption(newOption, index)
 
                doc = QtGui.QTextDocument()
                doc.setHtml(newOption.text)
-               doc.setTextWidth(newOption.rect.width())
+               if self._width != self.UNDEFINED_SIZE:
+                       width = self._width
+               else:
+                       width = newOption.rect.width()
+               doc.setTextWidth(width)
                size = QtCore.QSize(doc.idealWidth(), doc.size().height())
                return size
 
 
+class QSignalingMainWindow(QtGui.QMainWindow):
+
+       closed = QtCore.pyqtSignal()
+       hidden = QtCore.pyqtSignal()
+       shown = QtCore.pyqtSignal()
+
+       def __init__(self, *args, **kwd):
+               QtGui.QMainWindow.__init__(*((self, )+args), **kwd)
+
+       def closeEvent(self, event):
+               QtGui.QMainWindow.closeEvent(self, event)
+               self.closed.emit()
+
+       def hideEvent(self, event):
+               QtGui.QMainWindow.hideEvent(self, event)
+               self.hidden.emit()
+
+       def showEvent(self, event):
+               QtGui.QMainWindow.showEvent(self, event)
+               self.shown.emit()
+
+
 def _null_set_stackable(window, isStackable):
        pass
 
@@ -241,7 +300,7 @@ def _null_set_autorient(window, isStackable):
 
 
 def _maemo_set_autorient(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+       window.setAttribute(QtCore.Qt.WA_Maemo5AutoOrientation, isStackable)
 
 
 try:
@@ -251,34 +310,35 @@ except AttributeError:
        set_autorient = _null_set_autorient
 
 
-def _null_set_landscape(window, isStackable):
-       pass
-
-
-def _maemo_set_landscape(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
-
-
-try:
-       QtCore.Qt.WA_Maemo5LandscapeOrientation
-       set_landscape = _maemo_set_landscape
-except AttributeError:
-       set_landscape = _null_set_landscape
+def screen_orientation():
+       geom = QtGui.QApplication.desktop().screenGeometry()
+       if geom.width() <= geom.height():
+               return QtCore.Qt.Vertical
+       else:
+               return QtCore.Qt.Horizontal
 
 
-def _null_set_portrait(window, isStackable):
+def _null_set_window_orientation(window, orientation):
        pass
 
 
-def _maemo_set_portrait(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+def _maemo_set_window_orientation(window, orientation):
+       if orientation == QtCore.Qt.Vertical:
+               oldHint = QtCore.Qt.WA_Maemo5LandscapeOrientation
+               newHint = QtCore.Qt.WA_Maemo5PortraitOrientation
+       elif orientation == QtCore.Qt.Horizontal:
+               oldHint = QtCore.Qt.WA_Maemo5PortraitOrientation
+               newHint = QtCore.Qt.WA_Maemo5LandscapeOrientation
+       window.setAttribute(oldHint, False)
+       window.setAttribute(newHint, True)
 
 
 try:
+       QtCore.Qt.WA_Maemo5LandscapeOrientation
        QtCore.Qt.WA_Maemo5PortraitOrientation
-       set_portrait = _maemo_set_portrait
+       set_window_orientation = _maemo_set_window_orientation
 except AttributeError:
-       set_portrait = _null_set_portrait
+       set_window_orientation = _null_set_window_orientation
 
 
 def _null_show_progress_indicator(window, isStackable):
@@ -286,7 +346,7 @@ def _null_show_progress_indicator(window, isStackable):
 
 
 def _maemo_show_progress_indicator(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+       window.setAttribute(QtCore.Qt.WA_Maemo5ShowProgressIndicator, isStackable)
 
 
 try:
@@ -311,14 +371,6 @@ except AttributeError:
        mark_numbers_preferred = _null_mark_numbers_preferred
 
 
-def screen_orientation():
-       geom = QtGui.QApplication.desktop().screenGeometry()
-       if geom.width() <= geom.height():
-               return QtCore.Qt.Vertical
-       else:
-               return QtCore.Qt.Horizontal
-
-
 def _null_get_theme_icon(iconNames, fallback = None):
        icon = fallback if fallback is not None else QtGui.QIcon()
        return icon