3 Module for handling feed subscription process.
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
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 from gtk
.glade
import XML
45 class SubscribeView(MVP
.GladeView
):
46 def _initialize(self
):
47 self
._window
= self
._widget
.get_widget('subscribe_dialog')
48 self
._button
1 = self
._widget
.get_widget('button1')
49 self
._button
2 = self
._widget
.get_widget('button2')
50 self
._button
3 = self
._widget
.get_widget('button3')
51 self
._progress
_bar
= self
._widget
.get_widget('progress_bar')
52 self
._notebook
= self
._widget
.get_widget('notebook')
53 self
._location
_entry
= self
._widget
.get_widget('feed_location_entry')
54 self
._username
_entry
= self
._widget
.get_widget('username_entry')
55 self
._password
_entry
= self
._widget
.get_widget('password_entry')
56 self
._category
_tree
= self
._widget
.get_widget('category_tree')
57 self
._error
_text
= self
._widget
.get_widget('error_text')
58 self
._error
_box
= self
._widget
.get_widget('error_box')
59 self
._result
_tree
= self
._widget
.get_widget('result_tree')
61 self
.category_pixbuf
= gtk
.Label().render_icon(gtk
.STOCK_DIRECTORY
, gtk
.ICON_SIZE_MENU
)
63 def _populate_tree(self
, parent_id
, parent
= None):
64 if not self
.nodes
.has_key(parent_id
):
67 for node
in self
.nodes
[parent_id
].children
:
69 treeiter
= self
.category_store
.append(parent
, [self
.category_pixbuf
, helpers
.pango_escape(node
.name
), node
])
71 if self
.nodes
.has_key(node
.id):
72 self
._populate
_tree
(node
.id, treeiter
)
74 def _on_forward(self
):
75 location
= self
._location
_entry
.get_text()
77 self
.display_error(_("Feed Location must not be empty"))
79 #location = "file:///home/ppawel/Desktop/test.rss"
80 username
= self
._username
_entry
.get_text()
81 username
= username
.strip()
82 password
= self
._password
_entry
.get_text()
83 password
= password
.strip()
85 config
= Config
.get_instance()
88 response
= helpers
.report_offline_status(self
._window
)
89 if response
== gtk
.RESPONSE_CANCEL
:
92 config
.offline
= not config
.offline
95 FeedDiscovery
.discover(location
, [ { "job-done": [ self
._discovery
_finished
] } ])
97 #self._presenter.subscribe(location, username, password)
100 def progress_pulse(self
, obj
):
101 self
._progress
_bar
.pulse()
104 def progress_destroy(self
):
106 gobject
.source_remove(self
.timer
)
109 def _setup_entries(self
):
110 self
._location
_entry
.set_text("http://")
111 self
._username
_entry
.delete_text(0,-1)
112 self
._password
_entry
.delete_text(0,-1)
114 self
._location
_entry
.grab_focus()
117 self
.state
= STATE_INTRO
118 self
.set_state(gtk
.STOCK_CLOSE
, gtk
.STOCK_GO_FORWARD
, None)
121 self
._setup
_entries
()
122 self
._error
_box
.set_property('visible',False)
123 self
._notebook
.set_current_page(0)
126 self
.store
= gtk
.ListStore(bool, str, gobject
.TYPE_PYOBJECT
)
128 renderer
= gtk
.CellRendererToggle()
129 renderer
.set_property("activatable", True)
130 column
= gtk
.TreeViewColumn(_('Keep'), renderer
, active
= 0)
131 renderer
.connect('toggled', self
.col1_toggled_cb
, self
.store
)
132 self
._result
_tree
.append_column(column
)
134 renderer2
= gtk
.CellRendererText()
135 column
= gtk
.TreeViewColumn(_('_Title'), renderer2
, markup
= 1)
137 self
._result
_tree
.append_column(column
)
138 self
._result
_tree
.set_model(self
.store
)
140 column
= gtk
.TreeViewColumn()
142 status_renderer
= gtk
.CellRendererPixbuf()
143 column
.pack_start(status_renderer
, False)
144 column
.set_attributes(status_renderer
, pixbuf
= 0)
146 title_renderer
= gtk
.CellRendererText()
147 column
.pack_start(title_renderer
, False)
148 column
.set_attributes(title_renderer
, markup
= 1)
150 self
._category
_tree
.append_column(column
)
152 def col1_toggled_cb(self
, cell
, path
, model
):
153 self
.store
[path
][0] = not self
.store
[path
][0]
155 # Enable "Apply" button when at least one discovered feed is selected.
157 self
._button
3.set_sensitive(bool(sum([feed
[0] for feed
in self
.store
])))
159 def setup_category_tree(self
):
160 self
.category_store
= gtk
.TreeStore(gtk
.gdk
.Pixbuf
, str, gobject
.TYPE_PYOBJECT
)
161 self
.nodes
= FeedManager
.get_model()
163 self
._category
_tree
.set_model(None)
164 self
._category
_tree
.set_model(self
.category_store
)
166 treeiter
= self
.category_store
.append(None, [self
.category_pixbuf
, "Main category", None])
168 self
._populate
_tree
(1, parent
= treeiter
)
169 self
._category
_tree
.expand_all()
171 selection
= self
._category
_tree
.get_selection()
172 selection
.select_path("0")
174 def display_error(self
, text
):
175 self
._error
_box
.set_property('visible',True)
176 self
._error
_text
.set_text(text
)
178 def set_location_entry(self
, location
):
179 self
._location
_entry
.set_text(location
)
181 def set_parent(self
, parent
):
182 self
._window
.set_transient_for(parent
)
184 def _on_button1_clicked(self
, *args
):
185 self
.progress_destroy()
188 def _on_button2_clicked(self
, *args
):
189 if self
.state
== STATE_INTRO
:
190 if self
._on
_forward
():
191 self
._progress
_bar
.props
.visible
= True
192 self
.timer
= gobject
.timeout_add(100, self
.progress_pulse
, self
)
193 self
._button
2.set_sensitive(False)
194 elif self
.state
== STATE_FINISH
:
195 self
.state
= STATE_INTRO
196 self
.set_state(gtk
.STOCK_CLOSE
, gtk
.STOCK_GO_FORWARD
, None)
197 self
._notebook
.set_current_page(0)
199 def _on_button3_clicked(self
, *args
):
200 if self
.state
== STATE_FINISH
:
203 # Obtain selected category.
206 iter = self
._category
_tree
.get_selection().get_selected()[1]
209 path
= self
.category_store
.get_path(iter)
210 parent
= self
.category_store
[path
][2]
212 # Save selected feeds.
214 for feed
in [row
[2] for row
in self
.store
if row
[0]]:
216 new_feeds
.append(feed
)
218 FeedManager
.save_all(new_feeds
)
222 def _discovery_finished(self
, handler
, feeds
):
223 gtk
.gdk
.threads_enter()
226 label
= helpers
.pango_escape(feed
.title
) + '\n<span size="smaller">' + xml
.sax
.saxutils
.escape(feed
.location
) + '</span>'
227 self
.store
.append([None, label
, feed
])
229 self
._progress
_bar
.props
.visible
= False
230 self
._button
2.set_sensitive(True)
231 self
._button
3.set_sensitive(False)
232 self
.progress_destroy()
233 self
.state
= STATE_FINISH
234 self
.set_state(gtk
.STOCK_CLOSE
, gtk
.STOCK_GO_BACK
, gtk
.STOCK_APPLY
)
235 self
._notebook
.set_current_page(1)
237 self
.setup_category_tree()
239 gtk
.gdk
.threads_leave()
241 def set_state(self
, b1
, b2
, b3
):
245 self
._button
1.set_label(b1
)
251 self
._button
2.set_label(b2
)
257 self
._button
3.set_label(b3
)
260 def _on_feed_location_entry_key_press_event(self
, widget
, event
):
261 if event
.keyval
== gtk
.keysyms
.Return
:
262 self
._presenter
.subscribe(self
._location
_entry
.get_text())
264 class SubscribePresenter(MVP
.BasicPresenter
):
266 def _normalize(self
, url
):
267 u
= urlparse
.urlsplit(url
.strip())
268 # we check if 'scheme' is not empty here because URIs like
269 # "google.com" IS valid but, in this case, 'scheme' is empty because
270 # urlsplit() expects urls are in the format of scheme://netloc/...
271 if not u
[0] or (u
[0] != "http" and u
[0] != "feed"):
274 u
= urlparse
.urlsplit(u
[2])
275 # .. if that happens then we munge the url by adding a // and assume
276 # that 'http' is the scheme.
278 u
= urlparse
.urlsplit("//" + url
, 'http')
281 def subscribe(self
, location
, username
=None, password
=None):
282 self
._username
= username
283 self
._password
= password
284 self
._location
= location
290 feed
.location
= location
291 feed
.title
= location
292 FeedManager
.save_feed(feed
)
294 def set_parent(self
, parent
):
295 self
.view
.set_parent(parent
)
297 def get_credential(self
):
298 return (self
._location
, self
._username
, self
._password
)
300 def show(self
, url
=None):
302 self
.view
.set_location_entry(url
)
305 # def set_url_dnd(self, url):
306 # self._window.show()
307 # self._feed_location_presenter.view.find_feed(url)
309 def set_location_from_clipboard(self
):
310 def _clipboard_cb(cboard
, url
, data
=None):
312 url
= self
._normalize
(url
)
313 if url
and url
[0] == "http":
314 url
= urlparse
.urlunsplit(url
)
315 self
.view
.set_location_entry(url
)
316 clipboard
= gtk
.clipboard_get(selection
="CLIPBOARD")
317 clipboard
.request_text(_clipboard_cb
, None)
319 def subscribe_show(url
=None, parent
=None):
320 gladefile
= XML(os
.path
.join(straw
.STRAW_DATA_DIR
, "subscribe.glade"))
321 _dialog
= SubscribePresenter(view
=SubscribeView(gladefile
))
322 _dialog
.set_parent(parent
)
323 _dialog
.set_location_from_clipboard()