5 from PyQt4 import QtCore
6 from PyQt4 import QtGui
11 _moduleLogger = logging.getLogger(__name__)
14 @contextlib.contextmanager
15 def notify_error(log):
22 class ErrorMessage(object):
28 def __init__(self, message, level):
29 self._message = message
41 class QErrorLog(QtCore.QObject):
43 messagePushed = QtCore.pyqtSignal()
44 messagePopped = QtCore.pyqtSignal()
47 QtCore.QObject.__init__(self)
50 def push_busy(self, message):
51 self._push_message(message, ErrorMessage.LEVEL_BUSY)
53 def push_message(self, message):
54 self._push_message(message, ErrorMessage.LEVEL_INFO)
56 def push_error(self, message):
57 self._push_message(message, ErrorMessage.LEVEL_ERROR)
59 def push_exception(self):
60 userMessage = str(sys.exc_info()[1])
61 _moduleLogger.exception(userMessage)
62 self.push_error(userMessage)
64 def pop(self, message = None):
70 for (i, error) in enumerate(self._messages)
71 if error.message == message
73 # Might be removed out of order
75 del self._messages[messageIndex[0]]
76 self.messagePopped.emit()
78 def peek_message(self):
79 return self._messages[0]
81 def _push_message(self, message, level):
82 self._messages.append(ErrorMessage(message, level))
83 self.messagePushed.emit()
86 return len(self._messages)
89 class ErrorDisplay(object):
91 _SENTINEL_ICON = QtGui.QIcon()
93 def __init__(self, errorLog):
94 self._errorLog = errorLog
95 self._errorLog.messagePushed.connect(self._on_message_pushed)
96 self._errorLog.messagePopped.connect(self._on_message_popped)
99 ErrorMessage.LEVEL_BUSY:
101 #("process-working", "gtk-refresh")
104 ErrorMessage.LEVEL_INFO:
106 ("dialog-information", "general_notes", "gtk-info")
108 ErrorMessage.LEVEL_ERROR:
110 ("dialog-error", "app_install_error", "gtk-dialog-error")
113 self._severityLabel = QtGui.QLabel()
114 self._severityLabel.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
116 self._message = QtGui.QLabel()
117 self._message.setText("Boo")
118 self._message.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
119 self._message.setWordWrap(True)
121 closeIcon = get_theme_icon(("window-close", "general_close", "gtk-close"), self._SENTINEL_ICON)
122 if closeIcon is not self._SENTINEL_ICON:
123 self._closeLabel = QtGui.QPushButton(closeIcon, "")
125 self._closeLabel = QtGui.QPushButton("X")
126 self._closeLabel.clicked.connect(self._on_close)
128 self._controlLayout = QtGui.QHBoxLayout()
129 self._controlLayout.addWidget(self._severityLabel, 1, QtCore.Qt.AlignCenter)
130 self._controlLayout.addWidget(self._message, 1000)
131 self._controlLayout.addWidget(self._closeLabel, 1, QtCore.Qt.AlignCenter)
133 self._topLevelLayout = QtGui.QHBoxLayout()
134 self._topLevelLayout.addLayout(self._controlLayout)
135 self._widget = QtGui.QWidget()
136 self._widget.setLayout(self._topLevelLayout)
144 @QtCore.pyqtSlot(bool)
145 @misc.log_exception(_moduleLogger)
146 def _on_close(self, checked = False):
150 @misc.log_exception(_moduleLogger)
151 def _on_message_pushed(self):
152 if 1 <= len(self._errorLog) and self._widget.isHidden():
153 error = self._errorLog.peek_message()
154 self._message.setText(error.message)
155 self._severityLabel.setPixmap(self._icons[error.level])
159 @misc.log_exception(_moduleLogger)
160 def _on_message_popped(self):
161 if len(self._errorLog) == 0:
162 self._message.setText("")
165 error = self._errorLog.peek_message()
166 self._message.setText(error.message)
167 self._severityLabel.setPixmap(self._icons[error.level])
170 class QHtmlDelegate(QtGui.QStyledItemDelegate):
172 # @bug Not showing all of a message
174 def paint(self, painter, option, index):
175 newOption = QtGui.QStyleOptionViewItemV4(option)
176 self.initStyleOption(newOption, index)
177 if newOption.widget is not None:
178 style = newOption.widget.style()
180 style = QtGui.QApplication.style()
182 doc = QtGui.QTextDocument()
183 doc.setHtml(newOption.text)
184 doc.setTextWidth(newOption.rect.width())
187 style.drawControl(QtGui.QStyle.CE_ItemViewItem, newOption, painter)
189 ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
190 if newOption.state & QtGui.QStyle.State_Selected:
191 ctx.palette.setColor(
193 newOption.palette.color(
194 QtGui.QPalette.Active,
195 QtGui.QPalette.HighlightedText
199 ctx.palette.setColor(
201 newOption.palette.color(
202 QtGui.QPalette.Active,
207 textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, newOption)
209 painter.translate(textRect.topLeft())
210 painter.setClipRect(textRect.translated(-textRect.topLeft()))
211 doc.documentLayout().draw(painter, ctx)
214 def sizeHint(self, option, index):
215 newOption = QtGui.QStyleOptionViewItemV4(option)
216 self.initStyleOption(newOption, index)
218 doc = QtGui.QTextDocument()
219 doc.setHtml(newOption.text)
220 doc.setTextWidth(newOption.rect.width())
221 size = QtCore.QSize(doc.idealWidth(), doc.size().height())
225 def _null_set_stackable(window, isStackable):
229 def _maemo_set_stackable(window, isStackable):
230 window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
234 QtCore.Qt.WA_Maemo5StackedWindow
235 set_stackable = _maemo_set_stackable
236 except AttributeError:
237 set_stackable = _null_set_stackable
240 def _null_set_autorient(window, isStackable):
244 def _maemo_set_autorient(window, isStackable):
245 window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
249 QtCore.Qt.WA_Maemo5AutoOrientation
250 set_autorient = _maemo_set_autorient
251 except AttributeError:
252 set_autorient = _null_set_autorient
255 def _null_set_landscape(window, isStackable):
259 def _maemo_set_landscape(window, isStackable):
260 window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
264 QtCore.Qt.WA_Maemo5LandscapeOrientation
265 set_landscape = _maemo_set_landscape
266 except AttributeError:
267 set_landscape = _null_set_landscape
270 def _null_set_portrait(window, isStackable):
274 def _maemo_set_portrait(window, isStackable):
275 window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
279 QtCore.Qt.WA_Maemo5PortraitOrientation
280 set_portrait = _maemo_set_portrait
281 except AttributeError:
282 set_portrait = _null_set_portrait
285 def _null_show_progress_indicator(window, isStackable):
289 def _maemo_show_progress_indicator(window, isStackable):
290 window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
294 QtCore.Qt.WA_Maemo5ShowProgressIndicator
295 show_progress_indicator = _maemo_show_progress_indicator
296 except AttributeError:
297 show_progress_indicator = _null_show_progress_indicator
300 def _null_mark_numbers_preferred(widget):
304 def _newqt_mark_numbers_preferred(widget):
305 widget.setInputMethodHints(QtCore.Qt.ImhPreferNumbers)
309 QtCore.Qt.ImhPreferNumbers
310 mark_numbers_preferred = _newqt_mark_numbers_preferred
311 except AttributeError:
312 mark_numbers_preferred = _null_mark_numbers_preferred
315 def screen_orientation():
316 geom = QtGui.QApplication.desktop().screenGeometry()
317 if geom.width() <= geom.height():
318 return QtCore.Qt.Vertical
320 return QtCore.Qt.Horizontal
323 def _null_get_theme_icon(iconNames, fallback = None):
324 icon = fallback if fallback is not None else QtGui.QIcon()
328 def _newqt_get_theme_icon(iconNames, fallback = None):
329 for iconName in iconNames:
330 if QtGui.QIcon.hasThemeIcon(iconName):
331 icon = QtGui.QIcon.fromTheme(iconName)
334 icon = fallback if fallback is not None else QtGui.QIcon()
339 QtGui.QIcon.fromTheme
340 get_theme_icon = _newqt_get_theme_icon
341 except AttributeError:
342 get_theme_icon = _null_get_theme_icon