| 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,2009 Fluendo, S.L.
6 # Copyright (C) 2010,2011 Flumotion Services, S.A.
7 # All rights reserved.
8 #
9 # This file may be distributed and/or modified under the terms of
10 # the GNU Lesser General Public License version 2.1 as published by
11 # the Free Software Foundation.
12 # This file is distributed without any warranty; without even the implied
13 # warranty of merchantability or fitness for a particular purpose.
14 # See "LICENSE.LGPL" in the source distribution for more information.
15 #
16 # Headers in this file shall remain intact.
17
18 """a view display messages containing warnings, errors and information."""
19
20 import gettext
21 import os
22 import time
23
24 import pango
25 import gtk
26
27 from flumotion.common import log
28 from flumotion.common.documentation import getMessageWebLink
29 from flumotion.common.i18n import Translator
30 from flumotion.common.messages import ERROR, WARNING, INFO
31 from flumotion.configure import configure
32 from flumotion.common.pygobject import gsignal
33
34 _ = gettext.gettext
35 __version__ = "$Rev$"
36 _stock_icons = {
37 ERROR: gtk.STOCK_DIALOG_ERROR,
38 WARNING: gtk.STOCK_DIALOG_WARNING,
39 INFO: gtk.STOCK_DIALOG_INFO,
40 }
41 _headings = {
42 ERROR: _('Error'),
43 WARNING: _('Warning'),
44 INFO: _('Note'),
45 }
46
47
49 """
50 I am a button at the top right of the message view, representing a message.
51 """
52
54 gtk.ToggleButton.__init__(self)
55
56 self.message = message
57
58 i = gtk.Image()
59 i.set_from_stock(_stock_icons.get(message.level,
60 gtk.STOCK_MISSING_IMAGE),
61 gtk.ICON_SIZE_MENU)
62 i.show()
63 self.add(i)
64 self.set_focus_on_click(False)
65 self.set_relief(gtk.RELIEF_NONE)
66
68 return '<MessageButton for %s at %d>' % (self.message, id(self))
69
70
71 # instantiated through create_function in glade files
72
73
75 """
76 I am a widget that can show messages.
77 """
78 # I am a vbox with first row the label and icons,
79 # second row a separator
80 # and third row a text view
81 gsignal('resize-event', bool)
82
84 gtk.VBox.__init__(self)
85
86 self._disableTimestamps = False
87 self.active_button = None
88
89 self._createUI()
90 self.clear()
91
92 self._translator = Translator()
93 localedir = os.path.join(configure.localedatadir, 'locale')
94 # FIXME: add locales as messages from domains come in
95 self._translator.addLocaleDir(configure.PACKAGE, localedir)
96
98 h1 = gtk.HBox()
99 self.pack_start(h1, False, False, 0)
100
101 self.hline = gtk.HSeparator()
102 h1.pack_start(self.hline, True, True, 3)
103 # button box holding the message icons at the top right
104 h2 = gtk.HBox()
105 h1.pack_end(h2, False, False, 0)
106 self.buttonbox = h2
107
108 sw = gtk.ScrolledWindow()
109 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
110 sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
111 self.pack_start(sw, True, True, 0)
112 self.sw = sw
113
114 # text view shows the messages, plus debug information
115 # FIXME: needs to be hyperlinkable in the future
116 tv = gtk.TextView()
117 tv.set_wrap_mode(gtk.WRAP_WORD)
118 tv.set_left_margin(6)
119 tv.set_right_margin(6)
120 tv.set_accepts_tab(False)
121 tv.set_cursor_visible(False)
122 tv.set_editable(False)
123 #tv.set_sensitive(False)
124 # connect signals to act on the hyperlink
125 tv.connect('event-after', self._after_textview__event)
126 tv.connect('motion-notify-event',
127 self._on_textview___motion_notify_event)
128 sw.add(tv)
129 self.textview = tv
130
131 self.show_all()
132
134 """
135 Remove all messages and hide myself.
136 """
137 for child in self.buttonbox.get_children():
138 self.clearMessage(child.message.id)
139 self.hide()
140
142 """
143 Add a message to me.
144 @type m: L{flumotion.common.messages.Message}
145 """
146 # clear all previously added messages with the same id. This allows
147 # us to replace for example a "probing" message with the
148 # result message
149 self.clearMessage(m.id)
150
151 # add a message button to show this message
152 b = MessageButton(m)
153 b.sigid = b.connect('toggled', self._on_message_button__toggled, m)
154 b.show()
155 self.buttonbox.pack_start(b, False, False, 0)
156
157 firstButton = self._sortMessages()
158
159 self.show()
160 if not self.active_button:
161 b.set_active(True)
162 elif b == firstButton:
163 b.set_active(True)
164
166 """
167 Clear all messages with the given id.
168 Will bring the remaining most important message to the front,
169 or hide the view completely if no messages are left.
170 """
171 for button in self.buttonbox.get_children():
172 if button.message.id != id:
173 continue
174
175 self.buttonbox.remove(button)
176 button.disconnect(button.sigid)
177 button.sigid = 0
178 if not self.buttonbox.get_children():
179 self.active_button = None
180 self.hide()
181 elif self.active_button == button:
182 self.active_button = self.buttonbox.get_children()[0]
183 self.active_button.set_active(True)
184 break
185
187 """Disable timestamps for this MessageView,
188 it will make it easier to understand the error messages and
189 make it suitable for end users.
190 """
191 self._disableTimestamps = True
192
193 # Private
194
196 # FIXME: it would be good to have a "Debug" button when
197 # applicable, instead of always showing the text
198 text = self._translator.translate(message)
199
200 textbuffer = gtk.TextBuffer()
201 textbuffer.set_text(text)
202 self.textview.set_buffer(textbuffer)
203
204 # if we have help information, add it to the end of the text view
205 description = message.getDescription()
206 if description:
207 textbuffer.insert(textbuffer.get_end_iter(), ' ')
208 titer = textbuffer.get_end_iter()
209 # we set the 'link' data field on tags to identify them
210 translated = self._translator.translateTranslatable(description)
211 tag = textbuffer.create_tag(translated)
212 tag.set_property('underline', pango.UNDERLINE_SINGLE)
213 tag.set_property('foreground', 'blue')
214 tag.set_data('link', getMessageWebLink(message))
215 textbuffer.insert_with_tags_by_name(titer, translated,
216 tag.get_property('name'))
217
218 timestamp = message.getTimeStamp()
219 if timestamp and not self._disableTimestamps:
220 text = _("\nPosted on %s.\n") % time.strftime(
221 "%c", time.localtime(timestamp))
222 textbuffer.insert(textbuffer.get_end_iter(), text)
223
224 if message.debug:
225 text = "\n\n" + _("Debug information:\n") + message.debug + '\n'
226 textbuffer.insert(textbuffer.get_end_iter(), text)
227
229 # Sort all messages first by (reverse of) level, then priority
230 children = [(-w.message.level, w.message.priority, w)
231 for w in self.buttonbox.get_children()]
232 children.sort()
233 children.reverse()
234 children = [(i, children[i][2]) for i in range(len(children))]
235 for child in children:
236 self.buttonbox.reorder_child(child[1], child[0])
237
238 # the first button, e.g. highest priority
239 return children[0][1]
240
241 # Callbacks
242
261
262 # when the mouse cursor moves, set the cursor image accordingly
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 # without this call, further motion notify events don't get
269 # triggered
270 textview.window.get_pointer()
271
272 # if any of the tags is a link, show a hand
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
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 # we shouldn't follow a link if the user has selected something
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
| Trees | Indices | Help |
|---|
| Generated by Epydoc 3.0.1 on Mon May 11 00:19:37 2015 | http://epydoc.sourceforge.net |