1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """a view display messages containing warnings, errors and information."""
23
24 import gettext
25 import os
26 import time
27
28 import pango
29 import gtk
30
31 from flumotion.common import log
32 from flumotion.common.documentation import getMessageWebLink
33 from flumotion.common.i18n import Translator
34 from flumotion.common.messages import ERROR, WARNING, INFO
35 from flumotion.configure import configure
36
37 _ = gettext.gettext
38 __version__ = "$Rev: 7973 $"
39 _stock_icons = {
40 ERROR: gtk.STOCK_DIALOG_ERROR,
41 WARNING: gtk.STOCK_DIALOG_WARNING,
42 INFO: gtk.STOCK_DIALOG_INFO,
43 }
44 _headings = {
45 ERROR: _('Error'),
46 WARNING: _('Warning'),
47 INFO: _('Note'),
48 }
49
50
72
73
74
75
76
78 """
79 I am a widget that can show messages.
80 """
81
82
83
84
98
100 h1 = gtk.HBox()
101 self.pack_start(h1, False, False, 0)
102 self.label = gtk.Label()
103 self.label.show()
104 h1.pack_start(self.label, False, False, 6)
105
106
107 h2 = gtk.HBox()
108 h1.pack_end(h2, False, False, 0)
109 self.buttonbox = h2
110
111 s = gtk.HSeparator()
112 self.pack_start(s, False, False, 6)
113 sw = gtk.ScrolledWindow()
114 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
115 sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
116 self.pack_start(sw, True, True, 0)
117
118
119
120 tv = gtk.TextView()
121 tv.set_wrap_mode(gtk.WRAP_WORD)
122 tv.set_left_margin(6)
123 tv.set_right_margin(6)
124 tv.set_accepts_tab(False)
125 tv.set_cursor_visible(False)
126 tv.set_editable(False)
127
128
129 tv.connect('event-after', self._after_textview__event)
130 tv.connect('motion-notify-event',
131 self._on_textview___motion_notify_event)
132 sw.add(tv)
133 self.textview = tv
134
135 self.show_all()
136
144
146 """
147 Add a message to me.
148 @type m: L{flumotion.common.messages.Message}
149 """
150
151
152
153 self.clearMessage(m.id)
154
155
156 b = MessageButton(m)
157 b.sigid = b.connect('toggled', self._on_message_button__toggled, m)
158 b.show()
159 self.buttonbox.pack_start(b, False, False, 0)
160
161 firstButton = self._sortMessages()
162
163 if not self.active_button:
164 b.set_active(True)
165 elif b == firstButton:
166 b.set_active(True)
167 self.show()
168
170 """
171 Clear all messages with the given id.
172 Will bring the remaining most important message to the front,
173 or hide the view completely if no messages are left.
174 """
175 for button in self.buttonbox.get_children():
176 if button.message.id != id:
177 continue
178
179 self.buttonbox.remove(button)
180 button.disconnect(button.sigid)
181 button.sigid = 0
182 if not self.buttonbox.get_children():
183 self.active_button = None
184 self.hide()
185 elif self.active_button == button:
186 self.active_button = self.buttonbox.get_children()[0]
187 self.active_button.set_active(True)
188 break
189
191 """Disable timestamps for this MessageView,
192 it will make it easier to understand the error messages and
193 make it suitable for end users.
194 """
195 self._disableTimestamps = True
196
197
198
200
201
202 text = self._translator.translate(message)
203
204 textbuffer = gtk.TextBuffer()
205 textbuffer.set_text(text)
206 self.textview.set_buffer(textbuffer)
207 self.label.set_markup('<b>%s</b>' %
208 _headings.get(message.level, _('Message')))
209
210
211 description = message.getDescription()
212 if description:
213 textbuffer.insert(textbuffer.get_end_iter(), ' ')
214 titer = textbuffer.get_end_iter()
215
216 translated = self._translator.translateTranslatable(description)
217 tag = textbuffer.create_tag(translated)
218 tag.set_property('underline', pango.UNDERLINE_SINGLE)
219 tag.set_property('foreground', 'blue')
220 tag.set_data('link', getMessageWebLink(message))
221 textbuffer.insert_with_tags_by_name(titer, translated,
222 tag.get_property('name'))
223
224 timestamp = message.getTimeStamp()
225 if timestamp and not self._disableTimestamps:
226 text = _("\nPosted on %s.\n") % time.strftime(
227 "%c", time.localtime(timestamp))
228 textbuffer.insert(textbuffer.get_end_iter(), text)
229
230 if message.debug:
231 text = "\n\n" + _("Debug information:\n") + message.debug + '\n'
232 textbuffer.insert(textbuffer.get_end_iter(), text)
233
235
236 children = [(-w.message.level, w.message.priority, w)
237 for w in self.buttonbox.get_children()]
238 children.sort()
239 children.reverse()
240 children = [(i, children[i][2]) for i in range(len(children))]
241 for child in children:
242 self.buttonbox.reorder_child(child[1], child[0])
243
244
245 return children[0][1]
246
247
248
261
262
263
265 x, y = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
266 int(event.x), int(event.y))
267 tags = textview.get_iter_at_location(x, y).get_tags()
268
269
270 textview.window.get_pointer()
271
272
273 cursor = None
274 for tag in tags:
275 if tag.get_data('link'):
276 cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
277 break
278 textview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(cursor)
279 return False
280
281 - def _after_textview__event(self, textview, event):
282 if event.type != gtk.gdk.BUTTON_RELEASE:
283 return False
284 if event.button != 1:
285 return False
286
287 textbuffer = textview.get_buffer()
288
289 bounds = textbuffer.get_selection_bounds()
290 if bounds:
291 [start, end] = bounds
292 if start.get_offset() != end.get_offset():
293 return False
294
295 x, y = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
296 int(event.x), int(event.y))
297 iter = textview.get_iter_at_location(x, y)
298
299 for tag in iter.get_tags():
300 link = tag.get_data('link')
301 if link:
302 import webbrowser
303 log.debug('messageview', 'opening %s' % link)
304 webbrowser.open(link)
305 break
306
307 return False
308