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
23 from straw
import helpers
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
, 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
)
133 #renderer.connect('toggled', self._sticky_toggled)
135 renderer2
= gtk
.CellRendererText()
136 column
= gtk
.TreeViewColumn(_('_Title'), renderer2
, markup
= 1)
138 self
._result
_tree
.append_column(column
)
139 self
._result
_tree
.set_model(self
.store
)
141 column
= gtk
.TreeViewColumn()
143 status_renderer
= gtk
.CellRendererPixbuf()
144 column
.pack_start(status_renderer
, False)
145 column
.set_attributes(status_renderer
, pixbuf
= 0)
147 title_renderer
= gtk
.CellRendererText()
148 column
.pack_start(title_renderer
, False)
149 column
.set_attributes(title_renderer
, markup
= 1)
151 self
._category
_tree
.append_column(column
)
153 def col1_toggled_cb( self
, cell
, path
, model
):
154 self
.store
[path
][0] = not self
.store
[path
][0]
156 def setup_category_tree(self
):
157 self
.category_store
= gtk
.TreeStore(gtk
.gdk
.Pixbuf
, str, gobject
.TYPE_PYOBJECT
)
158 self
.nodes
= FeedManager
.get_model()
160 self
._category
_tree
.set_model(None)
161 self
._category
_tree
.set_model(self
.category_store
)
163 treeiter
= self
.category_store
.append(None, [self
.category_pixbuf
, "Main category", None])
165 self
._populate
_tree
(1, parent
= treeiter
)
166 self
._category
_tree
.expand_all()
168 def display_error(self
, text
):
169 self
._error
_box
.set_property('visible',True)
170 self
._error
_text
.set_text(text
)
172 def set_location_entry(self
, location
):
173 self
._location
_entry
.set_text(location
)
175 def set_parent(self
, parent
):
176 self
._window
.set_transient_for(parent
)
178 def _on_button1_clicked(self
, *args
):
179 self
.progress_destroy()
182 def _on_button2_clicked(self
, *args
):
183 if self
.state
== STATE_INTRO
:
184 if self
._on
_forward
():
185 self
._progress
_bar
.props
.visible
= True
186 self
.timer
= gobject
.timeout_add(100, self
.progress_pulse
, self
)
187 self
._button
2.set_sensitive(False)
188 elif self
.state
== STATE_FINISH
:
189 self
.state
= STATE_INTRO
190 self
.set_state(gtk
.STOCK_CLOSE
, gtk
.STOCK_GO_FORWARD
, None)
191 self
._notebook
.set_current_page(0)
193 def _on_button3_clicked(self
, *args
):
194 if self
.state
== STATE_FINISH
:
197 # Obtain selected category.
200 iter = self
._category
_tree
.get_selection().get_selected()[1]
203 path
= self
.category_store
.get_path(iter)
204 parent
= self
.category_store
[path
][2]
206 # Save selected feeds.
208 for feed
in [row
[2] for row
in self
.store
if row
[0]]:
210 new_feeds
.append(feed
)
212 FeedManager
.save_all(new_feeds
)
216 def _discovery_finished(self
, handler
, feeds
):
217 gtk
.gdk
.threads_enter()
220 label
= xml
.sax
.saxutils
.escape(feed
.title
) + '\n<span size="smaller">' + xml
.sax
.saxutils
.escape(feed
.location
) + '</span>'
221 self
.store
.append([None, label
, feed
])
223 self
._progress
_bar
.props
.visible
= False
224 self
._button
2.set_sensitive(True)
225 self
.progress_destroy()
226 self
.state
= STATE_FINISH
227 self
.set_state(gtk
.STOCK_CLOSE
, gtk
.STOCK_GO_BACK
, gtk
.STOCK_APPLY
)
228 self
._notebook
.set_current_page(1)
230 self
.setup_category_tree()
232 gtk
.gdk
.threads_leave()
234 def set_state(self
, b1
, b2
, b3
):
238 self
._button
1.set_label(b1
)
244 self
._button
2.set_label(b2
)
250 self
._button
3.set_label(b3
)
253 def _on_feed_location_entry_key_press_event(self
, widget
, event
):
254 if event
.keyval
== gtk
.keysyms
.Return
:
255 self
._presenter
.subscribe(self
._location
_entry
.get_text())
257 class SubscribePresenter(MVP
.BasicPresenter
):
259 def _normalize(self
, url
):
260 u
= urlparse
.urlsplit(url
.strip())
261 # we check if 'scheme' is not empty here because URIs like
262 # "google.com" IS valid but, in this case, 'scheme' is empty because
263 # urlsplit() expects urls are in the format of scheme://netloc/...
264 if not u
[0] or (u
[0] != "http" and u
[0] != "feed"):
267 u
= urlparse
.urlsplit(u
[2])
268 # .. if that happens then we munge the url by adding a // and assume
269 # that 'http' is the scheme.
271 u
= urlparse
.urlsplit("//" + url
, 'http')
274 def subscribe(self
, location
, username
=None, password
=None):
275 self
._username
= username
276 self
._password
= password
277 self
._location
= location
283 feed
.location
= location
284 feed
.title
= location
285 FeedManager
.save_feed(feed
)
287 def set_parent(self
, parent
):
288 self
.view
.set_parent(parent
)
290 def get_credential(self
):
291 return (self
._location
, self
._username
, self
._password
)
293 def show(self
, url
=None):
295 self
.view
.set_location_entry(url
)
298 # def set_url_dnd(self, url):
299 # self._window.show()
300 # self._feed_location_presenter.view.find_feed(url)
302 def set_location_from_clipboard(self
):
303 def _clipboard_cb(cboard
, url
, data
=None):
305 url
= self
._normalize
(url
)
306 if url
and url
[0] == "http":
307 url
= urlparse
.urlunsplit(url
)
308 self
.view
.set_location_entry(url
)
309 clipboard
= gtk
.clipboard_get(selection
="CLIPBOARD")
310 clipboard
.request_text(_clipboard_cb
, None)
312 def subscribe_show(url
=None, parent
=None):
313 gladefile
= XML(os
.path
.join(straw
.STRAW_DATA_DIR
, "subscribe.glade"))
314 _dialog
= SubscribePresenter(view
=SubscribeView(gladefile
))
315 _dialog
.set_parent(parent
)
316 _dialog
.set_location_from_clipboard()