1
# ReleaseNotesViewer.py
2
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
3
4
# Copyright (c) 2006 Sebastian Heinlein
6
7
# Author: Sebastian Heinlein <sebastian.heinlein@web.de>
7
8
# Michael Vogt <michael.vogt@ubuntu.com>
9
# This modul provides an inheritance of the Gtk.TextView that is
10
# This modul provides an inheritance of the Gtk.TextView that is
10
11
# aware of http URLs and allows to open them in a browser.
11
12
# It is based on the pygtk-demo "hypertext".
13
# This program is free software; you can redistribute it and/or
14
# modify it under the terms of the GNU General Public License as
14
# This program is free software; you can redistribute it and/or
15
# modify it under the terms of the GNU General Public License as
15
16
# published by the Free Software Foundation; either version 2 of the
16
17
# License, or (at your option) any later version.
18
19
# This program is distributed in the hope that it will be useful,
19
20
# but WITHOUT ANY WARRANTY; without even the implied warranty of
20
21
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
22
# GNU General Public License for more details.
23
24
# You should have received a copy of the GNU General Public License
24
25
# along with this program; if not, write to the Free Software
25
26
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
59
61
#self.buffer.connect("changed", self.search_links)
60
62
self.buffer.connect_after("insert-text", self.on_insert_text)
61
63
# search for links in the changelog and make them clickable
64
if changelog is not None:
63
65
self.buffer.set_text(changelog)
65
67
def create_context_menu(self, url):
66
"""Create the context menu to be displayed when links are right clicked"""
68
"""Create the context menu to be displayed when links are right
67
70
self.menu = Gtk.Menu()
69
72
# create menu items
70
73
item_grey_link = Gtk.MenuItem()
71
74
item_grey_link.set_label(url)
72
item_grey_link.connect("activate", self.handle_context_menu, "open", url)
75
item_grey_link.connect("activate", self.handle_context_menu, "open",
73
77
item_seperator = Gtk.MenuItem()
74
78
item_open_link = Gtk.MenuItem()
75
79
item_open_link.set_label(_("Open Link in Browser"))
76
item_open_link.connect("activate", self.handle_context_menu, "open", url)
80
item_open_link.connect("activate", self.handle_context_menu, "open",
77
82
item_copy_link = Gtk.MenuItem()
78
83
item_copy_link.set_label(_("Copy Link to Clipboard"))
79
item_copy_link.connect("activate", self.handle_context_menu, "copy", url)
84
item_copy_link.connect("activate", self.handle_context_menu, "copy",
82
88
self.menu.add(item_grey_link)
83
89
self.menu.add(item_seperator)
84
90
self.menu.add(item_open_link)
85
91
self.menu.add(item_copy_link)
86
92
self.menu.show_all()
88
94
def handle_context_menu(self, menuitem, action, url):
89
95
"""Handle activate event for the links' context menu"""
90
96
if action == "open":
110
116
tag = self.buffer.create_tag(None, foreground="blue",
111
117
underline=Pango.Underline.SINGLE)
113
self.buffer.apply_tag(tag , start, end)
119
self.buffer.apply_tag(tag, start, end)
115
121
def on_insert_text(self, buffer, iter_end, text, *args):
116
"""Search for http URLs in newly inserted text
122
"""Search for http URLs in newly inserted text
117
123
and tag them accordingly"""
119
125
# some convenient urls
121
127
DEBIAN = "http://bugs.debian.org/"
122
128
CVE = "http://cve.mitre.org/cgi-bin/cvename.cgi?name="
123
129
# some convinient end-markers
126
punct = [",","!",":"]
130
ws = [" ", "\t", "\n"]
131
brak = [")", "]", ">"]
132
punct = [",", "!", ":"]
130
136
# search items are start-str, list-of-end-strs, url-prefix
131
137
# a lot of this search is "TEH SUCK"(tm) because of limitations
132
138
# in iter.forward_search()
133
139
# - i.e. no insensitive searching, no regexp
134
search_items = [ ("http://", ws+brak+punct+dot_cr, "http://"),
135
("LP#", ws+brak+dot, MALONE),
136
("LP: #", ws+brak+dot, MALONE),
137
("lp: #", ws+brak+dot, MALONE),
138
("LP:#", ws+brak+dot, MALONE),
139
("Malone: #", ws+brak+dot, MALONE),
140
("Malone:#", ws+brak+dot, MALONE),
141
("Ubuntu: #", ws+brak+dot, MALONE),
142
("Ubuntu:#", ws+brak+dot, MALONE),
143
("Closes: #",ws+brak+dot, DEBIAN),
144
("Closes:#",ws+brak+dot, DEBIAN),
145
("closes:#",ws+brak+dot, DEBIAN),
146
("closes: #",ws+brak+dot, DEBIAN),
147
("CVE-", ws+brak+dot, CVE),
140
search_items = [("http://", ws + brak + punct + dot_cr, "http://"),
141
("LP#", ws + brak + dot, MALONE),
142
("LP: #", ws + brak + dot, MALONE),
143
("lp: #", ws + brak + dot, MALONE),
144
("LP:#", ws + brak + dot, MALONE),
145
("Malone: #", ws + brak + dot, MALONE),
146
("Malone:#", ws + brak + dot, MALONE),
147
("Ubuntu: #", ws + brak + dot, MALONE),
148
("Ubuntu:#", ws + brak + dot, MALONE),
149
("Closes: #", ws + brak + dot, DEBIAN),
150
("Closes:#", ws + brak + dot, DEBIAN),
151
("closes:#", ws + brak + dot, DEBIAN),
152
("closes: #", ws + brak + dot, DEBIAN),
153
("CVE-", ws + brak + dot, CVE),
150
156
iter = buffer.get_iter_at_offset(iter_end.get_offset() - len(text))
205
211
(x, y) = self.window_to_buffer_coords(Gtk.TextWindowType.WIDGET,
206
212
int(event.x), int(event.y))
207
213
iter = self.get_iter_at_location(x, y)
209
215
# call open_url or menu.popup if an URL is assigned to the iter
210
216
tags = iter.get_tags()
212
218
if hasattr(tag, "url"):
213
if event.button == 1:
219
if event.button == 1:
214
220
open_url(tag.url)
216
222
if event.button == 3:
217
223
self.create_context_menu(tag.url)
218
self.menu.popup(None, None, None, None, event.button, event.time)
224
self.menu.popup(None, None, None, None, event.button,
221
228
def motion_notify_event(self, text_view, event):
226
233
self.check_hovering(x, y)
227
234
self.get_window(Gtk.TextWindowType.TEXT).get_pointer()
230
237
def visibility_notify_event(self, text_view, event):
231
238
"""callback if the widgets gets visible (e.g. moves to the foreground)
232
239
that calls the check_hovering method with the mouse position
234
(screen, wx, wy, mod) = text_view.get_window(Gtk.TextWindowType.TEXT).get_pointer()
235
(bx, by) = text_view.window_to_buffer_coords(Gtk.TextWindowType.WIDGET, wx,
241
window = text_view.get_window(Gtk.TextWindowType.TEXT)
242
(screen, wx, wy, mod) = window.get_pointer()
243
(bx, by) = text_view.window_to_buffer_coords(Gtk.TextWindowType.WIDGET,
237
245
self.check_hovering(bx, by)
254
262
# change the global hovering state
255
if _hovering != self.hovering or self.first == True:
263
if _hovering != self.hovering or self.first:
256
264
self.first = False
257
265
self.hovering = _hovering
258
266
# Set the appropriate cursur icon
259
267
if self.hovering:
260
self.get_window(Gtk.TextWindowType.TEXT).\
261
set_cursor(Gdk.Cursor.new(Gdk.CursorType.HAND2))
268
self.get_window(Gtk.TextWindowType.TEXT).set_cursor(
269
Gdk.Cursor.new(Gdk.CursorType.HAND2))
263
self.get_window(Gtk.TextWindowType.TEXT).\
264
set_cursor(Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR))
271
self.get_window(Gtk.TextWindowType.TEXT).set_cursor(
272
Gdk.Cursor.new(Gdk.CursorType.LEFT_PTR))
267
275
if __name__ == "__main__":