Results of testing on Maemo 5
[gc-dialer] / src / util / qui_utils.py
1 import sys
2 import logging
3
4 from PyQt4 import QtCore
5 from PyQt4 import QtGui
6
7 import misc
8
9
10 _moduleLogger = logging.getLogger(__name__)
11
12
13 class QErrorLog(QtCore.QObject):
14
15         messagePushed = QtCore.pyqtSignal()
16         messagePopped = QtCore.pyqtSignal()
17
18         def __init__(self):
19                 QtCore.QObject.__init__(self)
20                 self._messages = []
21
22         def push_message(self, message):
23                 self._messages.append(message)
24                 self.messagePushed.emit()
25
26         def push_exception(self):
27                 userMessage = str(sys.exc_info()[1])
28                 _moduleLogger.exception(userMessage)
29                 self.push_message(userMessage)
30
31         def pop_message(self):
32                 del self._messages[0]
33                 self.messagePopped.emit()
34
35         def peek_message(self):
36                 return self._messages[0]
37
38         def __len__(self):
39                 return len(self._messages)
40
41
42 class ErrorDisplay(object):
43
44         def __init__(self, errorLog):
45                 self._errorLog = errorLog
46                 self._errorLog.messagePushed.connect(self._on_message_pushed)
47                 self._errorLog.messagePopped.connect(self._on_message_popped)
48
49                 errorIcon = get_theme_icon(("dialog-error", "app_install_error", "gtk-dialog-error"))
50                 self._severityIcon = errorIcon.pixmap(32, 32)
51                 self._severityLabel = QtGui.QLabel()
52                 self._severityLabel.setPixmap(self._severityIcon)
53
54                 self._message = QtGui.QLabel()
55                 self._message.setText("Boo")
56
57                 closeIcon = get_theme_icon(("window-close", "general_close", "gtk-close"))
58                 self._closeLabel = QtGui.QPushButton(closeIcon, "")
59                 self._closeLabel.clicked.connect(self._on_close)
60
61                 self._controlLayout = QtGui.QHBoxLayout()
62                 self._controlLayout.addWidget(self._severityLabel)
63                 self._controlLayout.addWidget(self._message)
64                 self._controlLayout.addWidget(self._closeLabel)
65
66                 self._topLevelLayout = QtGui.QHBoxLayout()
67                 self._topLevelLayout.addLayout(self._controlLayout)
68                 self._widget = QtGui.QWidget()
69                 self._widget.setLayout(self._topLevelLayout)
70                 self._widget.hide()
71
72         @property
73         def toplevel(self):
74                 return self._widget
75
76         @QtCore.pyqtSlot()
77         @QtCore.pyqtSlot(bool)
78         @misc.log_exception(_moduleLogger)
79         def _on_close(self, checked = False):
80                 self._errorLog.pop_message()
81
82         @QtCore.pyqtSlot()
83         @misc.log_exception(_moduleLogger)
84         def _on_message_pushed(self):
85                 if 1 <= len(self._errorLog) and self._widget.isHidden():
86                         self._message.setText(self._errorLog.peek_message())
87                         self._widget.show()
88
89         @QtCore.pyqtSlot()
90         @misc.log_exception(_moduleLogger)
91         def _on_message_popped(self):
92                 if len(self._errorLog) == 0:
93                         self._message.setText("")
94                         self._widget.hide()
95                 else:
96                         self._message.setText(self._errorLog.peek_message())
97
98
99 class QHtmlDelegate(QtGui.QStyledItemDelegate):
100
101         # @bug Doesn't show properly with dark themes (Maemo)
102
103         def paint(self, painter, option, index):
104                 newOption = QtGui.QStyleOptionViewItemV4(option)
105                 self.initStyleOption(newOption, index)
106
107                 doc = QtGui.QTextDocument()
108                 doc.setHtml(newOption.text)
109                 doc.setTextWidth(newOption.rect.width())
110
111                 if newOption.widget is not None:
112                         style = newOption.widget.style()
113                 else:
114                         style = QtGui.QApplication.style()
115
116                 newOption.text = ""
117                 style.drawControl(QtGui.QStyle.CE_ItemViewItem, newOption, painter)
118
119                 ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
120                 if newOption.state & QtGui.QStyle.State_Selected:
121                         ctx.palette.setColor(
122                                 QtGui.QPalette.Text,
123                                 newOption.palette.color(
124                                         QtGui.QPalette.Active,
125                                         QtGui.QPalette.HighlightedText
126                                 )
127                         )
128
129                 textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, newOption)
130                 painter.save()
131                 painter.translate(textRect.topLeft())
132                 painter.setClipRect(textRect.translated(-textRect.topLeft()))
133                 doc.documentLayout().draw(painter, ctx)
134                 painter.restore()
135
136         def sizeHint(self, option, index):
137                 newOption = QtGui.QStyleOptionViewItemV4(option)
138                 self.initStyleOption(newOption, index)
139
140                 doc = QtGui.QTextDocument()
141                 doc.setHtml(newOption.text)
142                 doc.setTextWidth(newOption.rect.width())
143                 size = QtCore.QSize(doc.idealWidth(), doc.size().height())
144                 return size
145
146
147 def _null_set_stackable(window, isStackable):
148         pass
149
150
151 def _maemo_set_stackable(window, isStackable):
152         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
153
154
155 try:
156         QtCore.Qt.WA_Maemo5StackedWindow
157         set_stackable = _maemo_set_stackable
158 except AttributeError:
159         set_stackable = _null_set_stackable
160
161
162 def _null_set_autorient(window, isStackable):
163         pass
164
165
166 def _maemo_set_autorient(window, isStackable):
167         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
168
169
170 try:
171         QtCore.Qt.WA_Maemo5AutoOrientation
172         set_autorient = _maemo_set_autorient
173 except AttributeError:
174         set_autorient = _null_set_autorient
175
176
177 def _null_set_landscape(window, isStackable):
178         pass
179
180
181 def _maemo_set_landscape(window, isStackable):
182         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
183
184
185 try:
186         QtCore.Qt.WA_Maemo5LandscapeOrientation
187         set_landscape = _maemo_set_landscape
188 except AttributeError:
189         set_landscape = _null_set_landscape
190
191
192 def _null_set_portrait(window, isStackable):
193         pass
194
195
196 def _maemo_set_portrait(window, isStackable):
197         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
198
199
200 try:
201         QtCore.Qt.WA_Maemo5PortraitOrientation
202         set_portrait = _maemo_set_portrait
203 except AttributeError:
204         set_portrait = _null_set_portrait
205
206
207 def _null_show_progress_indicator(window, isStackable):
208         pass
209
210
211 def _maemo_show_progress_indicator(window, isStackable):
212         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
213
214
215 try:
216         QtCore.Qt.WA_Maemo5ShowProgressIndicator
217         show_progress_indicator = _maemo_show_progress_indicator
218 except AttributeError:
219         show_progress_indicator = _null_show_progress_indicator
220
221
222 def _null_mark_numbers_preferred(widget):
223         pass
224
225
226 def _newqt_mark_numbers_preferred(widget):
227         widget.setInputMethodHints(QtCore.Qt.ImhPreferNumbers)
228
229
230 try:
231         QtCore.Qt.ImhPreferNumbers
232         mark_numbers_preferred = _newqt_mark_numbers_preferred
233 except AttributeError:
234         mark_numbers_preferred = _null_mark_numbers_preferred
235
236
237 def screen_orientation():
238         geom = QtGui.QApplication.desktop().screenGeometry()
239         if geom.width() <= geom.height():
240                 return QtCore.Qt.Vertical
241         else:
242                 return QtCore.Qt.Horizontal
243
244
245 def _null_get_theme_icon(iconNames, fallback = None):
246         icon = fallback if fallback is not None else QtGui.QIcon()
247         return icon
248
249
250 def _newqt_get_theme_icon(iconNames, fallback = None):
251         for iconName in iconNames:
252                 if QtGui.QIcon.hasThemeIcon(iconName):
253                         icon = QtGui.QIcon.fromTheme(iconName)
254                         break
255         else:
256                 icon = fallback if fallback is not None else QtGui.QIcon()
257         return icon
258
259
260 try:
261         QtGui.QIcon.fromTheme
262         get_theme_icon = _newqt_get_theme_icon
263 except AttributeError:
264         get_theme_icon = _null_get_theme_icon
265