home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / AppInstall / ReleaseNotesViewer.py < prev    next >
Encoding:
Python Source  |  2006-08-02  |  7.3 KB  |  191 lines

  1. # ReleaseNotesViewer.py
  2. #  
  3. #  Copyright (c) 2006 Sebastian Heinlein
  4. #  
  5. #  Author: Sebastian Heinlein <sebastian.heinlein@web.de>
  6. #
  7. #  This modul provides an inheritance of the gtk.TextView that is 
  8. #  aware of http URLs and allows to open them in a browser.
  9. #  It is based on the pygtk-demo "hypertext".
  10. #  This program is free software; you can redistribute it and/or 
  11. #  modify it under the terms of the GNU General Public License as 
  12. #  published by the Free Software Foundation; either version 2 of the
  13. #  License, or (at your option) any later version.
  14. #  This program is distributed in the hope that it will be useful,
  15. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. #  GNU General Public License for more details.
  18. #  You should have received a copy of the GNU General Public License
  19. #  along with this program; if not, write to the Free Software
  20. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. #  USA
  22.  
  23.  
  24. import pygtk
  25. import gtk
  26. import pango
  27. import subprocess
  28. import os
  29.  
  30. class ReleaseNotesViewer(gtk.TextView):
  31.     def __init__(self, notes=None):
  32.         """Init the ReleaseNotesViewer as an Inheritance of the gtk.TextView.
  33.            Load the notes into the buffer and make links clickable"""
  34.         # init the parent
  35.         gtk.TextView.__init__(self)
  36.         # global hovering over link state
  37.         self.hovering = False
  38.         self.first = True
  39.         # setup the buffer and signals
  40.         self.set_property("editable", False)
  41.         self.set_cursor_visible(False)
  42.         self.buffer = gtk.TextBuffer()
  43.         self.set_buffer(self.buffer)
  44.         self.connect("event-after", self.event_after)
  45.         self.connect("motion-notify-event", self.motion_notify_event)
  46.         self.connect("visibility-notify-event", self.visibility_notify_event)
  47.         #self.buffer.connect("changed", self.search_links)
  48.         self.buffer.connect_after("insert-text", self.on_insert_text)
  49.         # search for links in the notes and make them clickable
  50.         if notes != None:
  51.             self.buffer.set_text(notes)
  52.  
  53.     def tag_link(self, start, end, url):
  54.         """Apply the tag that marks links to the specified buffer selection"""
  55.         tag = self.buffer.create_tag(None, foreground="blue",
  56.                                      underline=pango.UNDERLINE_SINGLE)
  57.         tag.set_data("url", url)
  58.         self.buffer.apply_tag(tag , start, end)
  59.  
  60.     def on_insert_text(self, buffer, iter_end, text, *args):
  61.         """Search for http URLs in newly inserted text  
  62.            and tag them accordingly"""
  63.         iter = buffer.get_iter_at_offset(iter_end.get_offset() - len(text))
  64.         iter_real_end = buffer.get_end_iter()
  65.         while 1:
  66.             # search for the next URL in the buffer
  67.             ret = iter.forward_search("http://", 
  68.                                       gtk.TEXT_SEARCH_VISIBLE_ONLY,
  69.                                       iter_end)
  70.             # if we reach the end break the loop
  71.             if not ret:
  72.                 break
  73.             # get the position of the protocol prefix
  74.             (match_start, match_end) = ret
  75.             match_tmp = match_end.copy()
  76.             while 1:
  77.                 # extend the selection to the complete URL
  78.                 if match_tmp.forward_char():
  79.                     text =  match_end.get_text(match_tmp)
  80.                     if text in (" ", ")", "]", "\n", "\t",">","!"):
  81.                         break
  82.                 else:
  83.                     break
  84.                 match_end = match_tmp.copy()
  85.             # call the tagging method for the complete URL
  86.             url = match_start.get_text(match_end)
  87.             tags = match_start.get_tags()
  88.             tagged = False
  89.             for tag in tags:
  90.                 url = tag.get_data("url")
  91.                 if url != "":
  92.                     tagged = True
  93.                     break
  94.             if tagged == False:
  95.                 self.tag_link(match_start, match_end, url)
  96.             # set the starting point for the next search
  97.             iter = match_end
  98.  
  99.     def event_after(self, text_view, event):
  100.         """callback for mouse click events"""
  101.         # we only react on left mouse clicks
  102.         if event.type != gtk.gdk.BUTTON_RELEASE:
  103.             return False
  104.         if event.button != 1:
  105.             return False
  106.  
  107.         # try to get a selection
  108.         try:
  109.             (start, end) = self.buffer.get_selection_bounds()
  110.         except ValueError:
  111.             pass
  112.         else:
  113.             if start.get_offset() != end.get_offset():
  114.                 return False
  115.  
  116.         # get the iter at the mouse position
  117.         (x, y) = self.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
  118.                                               int(event.x), int(event.y))
  119.         iter = self.get_iter_at_location(x, y)
  120.         
  121.         # call open_url if an URL is assigned to the iter
  122.         tags = iter.get_tags()
  123.         for tag in tags:
  124.             url = tag.get_data("url")
  125.             if url != None:
  126.                 self.open_url(url)
  127.                 break
  128.  
  129.     def open_url(self, url):
  130.         """Open the specified URL in a browser"""
  131.         # Find an appropiate browser
  132.         if os.path.exists('/usr/bin/gnome-open'):
  133.             command = ['gnome-open', url]
  134.         else:
  135.             command = ['x-www-browser', url]
  136.  
  137.         # Avoid to run the browser as user root
  138.         if os.getuid() == 0 and os.environ.has_key('SUDO_USER'):
  139.             command = ['sudo', '-u', os.environ['SUDO_USER']] + command
  140.  
  141.         subprocess.Popen(command)
  142.  
  143.     def motion_notify_event(self, text_view, event):
  144.         """callback for the mouse movement event, that calls the
  145.            check_hovering method with the mouse postition coordiantes"""
  146.         x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
  147.                                                  int(event.x), int(event.y))
  148.         self.check_hovering(x, y)
  149.         self.window.get_pointer()
  150.         return False
  151.     
  152.     def visibility_notify_event(self, text_view, event):
  153.         """callback if the widgets gets visible (e.g. moves to the foreground)
  154.            that calls the check_hovering method with the mouse position
  155.            coordinates"""
  156.         (wx, wy, mod) = text_view.window.get_pointer()
  157.         (bx, by) = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx,
  158.                                                      wy)
  159.         self.check_hovering(bx, by)
  160.         return False
  161.  
  162.     def check_hovering(self, x, y):
  163.         """Check if the mouse is above a tagged link and if yes show
  164.            a hand cursor"""
  165.         _hovering = False
  166.         # get the iter at the mouse position
  167.         iter = self.get_iter_at_location(x, y)
  168.         
  169.         # set _hovering if the iter has the tag "url"
  170.         tags = iter.get_tags()
  171.         for tag in tags:
  172.             url = tag.get_data("url")
  173.             if url != None:
  174.                 _hovering = True
  175.                 break
  176.  
  177.         # change the global hovering state
  178.         if _hovering != self.hovering or self.first == True:
  179.             self.first = False
  180.             self.hovering = _hovering
  181.             # Set the appropriate cursur icon
  182.             if self.hovering:
  183.                 self.get_window(gtk.TEXT_WINDOW_TEXT).\
  184.                         set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
  185.             else:
  186.                 self.get_window(gtk.TEXT_WINDOW_TEXT).\
  187.                         set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
  188.