| Trees | Indices | Help |
|---|
|
|
1 # -*- Mode: Python -*-
2 # vi:si:et:sw=4:sts=4:ts=4
3 #
4 # Flumotion - a streaming media server
5 # Copyright (C) 2004,2005,2006,2007,2008 Fluendo, S.L. (www.fluendo.com).
6 # All rights reserved.
7
8 # This file may be distributed and/or modified under the terms of
9 # the GNU General Public License version 2 as published by
10 # the Free Software Foundation.
11 # This file is distributed without any warranty; without even the implied
12 # warranty of merchantability or fitness for a particular purpose.
13 # See "LICENSE.GPL" in the source distribution for more information.
14
15 # Licensees having purchased or holding a valid Flumotion Advanced
16 # Streaming Server license may use this file in accordance with the
17 # Flumotion Advanced Streaming Server Commercial License Agreement.
18 # See "LICENSE.Flumotion" in the source distribution for more information.
19
20 # Headers in this file shall remain intact.
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 from flumotion.common.pygobject import gsignal
37
38 _ = gettext.gettext
39 __version__ = "$Rev: 8476 $"
40 _stock_icons = {
41 ERROR: gtk.STOCK_DIALOG_ERROR,
42 WARNING: gtk.STOCK_DIALOG_WARNING,
43 INFO: gtk.STOCK_DIALOG_INFO,
44 }
45 _headings = {
46 ERROR: _('Error'),
47 WARNING: _('Warning'),
48 INFO: _('Note'),
49 }
50
51
53 """
54 I am a button at the top right of the message view, representing a message.
55 """
56
58 gtk.ToggleButton.__init__(self)
59
60 self.message = message
61
62 i = gtk.Image()
63 i.set_from_stock(_stock_icons.get(message.level,
64 gtk.STOCK_MISSING_IMAGE),
65 gtk.ICON_SIZE_MENU)
66 i.show()
67 self.add(i)
68 self.set_focus_on_click(False)
69 self.set_relief(gtk.RELIEF_NONE)
70
72 return '<MessageButton for %s at %d>' % (self.message, id(self))
73
74
75 # instantiated through create_function in glade files
76
77
79 """
80 I am a widget that can show messages.
81 """
82 # I am a vbox with first row the label and icons,
83 # second row a separator
84 # and third row a text view
85 gsignal('resize-event', bool)
86
88 gtk.VBox.__init__(self)
89
90 self._disableTimestamps = False
91 self.active_button = None
92
93 self._createUI()
94 self.clear()
95
96 self._translator = Translator()
97 localedir = os.path.join(configure.localedatadir, 'locale')
98 # FIXME: add locales as messages from domains come in
99 self._translator.addLocaleDir(configure.PACKAGE, localedir)
100
102 h1 = gtk.HBox()
103 self.pack_start(h1, False, False, 0)
104
105 self.hline = gtk.HSeparator()
106 h1.pack_start(self.hline, True, True, 3)
107 # button box holding the message icons at the top right
108 h2 = gtk.HBox()
109 h1.pack_end(h2, False, False, 0)
110 self.buttonbox = h2
111
112 sw = gtk.ScrolledWindow()
113 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
114 sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
115 self.pack_start(sw, True, True, 0)
116 self.sw = sw
117
118 # text view shows the messages, plus debug information
119 # FIXME: needs to be hyperlinkable in the future
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 #tv.set_sensitive(False)
128 # connect signals to act on the hyperlink
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
138 """
139 Remove all messages and hide myself.
140 """
141 for child in self.buttonbox.get_children():
142 self.clearMessage(child.message.id)
143 self.hide()
144
146 """
147 Add a message to me.
148 @type m: L{flumotion.common.messages.Message}
149 """
150 # clear all previously added messages with the same id. This allows
151 # us to replace for example a "probing" message with the
152 # result message
153 self.clearMessage(m.id)
154
155 # add a message button to show this message
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 self.show()
164 if not self.active_button:
165 b.set_active(True)
166 elif b == firstButton:
167 b.set_active(True)
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 # Private
198
200 # FIXME: it would be good to have a "Debug" button when
201 # applicable, instead of always showing the text
202 text = self._translator.translate(message)
203
204 textbuffer = gtk.TextBuffer()
205 textbuffer.set_text(text)
206 self.textview.set_buffer(textbuffer)
207
208 # if we have help information, add it to the end of the text view
209 description = message.getDescription()
210 if description:
211 textbuffer.insert(textbuffer.get_end_iter(), ' ')
212 titer = textbuffer.get_end_iter()
213 # we set the 'link' data field on tags to identify them
214 translated = self._translator.translateTranslatable(description)
215 tag = textbuffer.create_tag(translated)
216 tag.set_property('underline', pango.UNDERLINE_SINGLE)
217 tag.set_property('foreground', 'blue')
218 tag.set_data('link', getMessageWebLink(message))
219 textbuffer.insert_with_tags_by_name(titer, translated,
220 tag.get_property('name'))
221
222 timestamp = message.getTimeStamp()
223 if timestamp and not self._disableTimestamps:
224 text = _("\nPosted on %s.\n") % time.strftime(
225 "%c", time.localtime(timestamp))
226 textbuffer.insert(textbuffer.get_end_iter(), text)
227
228 if message.debug:
229 text = "\n\n" + _("Debug information:\n") + message.debug + '\n'
230 textbuffer.insert(textbuffer.get_end_iter(), text)
231
233 # Sort all messages first by (reverse of) level, then priority
234 children = [(-w.message.level, w.message.priority, w)
235 for w in self.buttonbox.get_children()]
236 children.sort()
237 children.reverse()
238 children = [(i, children[i][2]) for i in range(len(children))]
239 for child in children:
240 self.buttonbox.reorder_child(child[1], child[0])
241
242 # the first button, e.g. highest priority
243 return children[0][1]
244
245 # Callbacks
246
265
266 # when the mouse cursor moves, set the cursor image accordingly
267
269 x, y = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
270 int(event.x), int(event.y))
271 tags = textview.get_iter_at_location(x, y).get_tags()
272 # without this call, further motion notify events don't get
273 # triggered
274 textview.window.get_pointer()
275
276 # if any of the tags is a link, show a hand
277 cursor = None
278 for tag in tags:
279 if tag.get_data('link'):
280 cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
281 break
282 textview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(cursor)
283 return False
284
286 if event.type != gtk.gdk.BUTTON_RELEASE:
287 return False
288 if event.button != 1:
289 return False
290
291 textbuffer = textview.get_buffer()
292 # we shouldn't follow a link if the user has selected something
293 bounds = textbuffer.get_selection_bounds()
294 if bounds:
295 [start, end] = bounds
296 if start.get_offset() != end.get_offset():
297 return False
298
299 x, y = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
300 int(event.x), int(event.y))
301 iter = textview.get_iter_at_location(x, y)
302
303 for tag in iter.get_tags():
304 link = tag.get_data('link')
305 if link:
306 import webbrowser
307 log.debug('messageview', 'opening %s' % link)
308 webbrowser.open(link)
309 break
310
311 return False
312
| Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Fri Sep 24 12:50:37 2010 | http://epydoc.sourceforge.net |