Fixed url_show.
[straw.git] / straw / helpers.py
blob366dc90d00611e1cac3bfb4539b51f56faa30ce6
1 """ dialogs.py
3 Module for displaying dialogs related to errors, warnings, notifications,
4 etc...
5 """
7 __copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
8 __license__ = """
9 Straw is free software; you can redistribute it and/or modify it under the
10 terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 2 of the License, or (at your option) any later
12 version.
14 Straw is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along with
19 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 Place - Suite 330, Boston, MA 02111-1307, USA. """
22 from Constants import *
23 from gettext import gettext as _
24 import Config
25 import codecs
26 import error
27 import gnomevfs
28 import gobject
29 import gtk
30 import htmlentitydefs
31 import opml
32 import os.path, re, locale, time, calendar
33 import straw
34 import urllib, string, urlparse
35 import xml
37 class UIFactory(object):
38 _shared_state = {}
39 manager = None
41 actions = [
42 ("refresh", gtk.STOCK_REFRESH, _("_Refresh"), None, _("Update this feed"), None),
43 ("add_child", gtk.STOCK_ADD, _("Add child"), None, _("Update this feed"), None),
44 ("mark_as_read", gtk.STOCK_CLEAR, _("_Mark As Read"),
45 None, _("Mark all items in this feed as read"), None),
46 ("stop_refresh", None, _("_Stop Refresh"), None, _("Stop updating this feed"), None),
47 ("remove", gtk.STOCK_REMOVE, _("Remo_ve"), None, _("Remove"), None),
48 ("properties", gtk.STOCK_INFO, _("_Information"), None, _("Feed-specific properties"), None),
49 ("text_copy", gtk.STOCK_COPY, "_Copy", None, None, None),
50 ("link_copy", None, "_Copy Link Location", None, None, None),
51 ("link_open", None, "_Open Link", None, None, None),
52 ("subscribe", None, "_Subscribe", None, None, None),
53 ("zoom_in", gtk.STOCK_ZOOM_IN, "Zoom _In", None, None, None),
54 ("zoom_out", gtk.STOCK_ZOOM_OUT, "Zoom _Out", None, None, None),
55 ("zoom_100", gtk.STOCK_ZOOM_100, "_Normal Size", None, None, None),
56 ("mark_as_unread", gtk.STOCK_CONVERT, "Mark as _Unread", None, "Mark this item as unread", None)
59 def __new__(cls, *a, **k):
60 obj = object.__new__(cls, *a, **k)
61 obj.__dict__ = cls._shared_state
62 return obj
64 def __init__(self, name):
65 if not self.manager:
66 print 'initializing ui manager'
67 self.action_groups = {}
68 self.manager = gtk.UIManager()
69 action_group = gtk.ActionGroup(name)
70 action_group.add_actions(UIFactory.actions)
71 num_action_groups = len(self.manager.get_action_groups())
72 self.action_groups[name] = num_action_groups
73 self.manager.insert_action_group(action_group, num_action_groups)
74 ui = os.path.join(straw.defs.STRAW_DATA_DIR, 'ui.xml')
75 self.manager.add_ui_from_file(ui)
77 def get_popup(self, path):
78 return self.manager.get_widget(path)
80 def get_action(self, path):
81 return self.manager.get_action(path)
83 def ensure_update(self):
84 self.manager.ensure_update()
87 def report_error(primary, secondary, parent=None):
88 dialog = gtk.MessageDialog(parent,
89 type=gtk.MESSAGE_ERROR,
90 buttons=gtk.BUTTONS_OK,
91 message_format=primary)
92 dialog.format_secondary_text(secondary)
93 response = dialog.run()
94 dialog.destroy()
95 return response
97 def report_offline_status(parent=None):
98 dialog = gtk.MessageDialog(parent,
99 type=gtk.MESSAGE_WARNING,
100 buttons=gtk.BUTTONS_OK_CANCEL,
101 message_format="You Are Offline!")
102 dialog.format_secondary_markup(_("You are currently reading offline. Would you like to go online now?"))
103 response = dialog.run()
104 dialog.destroy()
105 return response
107 def credits():
108 people = u'''Author:
109 Juri Pakaste <juri@iki.fi>
111 Contributors:
112 Jan Alonzo <jmalonzo@unpluggable.com>
113 Ryan P. Skadberg <skadz@stigmata.org>
114 Leandro Lameiro <lameiro@gmail.com>
115 Tuukka Hastrup <tuukka@iki.fi>
117 Past Contributors:
118 Iain McCoy <iain@mccoy.id.au>
119 Lucas Nussbaum <lucas@lucas-nussbaum.net>
120 Olivier Crete <tester@tester.ca>
121 Scott Douglas-Watson <sdouglaswatson@yahoo.co.uk>
122 Terje R\xf8sten (distutils)
124 Special Thanks:
125 Mark Pilgrim (feedparser and feedfinder)
126 Joe Gregorio (httplib2)
128 iconfile = os.path.join(straw.defs.STRAW_DATA_DIR,"straw.png")
129 logo = gtk.gdk.pixbuf_new_from_file(iconfile)
130 description = _("A Desktop Feed Reader")
131 straw_copyright = u"""
132 Copyright \xa9 2005-2007 Straw Contributors
133 Copyright \xa9 2002-2004 Juri Pakaste"""
134 artists = [
135 u'Jakub \'jimmac\' Steiner',
136 u'Juri Pakaste'
139 translators = [
140 u"GNOME i18n Project and Translators<http://developer.gnome.org/projects/gtp/>",
141 u"Juri Pakaste <juri@iki.fi>",
142 u"Martin Steldinger <tribble@hanfplantage.de>",
143 u"David Rousseau <boiteaflood@wanadoo.fr>",
144 u"Sergei Vavinov <svv@cmc.msu.ru>",
145 u"Terje R\xf8sten <terjeros@phys.ntnu.no>",
146 u"Francisco J. Fernandez <franciscojavier.fernandez.serrador@hispalinux.es>",
147 u"Elros Cyriatan (Dutch Translation)"
150 translator_credits = 'translator_credits'
151 about = gtk.AboutDialog()
152 about.set_name(straw.defs.PACKAGE)
153 about.set_version(straw.defs.VERSION)
154 about.set_copyright(straw_copyright)
155 about.set_comments(description)
156 about.set_authors(people.splitlines())
157 about.set_artists(artists)
158 about.set_logo(logo)
159 about.set_translator_credits(translator_credits)
160 about.set_license(__license__)
161 gtk.about_dialog_set_url_hook(lambda about, url: url_show(url))
162 about.set_website(straw.defs.STRAW_HOME)
163 about.set_website_label(straw.defs.STRAW_HOME)
164 about.connect('response', lambda widget, response: widget.destroy())
165 return about
167 def listdiff(l1, l2, test=None):
168 if test is not None:
169 return _listdifftest(l1, l2, test)
170 common = []
171 inl1 = []
172 inl2 = []
173 for e in l1:
174 if e in l2:
175 common.append(e)
176 else:
177 inl1.append(e)
178 for e in l2:
179 if e in l1:
180 if e not in common:
181 common.append(e)
182 else:
183 inl2.append(e)
184 return (common, inl1, inl2)
186 def url_show(url):
187 browser_type = Config.get(OPTION_WEB_BROWSER_TYPE)
189 if browser_type == "gnome":
190 return gnomevfs.url_show(url)
191 else:
192 try:
193 browser_cmd = Config.get(OPTION_WEB_BROWSER_CMD)
194 cmdbin, args = string.splitfields(browser_cmd, maxsplit=1)
195 link = args % url
196 import subprocess
197 pid = subprocess.Popen([cmdbin, link]).pid
198 return pid
199 except ValueError, ve:
200 raise UrlOpenException("Problem opening link %s" % ve)
203 def set_clipboard_text(text):
204 clipboard = gtk.clipboard_get(selection="CLIPBOARD")
205 clipboard.set_text(text)
208 class UrlOpenException(Exception):
209 pass
211 entity = re.compile(r'\&.\w*?\;')
212 def convert_entities(text):
213 def conv(ents):
214 entities = htmlentitydefs.entitydefs
215 ents = ents.group(0)
216 ent_code = entities.get(ents[1:-1], None)
217 if ent_code is not None:
218 try:
219 ents = unicode(ent_code, get_locale_encoding())
220 except UnicodeDecodeError:
221 ents = unicode(ent_code, 'latin-1')
222 except Exception, ex:
223 error.log("error occurred while converting entity %s: %s" % (ents, ex))
225 # check if it still needs conversion
226 if entity.search(ents) is None:
227 return ents
229 if ents[1] == '#':
230 code = ents[2:-1]
231 base = 10
232 if code[0] == 'x':
233 code = code[1:]
234 base = 16
235 return unichr(int(code, base))
236 else:
237 return
239 in_entity = entity.search(text)
240 if in_entity is None:
241 return text
242 else:
243 ctext = in_entity.re.sub(conv, text)
244 return ctext
246 def complete_url(url, feed_location):
247 #print "---- COMPLETING %s WITH %s" % (url, feed_location)
248 url = urllib.quote(url, safe=string.punctuation)
249 if urlparse.urlparse(url)[0] == '':
250 return urlparse.urljoin(feed_location, url)
251 else:
252 return url
254 def get_url_location(url):
255 url = urllib.quote(url, safe=string.punctuation)
256 parsed_url = urlparse.urlsplit(url)
257 return urlparse.urlunsplit((parsed_url[0], parsed_url[1], '','',''))
259 def get_locale_encoding():
260 try:
261 encoding = locale.getpreferredencoding()
262 except locale.Error:
263 encoding = sys.getdefaultencoding()
264 return encoding
266 def format_date(date, format=None, encoding=None):
267 return date
268 if format is None:
269 format = get_date_format()
270 if encoding is None:
271 encoding = get_locale_encoding()
272 timestr = time.strftime(format, time.localtime(calendar.timegm(date)))
273 return unicode(timestr, encoding)
275 def get_date_format():
276 # this is here just to make xgettext happy: it should be defined in
277 # only one place, and a good one would be MainWindow.py module level.
278 # however, we can't access _ there.
279 # The format: %A is the full weekday name
280 # %B is the full month name
281 # %e is the day of the month as a decimal number,
282 # without leading zero
283 # This should be translated to be suitable for the locale in
284 # question, feel free to alter the order and the parameters (they
285 # are strftime(3) parameters, the whole string is passed to the
286 # function, Straw does no additional interpretation) if you feel
287 # it's necessary in the translation file.
288 return _('%A %B %e %H:%M')
290 def pango_escape(text):
291 if text:
292 return xml.sax.saxutils.escape(text)
293 else:
294 return ""
296 def html_replace(exc):
297 """ Python Cookbook 2ed, Section 1.23
299 if isinstance(exc, (UnicodeDecodeError, UnicodeTranslateError)):
300 s = [ u'&%s;' % codepoint2name[ord(c)] for c in exc.object[exc.start:exc.end]]
301 return ''.join(s), exc.end
302 else:
303 raise TypeError("can't handle %s" % exc.__name__)
305 codecs.register_error('html_replace', html_replace)