~ubuntu-core-dev/update-manager/main

« back to all changes in this revision

Viewing changes to UpdateManager/ReleaseNotesViewer.py

  • Committer: Michael Terry
  • Date: 2012-06-28 16:15:24 UTC
  • Revision ID: michael.terry@canonical.com-20120628161524-hqs1adtbgl6qahio
drop DistUpgradeFetcher and related bits from this package and move them into ubuntu-release-upgrader

Show diffs side-by-side

added added

removed removed

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