iteration 1 - Use gobject for events in feed, summaryitem and feedlist
[straw.git] / src / lib / subscribe.py
blob671f510967971eedd64845c1f8644e78caf1acd4
1 """ subscribe.py
3 Module for handling feed subscription process.
4 """
5 __copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
6 __license__ = """ GNU General Public License
8 This program is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 2 of the License, or (at your option) any later
11 version.
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along with
18 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 Place - Suite 330, Boston, MA 02111-1307, USA. """
22 import urlparse
23 import urllib
24 import pygtk
25 pygtk.require('2.0')
26 import gtk
27 import gtk.glade
28 import gettext
29 import feeds
30 import error
31 import Event
32 import utils
33 import SummaryParser
34 import ParsedSummary
35 import dialogs
36 import time
37 import URLFetch
38 import MVP
39 import Config
41 class SubscribeView(MVP.GladeView):
42 def _initialize(self):
43 self._window = self._widget.get_widget('subscribe_dialog')
44 self._location_entry = self._widget.get_widget('feed_location_entry')
45 self._username_entry = self._widget.get_widget('username_entry')
46 self._password_entry = self._widget.get_widget('password_entry')
47 self._error_text = self._widget.get_widget('error_text')
48 self._error_box = self._widget.get_widget('error_box')
49 self._location_entry.grab_focus()
51 def _on_ok_clicked(self, *args):
52 location = self._location_entry.get_text()
53 if not location:
54 self.display_error(_("Feed Location must not be empty"))
55 return
56 username = self._username_entry.get_text()
57 username = username.strip()
58 password = self._password_entry.get_text()
59 password = password.strip()
61 config = Config.get_instance()
62 if config.offline:
63 self._window.hide()
64 response = dialogs.report_offline_status(self._window)
65 if response == gtk.RESPONSE_CANCEL:
66 self.show()
67 return
68 config.offline = not config.offline
69 self._presenter.subscribe(location, username, password)
71 def _clear_entries(self):
72 self._location_entry.delete_text(0,-1)
73 self._username_entry.delete_text(0,-1)
74 self._password_entry.delete_text(0,-1)
76 def show(self):
77 self._clear_entries()
78 self._error_box.set_property('visible',False)
79 self._window.show()
81 def display_error(self, text):
82 self._error_box.set_property('visible',True)
83 self._error_text.set_text(text)
85 def set_location_entry(self, location):
86 self._location_entry.set_text(location)
88 def set_parent(self, parent):
89 self._window.set_transient_for(parent)
91 def _on_close_clicked(self, *args):
92 self._window.hide()
94 def _on_feed_location_entry_key_press_event(self, widget, event):
95 if event.keyval == gtk.keysyms.Return:
96 self._presenter.subscribe(self._location_entry.get_text())
98 class SubscribePresenter(MVP.BasicPresenter):
100 def _normalize(self, url):
101 u = urlparse.urlsplit(url.strip())
102 # we check if 'scheme' is not empty here because URIs like
103 # "google.com" IS valid but, in this case, 'scheme' is empty because
104 # urlsplit() expects urls are in the format of scheme://netloc/...
105 if not u[0] or (u[0] != "http" and u[0] != "feed"):
106 return None
107 if u[0] == 'feed':
108 u = urlparse.urlsplit(u[2])
109 # .. if that happens then we munge the url by adding a // and assume
110 # that 'http' is the scheme.
111 if u[1] == '':
112 u = urlparse.urlsplit("//" + url, 'http')
113 return u
115 def subscribe(self, location, username=None, password=None):
116 self._username = username
117 self._password = password
118 self._location = location
120 consumer = SubscribeConsumer(self)
122 try:
123 URLFetch.get_instance().request(location, consumer,
124 user=username, password=password)
125 except Exception, e:
126 consumer.http_failed(e)
128 def set_parent(self, parent):
129 self.view.set_parent(parent)
131 def get_credential(self):
132 return (self._location, self._username, self._password)
134 def show(self, url):
135 if url:
136 self.view.set_location_entry(url)
137 self.view.show()
139 # def set_url_dnd(self, url):
140 # self._window.show()
141 # self._feed_location_presenter.view.find_feed(url)
143 def set_location_from_clipboard(self):
144 def _clipboard_cb(cboard, url, data=None):
145 if url:
146 url = self._normalize(url)
147 if url and url[0] == "http":
148 url = urlparse.urlunsplit(url)
149 self.view.set_location_entry(url)
150 clipboard = gtk.clipboard_get(selection="CLIPBOARD")
151 clipboard.request_text(_clipboard_cb, None)
154 class SubscribeConsumer:
156 def __init__(self, presenter):
157 self._presenter = presenter
159 def http_results(self, status, data):
160 url, user, password = self._presenter.get_credential()
161 feed = feeds.Feed.create_new_feed("", url, user, password)
162 parsed = SummaryParser.parse(data, feed)
163 if parsed.title == "":
164 # store url loc in title in case it's empty
165 parsed.title = urlparse.urlsplit(url.strip())[1]
166 feed.title = utils.convert_entities(parsed.title)
167 feed.channel_description = utils.convert_entities(parsed.description)
168 feed.access_info = (url, user, password)
169 feed.last_poll = int(time.time())
170 category = None # Add to 'All' category
171 feeds.get_instance().append(category, feed)
172 feed.router.route_all(parsed)
173 feed.poll_done()
175 def http_failed(self, exception):
176 # XXX signal to the user that subscription failed? incl. erros
177 print "subscribe failed", exception
179 def operation_stopped(self):
180 # XXX signal that it stopped, why it stopped, and stop all progress
181 # bars, etc...
182 print "subscribe operation stopped"
184 def display_window(url=None, parent=None):
185 dialog = _get_instance()
186 dialog.set_parent(parent)
187 dialog.set_location_from_clipboard()
188 dialog.show(url)
190 instance = None
191 def _get_instance():
192 global instance
193 if instance is None:
194 widget_tree = MVP.get_widget_tree('subscribe_dialog')
195 instance = SubscribePresenter(view=SubscribeView(widget_tree))
196 return instance