diff options
Diffstat (limited to 'UpdateManager/ReleaseNotesViewer.py')
| -rw-r--r-- | UpdateManager/ReleaseNotesViewer.py | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/UpdateManager/ReleaseNotesViewer.py b/UpdateManager/ReleaseNotesViewer.py new file mode 100644 index 00000000..33122be9 --- /dev/null +++ b/UpdateManager/ReleaseNotesViewer.py @@ -0,0 +1,179 @@ +# ReleaseNotesViewer.py +# +# Copyright (c) 2006 Sebastian Heinlein +# +# Author: Sebastian Heinlein <sebastian.heinlein@web.de> +# +# This modul provides an inheritance of the gtk.TextView that is +# aware of http URLs and allows to open them in a browser. +# It is based on the pygtk-demo "hypertext". +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + + +import pygtk +import gtk +import pango +import subprocess +import os + +class ReleaseNotesViewer(gtk.TextView): + def __init__(self, notes): + """Init the ReleaseNotesViewer as an Inheritance of the gtk.TextView. + Load the notes into the buffer and make links clickable""" + # init the parent + gtk.TextView.__init__(self) + # global hovering over link state + self.hovering = False + self.first = True + # setup the buffer and signals + self.set_property("editable", False) + self.set_cursor_visible(False) + self.buffer = gtk.TextBuffer() + self.set_buffer(self.buffer) + self.buffer.set_text(notes) + self.connect("event-after", self.event_after) + self.connect("motion-notify-event", self.motion_notify_event) + self.connect("visibility-notify-event", self.visibility_notify_event) + # search for links in the notes and make them clickable + self.search_links() + + def tag_link(self, start, end, url): + """Apply the tag that marks links to the specified buffer selection""" + tag = self.buffer.create_tag(None, foreground="blue", + underline=pango.UNDERLINE_SINGLE) + tag.set_data("url", url) + self.buffer.apply_tag(tag , start, end) + + def search_links(self): + """Search for http URLs in the buffer and call the tag_link method + for each one to tag them as links""" + # start at the beginning of the buffer + iter = self.buffer.get_iter_at_offset(0) + while 1: + # search for the next URL in the buffer + ret = iter.forward_search("http://", gtk.TEXT_SEARCH_VISIBLE_ONLY, + None) + # if we reach the end break the loop + if not ret: + break + # get the position of the protocol prefix + (match_start, match_end) = ret + match_tmp = match_end.copy() + while 1: + # extend the selection to the complete URL + if match_tmp.forward_char(): + text = match_end.get_text(match_tmp) + if text in (" ", ")", "]", "\n", "\t"): + break + else: + break + match_end = match_tmp.copy() + # call the tagging method for the complete URL + url = match_start.get_text(match_end) + self.tag_link(match_start, match_end, url) + # set the starting point for the next search + iter = match_end + + def event_after(self, text_view, event): + """callback for mouse click events""" + # we only react on left mouse clicks + if event.type != gtk.gdk.BUTTON_RELEASE: + return False + if event.button != 1: + return False + + # try to get a selection + try: + (start, end) = self.buffer.get_selection_bounds() + except ValueError: + pass + else: + if start.get_offset() != end.get_offset(): + return False + + # get the iter at the mouse position + (x, y) = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, + int(event.x), int(event.y)) + iter = self.get_iter_at_location(x, y) + + # call open_url if an URL is assigned to the iter + tags = iter.get_tags() + for tag in tags: + url = tag.get_data("url") + if url != "": + self.open_url(url) + break + + def open_url(self, url): + """Open the specified URL in a browser""" + # Find an appropiate browser + if os.path.exists('usr/bin/gnome-open'): + command = ['gnome-open', url] + else: + command = ['x-www-browser', url] + + # Avoid to run the browser as user root + if os.getuid() == 0 and os.environ.has_key('SUDO_USER'): + command = ['sudo', '-u', os.environ['SUDO_USER']] + command + + subprocess.Popen(command) + + def motion_notify_event(self, text_view, event): + """callback for the mouse movement event, that calls the + check_hovering method with the mouse postition coordiantes""" + x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, + int(event.x), int(event.y)) + self.check_hovering(x, y) + self.window.get_pointer() + return False + + def visibility_notify_event(self, text_view, event): + """callback if the widgets gets visible (e.g. moves to the foreground) + that calls the check_hovering method with the mouse position + coordinates""" + (wx, wy, mod) = text_view.window.get_pointer() + (bx, by) = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx, + wy) + self.check_hovering(bx, by) + return False + + def check_hovering(self, x, y): + """Check if the mouse is above a tagged link and if yes show + a hand cursor""" + _hovering = False + # get the iter at the mouse position + iter = self.get_iter_at_location(x, y) + + # set _hovering if the iter has the tag "url" + tags = iter.get_tags() + for tag in tags: + url = tag.get_data("url") + if url != "": + _hovering = True + break + + # change the global hovering state + if _hovering != self.hovering or self.first == True: + self.first = False + self.hovering = _hovering + # Set the appropriate cursur icon + if self.hovering: + self.get_window(gtk.TEXT_WINDOW_TEXT).\ + set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2)) + else: + self.get_window(gtk.TEXT_WINDOW_TEXT).\ + set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) |
