iteration 1 - Use gobject for events in feed, summaryitem and feedlist
[straw.git] / src / lib / FeedPropertiesDialog.py
blobe6a78b8436738f87a0f13bbb3e1dd7df9cc4aba2
1 """ FeedPropertiesDialog.py
3 Provides a module for handling the properties of a feed
4 """
5 __copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
6 __license__ = """
7 Straw is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2 of the License, or (at your option) any later
10 version.
12 Straw is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place - Suite 330, Boston, MA 02111-1307, USA. """
21 from error import log, logparam, logtb
22 from xml.sax import saxutils
23 import pygtk
24 pygtk.require('2.0')
25 import gtk
26 import gobject
27 import time
28 import utils
29 import feeds
30 import Config
31 import FeedCategoryList
32 import SummaryParser
33 import gettext
34 import MVP
36 class FeedPropertyView(MVP.GladeView):
38 COLUMN_NAME = 0
39 COLUMN_MEMBER = 1
40 COLUMN_OBJECT = 2
42 def _initialize(self):
43 self._feed = None
44 self._defaults = {'title':'','url':'','username':'','password':''}
45 self._window = self._widget.get_widget('feed_properties')
46 self._title = self._widget.get_widget('properties_title_entry')
47 self._location = self._widget.get_widget('properties_location_entry')
48 self._username = self._widget.get_widget('properties_username_entry')
49 self._password = self._widget.get_widget('properties_password_entry')
51 self._next_refresh_label = self._widget.get_widget('properties_next_refresh_label')
52 self._previous_refresh_label = self._widget.get_widget('properties_previous_refresh_label')
54 self._restore_button = self._widget.get_widget('properties_reset_button')
55 self._refresh_spin = self._widget.get_widget('properties_refresh_spin')
56 self._articles_spin = self._widget.get_widget('properties_articles_spin')
57 self._refresh_default_check = self._widget.get_widget('properties_keep_refresh_default')
58 self._articles_default_check = self._widget.get_widget('properties_keep_articles_default')
60 self._categories_treeview = self._widget.get_widget('feed_categories_treeview')
62 self._feed_info_description = self._widget.get_widget('feed_info_description')
63 self._feed_info_copyright = self._widget.get_widget('feed_info_copyright')
64 self._feed_info_link_box = self._widget.get_widget('feed_info_link_box')
66 model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN,
67 gobject.TYPE_PYOBJECT)
68 self._categories_treeview.set_model(model)
69 self._categories_treeview.set_rules_hint(True)
71 r = gtk.CellRendererToggle()
72 r.connect('toggled', self.member_toggled)
73 column = gtk.TreeViewColumn(_('Member'), r, active=self.COLUMN_MEMBER)
74 self._categories_treeview.append_column(column)
76 r = gtk.CellRendererText()
77 column = gtk.TreeViewColumn(_('Name'), r, text=self.COLUMN_NAME)
78 self._categories_treeview.append_column(column)
80 def set_feed(self, feed):
81 self._feed = feed
83 def member_toggled(self, cell, path):
84 model = self._categories_treeview.get_model()
85 category = model[path][self.COLUMN_OBJECT]
86 if self._feed in category.feeds:
87 category.remove_feed(self._feed)
88 model[path][self.COLUMN_MEMBER] = False
89 else:
90 category.append_feed(self._feed, False)
91 model[path][self.COLUMN_MEMBER] = True
93 def show(self):
94 self._initializing_window = True
95 self.display_properties()
96 self._window.present()
97 self._initializing_window = False
99 def hide(self, *args):
100 self._presenter.activate_deleter()
101 self._window.hide()
102 self._window.destroy()
104 def _on_feed_properties_delete_event(self, *args):
105 self.hide()
106 return True
108 def _on_properties_close_button_clicked(self, *args):
109 self.hide()
110 return
112 def display_properties(self):
113 self._defaults['title'] = self._feed.title
114 loc, un, pw = self._feed.access_info
115 self._defaults['url'] = loc
116 self._defaults['username'] = un
117 self._defaults['password'] = pw
118 self._defaults['frequency'] = self._feed.poll_frequency
119 self._defaults['stored'] = self._feed.number_of_items_stored
121 self._window.set_title(_("%s Properties") % self._feed.title)
122 self._title.set_text(self._feed.title)
123 self._location.set_text(self._feed.access_info[0])
125 config = Config.get_instance()
126 if self._feed.poll_frequency == feeds.Feed.DEFAULT:
127 freq = config.poll_frequency
128 fdefault = True
129 self._refresh_keep = True
130 else:
131 freq = self._feed.poll_frequency
132 fdefault = False
133 self._refresh_keep = False
134 self._refresh_spin.set_value(float(freq / 60))
135 self._refresh_spin.set_sensitive(not fdefault)
136 self._refresh_default_check.set_active(fdefault)
137 if self._feed.number_of_items_stored == feeds.Feed.DEFAULT:
138 nitems = config.number_of_items_stored
139 nidefault = True
140 self._articles_keep = True
141 else:
142 nitems = self._feed.number_of_items_stored
143 nidefault = False
144 self._articles_keep = False
145 self._articles_spin.set_value(float(nitems))
146 self._articles_spin.set_sensitive(not nidefault)
147 self._articles_default_check.set_active(nidefault)
149 if un:
150 self._username.set_text(un)
151 if pw:
152 self._password.set_text(pw)
154 model = self._categories_treeview.get_model()
155 model.clear()
156 fclist = FeedCategoryList.get_instance()
157 for c in fclist.user_categories:
158 iter = model.append()
159 model.set(iter,
160 self.COLUMN_NAME, c.title,
161 self.COLUMN_MEMBER, self._feed in c.feeds,
162 self.COLUMN_OBJECT, c)
164 self._previous_refresh_label.set_text(
165 utils.format_date(time.gmtime(self._feed.last_poll)))
166 next = self._feed.next_refresh
167 if next:
168 self._next_refresh_label.set_text(
169 utils.format_date(time.gmtime(next)))
170 self._next_refresh_label.show()
171 else:
172 self._next_refresh_label.hide()
174 self._display_feed_information(self._feed)
175 self._restore_button.set_sensitive(False)
177 def _display_feed_information(self, feed):
178 title = utils.convert_entities(feed.channel_title)
179 if len(title) == 0:
180 title = feed.title or feed.channel_link
181 title = title.strip()
183 link = feed.channel_link.strip()
184 if not link: link = feed.location
186 if link:
187 link_button = gtk.LinkButton(link, link)
188 self._feed_info_link_box.pack_end(link_button)
189 gtk.link_button_set_uri_hook(self._load_uri, link)
190 self._feed_info_link_box.show_all()
192 description = utils.convert_entities(feed.channel_description.strip())
193 if description and description != title:
194 description = read_text(description, len(description))
195 self._feed_info_description.set_text(utils.convert_entities(description))
196 self._feed_info_description.show()
197 else:
198 self._feed_info_description.hide()
200 copyright = utils.convert_entities(feed.channel_copyright)
201 if copyright:
202 self._feed_info_copyright.set_text(copyright)
203 self._feed_info_copyright.show()
204 else:
205 self._feed_info_copyright.hide()
207 def _load_uri(self, widget, event, data):
208 utils.url_show(data)
210 def restore_defaults(self):
211 # FIXME: add frequency and number of items and the default flags
212 self._feed.title = self._defaults['title']
213 self._feed.access_info = (
214 self._defaults['url'], self._defaults['username'], self._defaults['password'])
215 self._title.set_text(self._feed.title)
216 self._location.set_text(self._feed.location)
217 self._username.set_text(self._defaults.get('username',''))
218 self._password.set_text(self._defaults.get('password',''))
219 self._refresh_default_check.set_active(self._refresh_keep)
220 if not self._refresh_keep:
221 self._refresh_spin.set_value(float(self._refresh_default))
222 self._articles_default_check.set_active(self._articles_keep)
223 if not self._articles_keep:
224 self._articles_spin.set_value(float(self._articles_default))
225 self._restore_button.set_sensitive(False)
227 def _on_properties_title_entry_insert_text(self, *args):
228 if self._initializing_window:
229 return
230 self._restore_button.set_sensitive(True)
232 def _on_properties_title_entry_delete_text(self, *args):
233 if self._initializing_window:
234 return
235 self._restore_button.set_sensitive(True)
237 def _on_properties_title_entry_focus_out_event(self, widget, *args):
238 self._feed.title = widget.get_text().strip()
240 def _on_properties_location_entry_insert_text(self, *args):
241 if self._initializing_window:
242 return
243 self._restore_button.set_sensitive(True)
245 def _on_properties_location_entry_delete_text(self, *args):
246 if self._initializing_window:
247 return
248 self._restore_button.set_sensitive(True)
250 def _on_properties_location_entry_focus_out_event(self, widget, *args):
251 loc, username, pw = self._feed.access_info
252 self._feed.access_info = (widget.get_text().strip(), username, pw)
254 def _on_properties_username_entry_insert_text(self, *args):
255 if self._initializing_window:
256 return
257 self._restore_button.set_sensitive(True)
259 def _on_properties_username_entry_delete_text(self, *args):
260 if self._initializing_window:
261 return
262 self._restore_button.set_sensitive(False)
264 def _on_properties_username_entry_focus_out_event(self, widget, *args):
265 self._presenter.set_username(widget.get_text().strip())
267 def _on_properties_password_entry_insert_text(self, *args):
268 if self._initializing_window:
269 return
270 self._restore_button.set_sensitive(True)
272 def _on_properties_password_entry_delete_text(self, *args):
273 if self._initializing_window:
274 return
275 self._restore_button.set_sensitive(False)
277 def _on_properties_password_entry_focus_out_event(self, widget, *args):
278 self._presenter.set_password(widget.get_text().strip())
280 def _on_properties_reset_button_clicked(self, *args):
281 self.restore_defaults()
283 def _on_properties_refresh_spin_focus_out_event(self, widget, *args):
284 widget.update()
285 value = widget.get_value_as_int()
286 self._presenter.set_poll_frequency(value)
288 def _on_properties_articles_spin_focus_out_event(self, widget, *args):
289 widget.update()
290 value = widget.get_value_as_int()
291 self._presenter.set_items_stored(value)
293 def _on_properties_articles_spin_value_changed(self, widget, *args):
294 if self._initializing_window:
295 return
296 self._restore_button.set_sensitive(True)
298 def _on_properties_refresh_spin_value_changed(self, widget, *args):
299 if self._initializing_window:
300 return
301 self._restore_button.set_sensitive(True)
303 def _on_properties_keep_refresh_default_toggled(self, widget, *args):
304 if self._initializing_window:
305 return
306 isactive = widget.get_active()
307 if isactive:
308 self._presenter.set_poll_frequency(feeds.Feed.DEFAULT)
309 self._refresh_spin.set_value(float(Config.get_instance().poll_frequency / 60))
310 else:
311 self._presenter.set_poll_frequency(self._refresh_spin.get_value_as_int() * 60)
313 self._refresh_spin.set_sensitive(not isactive)
314 self._restore_button.set_sensitive(True)
316 def _on_properties_keep_articles_default_toggled(self, widget, *args):
317 if self._initializing_window:
318 return
319 isactive = widget.get_active()
320 if isactive:
321 self._presenter.set_items_stored(feeds.Feed.DEFAULT)
322 self._articles_spin.set_value(float(Config.get_instance().number_of_items_stored))
323 else:
324 self._presenter.set_items_stored(self._articles_spin.get_value_as_int())
325 self._articles_spin.set_sensitive(not isactive)
326 self._restore_button.set_sensitive(True)
329 class FeedPropertyPresenter(MVP.BasicPresenter):
331 TIME_INTERVAL = 60
333 def _initialize(self):
334 self._feed = None
335 self._deleter = None
337 def set_deleter(self, deleter):
338 self._deleter = deleter
340 def activate_deleter(self):
341 if self._deleter:
342 self._deleter()
344 def set_feed(self, feed):
345 self._feed = feed
346 self._view.set_feed(self._feed)
348 def set_username(self, username):
349 loc, uname, pw = self._feed.access_info
350 self._feed.access_info = (loc, username, pw)
352 def set_password(self, password):
353 loc, uname, pw = self._feed.access_info
354 self._feed.access_info = (loc, uname, password)
356 def set_poll_frequency(self, pf):
357 if pf != self._feed.poll_frequency:
358 self._feed.poll_frequency = pf * FeedPropertyPresenter.TIME_INTERVAL
360 def set_items_stored(self, nitems):
361 if nitems != self._feed.number_of_items_stored:
362 self._feed.number_of_items_stored = nitems
364 dialogs = {}
365 def show_feed_properties(parent, feed):
366 global dialogs
367 class _dialogdeleter:
368 def __init__(self, feed, hash):
369 self.feed = feed
370 self.hash = hash
372 def __call__(self):
373 del self.hash[feed]
375 dialog = dialogs.get(feed, None)
376 if not dialog:
377 widget_tree = MVP.get_widget_tree('feed_properties')
378 dialog = FeedPropertyPresenter(view=FeedPropertyView(widget_tree))
379 dialog.set_feed(feed)
380 dialog.set_deleter(_dialogdeleter(feed, dialogs))
381 dialogs[feed] = dialog
382 dialog.view.show()
383 return
385 def read_text(fragment, chars):
386 """Read chars cdata characters from html fragment fragment"""
387 parser = SummaryParser.TitleImgParser()
388 parser.feed(fragment)
389 text = parser.get_text(chars)
390 parser.close()
391 return text