Adding an About dialog for copyright reasons, fixing quit issues with dialogs
[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 Not showing all of a message
102
103         def paint(self, painter, option, index):
104                 newOption = QtGui.QStyleOptionViewItemV4(option)
105                 self.initStyleOption(newOption, index)
106                 if newOption.widget is not None:
107                         style = newOption.widget.style()
108                 else:
109                         style = QtGui.QApplication.style()
110
111                 doc = QtGui.QTextDocument()
112                 doc.setHtml(newOption.text)
113                 doc.setTextWidth(newOption.rect.width())
114
115                 newOption.text = ""
116                 style.drawControl(QtGui.QStyle.CE_ItemViewItem, newOption, painter)
117
118                 ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
119                 if newOption.state & QtGui.QStyle.State_Selected:
120                         ctx.palette.setColor(
121                                 QtGui.QPalette.Text,
122                                 newOption.palette.color(
123                                         QtGui.QPalette.Active,
124                                         QtGui.QPalette.HighlightedText
125                                 )
126                         )
127                 else:
128                         ctx.palette.setColor(
129                                 QtGui.QPalette.Text,
130                                 newOption.palette.color(
131                                         QtGui.QPalette.Active,
132                                         QtGui.QPalette.Text
133                                 )
134                         )
135
136                 textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, newOption)
137                 painter.save()
138                 painter.translate(textRect.topLeft())
139                 painter.setClipRect(textRect.translated(-textRect.topLeft()))
140                 doc.documentLayout().draw(painter, ctx)
141                 painter.restore()
142
143         def sizeHint(self, option, index):
144                 newOption = QtGui.QStyleOptionViewItemV4(option)
145                 self.initStyleOption(newOption, index)
146
147                 doc = QtGui.QTextDocument()
148                 doc.setHtml(newOption.text)
149                 doc.setTextWidth(newOption.rect.width())
150                 size = QtCore.QSize(doc.idealWidth(), doc.size().height())
151                 return size
152
153
154 def _null_set_stackable(window, isStackable):
155         pass
156
157
158 def _maemo_set_stackable(window, isStackable):
159         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
160
161
162 try:
163         QtCore.Qt.WA_Maemo5StackedWindow
164         set_stackable = _maemo_set_stackable
165 except AttributeError:
166         set_stackable = _null_set_stackable
167
168
169 def _null_set_autorient(window, isStackable):
170         pass
171
172
173 def _maemo_set_autorient(window, isStackable):
174         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
175
176
177 try:
178         QtCore.Qt.WA_Maemo5AutoOrientation
179         set_autorient = _maemo_set_autorient
180 except AttributeError:
181         set_autorient = _null_set_autorient
182
183
184 def _null_set_landscape(window, isStackable):
185         pass
186
187
188 def _maemo_set_landscape(window, isStackable):
189         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
190
191
192 try:
193         QtCore.Qt.WA_Maemo5LandscapeOrientation
194         set_landscape = _maemo_set_landscape
195 except AttributeError:
196         set_landscape = _null_set_landscape
197
198
199 def _null_set_portrait(window, isStackable):
200         pass
201
202
203 def _maemo_set_portrait(window, isStackable):
204         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
205
206
207 try:
208         QtCore.Qt.WA_Maemo5PortraitOrientation
209         set_portrait = _maemo_set_portrait
210 except AttributeError:
211         set_portrait = _null_set_portrait
212
213
214 def _null_show_progress_indicator(window, isStackable):
215         pass
216
217
218 def _maemo_show_progress_indicator(window, isStackable):
219         window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
220
221
222 try:
223         QtCore.Qt.WA_Maemo5ShowProgressIndicator
224         show_progress_indicator = _maemo_show_progress_indicator
225 except AttributeError:
226         show_progress_indicator = _null_show_progress_indicator
227
228
229 def _null_mark_numbers_preferred(widget):
230         pass
231
232
233 def _newqt_mark_numbers_preferred(widget):
234         widget.setInputMethodHints(QtCore.Qt.ImhPreferNumbers)
235
236
237 try:
238         QtCore.Qt.ImhPreferNumbers
239         mark_numbers_preferred = _newqt_mark_numbers_preferred
240 except AttributeError:
241         mark_numbers_preferred = _null_mark_numbers_preferred
242
243
244 def screen_orientation():
245         geom = QtGui.QApplication.desktop().screenGeometry()
246         if geom.width() <= geom.height():
247                 return QtCore.Qt.Vertical
248         else:
249                 return QtCore.Qt.Horizontal
250
251
252 def _null_get_theme_icon(iconNames, fallback = None):
253         icon = fallback if fallback is not None else QtGui.QIcon()
254         return icon
255
256
257 def _newqt_get_theme_icon(iconNames, fallback = None):
258         for iconName in iconNames:
259                 if QtGui.QIcon.hasThemeIcon(iconName):
260                         icon = QtGui.QIcon.fromTheme(iconName)
261                         break
262         else:
263                 icon = fallback if fallback is not None else QtGui.QIcon()
264         return icon
265
266
267 try:
268         QtGui.QIcon.fromTheme
269         get_theme_icon = _newqt_get_theme_icon
270 except AttributeError:
271         get_theme_icon = _null_get_theme_icon
272