fb585f8969e5710942fa4ead5d954a5c3acf15fd
1 from Constants
import *
2 from error
import debug
3 from gobject
import GObject
, SIGNAL_RUN_FIRST
4 from model
import Feed
, Item
, Category
5 from storage
import DAO
, Storage
15 fm
.init_storage(_storage_path
)
17 def setup(storage_path
= None):
19 _storage_path
= storage_path
21 def import_opml(path
, category
):
23 fm
.import_opml(path
, category
)
25 def export_opml(root_id
, filename
):
27 fm
.export_opml(root_id
, filename
)
31 return fm
.lookup_feed(id)
33 def lookup_category(ctg_id
):
35 return fm
.lookup_category(ctg_id
)
41 def update_all_feeds(observers
):
43 return fm
.update_all_feeds(observers
)
45 def is_update_all_running():
47 return fm
.update_all_id
!= None
49 def stop_update_all():
51 return fm
.stop_update_all()
53 def update_nodes(nodes
, observers
= {}):
55 return fm
.update_nodes(nodes
, observers
)
57 def save_category(category
):
59 return fm
.save_category(category
)
63 result
= fm
.save_feed(feed
)
66 def save_all(save_list
):
68 fm
.save_all(save_list
)
74 def get_children_feeds(node_id
):
75 node
= lookup_category(node_id
)
80 return [_node
for _node
in node
.all_children() if _node
.type == "F"]
82 def categories(root_id
= 1):
85 if not nodes
.has_key(root_id
):
90 for node
in nodes
[root_id
].children
:
92 for child
in categories(node
.id):
95 def move_node(node
, target_path
):
97 fm
.move_node(node
, target_path
)
99 def delete_nodes(node_ids
):
101 fm
.delete_nodes(node_ids
)
103 class FeedManager(GObject
):
105 "item-added": (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, (gobject
.TYPE_PYOBJECT
,)),
106 "feed-added": (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, (gobject
.TYPE_PYOBJECT
,)),
107 "feed-status-changed": (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, (gobject
.TYPE_PYOBJECT
,)),
108 "category-added": (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, (gobject
.TYPE_PYOBJECT
,)),
109 "update-all-done": (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, ())
113 GObject
.__init
__(self
)
116 self
.update_all_id
= None
118 def emit(self
, *args
):
119 gobject
.idle_add(gobject
.GObject
.emit
, self
, *args
)
121 def init_storage(self
, path
):
122 self
.storage
= Storage(path
)
123 self
.dao
= DAO(self
.storage
)
124 self
.nodes
= self
.dao
.get_nodes()
126 self
._prepare
_model
()
128 def _prepare_model(self
):
129 for node
in self
.nodes
.values():
130 self
._setup
_node
_signals
(node
)
132 if node
.parent_id
!= None:
133 node
.parent
= self
.nodes
[node
.parent_id
]
134 node
.parent
.append_child(node
)
138 if isinstance(node
, Feed
):
139 self
._set
_feed
_status
(node
, FS_IDLE
)
141 def _setup_node_signals(self
, node
):
142 node
.connect("parent-changed", self
.on_parent_changed
)
143 node
.connect("norder-changed", self
.on_norder_changed
)
145 def _set_feed_status(self
, feed
, status
):
146 if not hasattr(feed
, "status"):
149 if feed
.status
!= status
:
151 self
.emit("feed-status-changed", feed
)
153 def import_opml(self
, path
, category
):
154 # XXX: We should support remote locations for OPML import!
155 url
= "file://" + path
156 opml
.import_opml(url
, category
, [ { "opml-imported": [ self
._on
_opml
_imported
] } ])
158 def _on_opml_imported(self
, handler
, save_list
):
161 self
.save_all(save_list
)
164 def export_opml(self
, root_id
, filename
):
165 if not self
.nodes
.has_key(root_id
):
168 opml
.export(self
.nodes
[root_id
], filename
)
170 def _model_add_node(self
, node
):
171 self
.nodes
[node
.parent_id
].add_child(node
)
173 def move_node(self
, node
, target_path
):
174 debug("fm:move_node %d to %s" % (node
.id, str(target_path
)))
175 new_parent
= self
.nodes
[1].get_by_path(target_path
[:-1])
178 new_parent
= self
.nodes
[1]
181 node
.move(new_parent
, target_path
[-1:][0])
184 def delete_nodes(self
, node_ids
):
192 def delete_node(self
, id):
193 if not self
.nodes
.has_key(id):
196 node
= self
.nodes
[id]
198 children
= list(node
.children
)
201 for child_node
in children
:
202 self
.delete_node(child_node
.id)
204 node
.parent
.remove_child(node
)
208 debug("deleting F %s" % id)
209 self
.dao
.delete_feed(id)
210 elif node
.type == "C":
211 debug("deleting C %s" % id)
212 self
.dao
.delete_category(id)
214 def save_all(self
, save_list
):
215 for item
in save_list
:
216 if isinstance(item
, Feed
):
217 self
._set
_feed
_status
(item
, FS_IDLE
)
221 item
.parent_id
= item
.parent
.id
224 item
.parent
= self
.nodes
[1]
229 item
.parent_id
= item
.parent
.id
232 item
.parent
= self
.nodes
[1]
234 self
.save_category(item
)
236 def lookup_feed(self
, id):
237 return self
.nodes
[id]
239 def lookup_category(self
, id):
240 return self
.nodes
[id]
242 def save_feed(self
, feed
):
243 if not feed
.parent_id
:
246 category
= self
.lookup_category(feed
.parent_id
)
252 result
= self
.dao
.save(feed
)
254 result
= self
.dao
.save(feed
)
255 self
._model
_add
_node
(feed
)
258 self
.nodes
[feed
.id] = feed
260 self
._setup
_node
_signals
(feed
)
261 self
.emit("feed-added", feed
)
265 def update_all_feeds(self
, observers
):
266 feeds
= [node
for node
in self
.nodes
.values() if node
.type == "F"]
268 self
.update_all_id
= FeedUpdater
.update(feeds
, [{
269 "job-done": [ self
._on
_update
_all
_done
],
270 "update-started": [ self
._on
_update
_feed
_start
],
271 "update-done": [ self
._on
_update
_feed
_done
]
274 def update_nodes(self
, nodes
, observers
):
281 feeds
.extend([child_node
for child_node
in node
.all_children() if child_node
.type == "F"])
283 FeedUpdater
.update(feeds
, [{
284 "update-started": [ self
._on
_update
_feed
_start
],
285 "update-done": [ self
._on
_update
_feed
_done
]
288 def stop_update_all(self
):
289 FeedUpdater
.stop(self
.update_all_id
)
291 def _on_update_all_done(self
, handler
, data
):
292 self
.update_all_id
= None
293 self
.emit("update-all-done")
295 def _on_update_feed_start(self
, handler
, feed
):
296 self
._set
_feed
_status
(feed
, FS_UPDATING
)
298 def _on_update_feed_done(self
, handler
, update_result
):
299 feed
= update_result
.feed
301 if update_result
.error
:
302 feed
.update_result
= update_result
303 self
._set
_feed
_status
(feed
, FS_ERROR
)
306 self
._set
_feed
_status
(feed
, FS_IDLE
)
310 # Some metadata could change between the updates.
313 for item
in feed
.items
:
314 item
.feed_id
= feed
.id
316 if not ItemManager
.feed_item_exists(item
):
318 feed
.props
.unread_count
+= 1
319 self
.emit("item-added", item
)
323 def save_category(self
, category
):
324 debug("saving category %s with parent %s" % (category
.name
, str(category
.parent_id
)))
326 if category
.parent
and not category
.parent_id
:
327 category
.parent_id
= category
.parent
.id
331 self
.dao
.save(category
)
332 self
._model
_add
_node
(category
)
333 self
.dao
.save(category
)
337 self
.nodes
[category
.id] = category
339 self
._setup
_node
_signals
(category
)
340 self
.emit("category-added", category
)
342 def on_parent_changed(self
, obj
, old_parent
):
343 #debug("parent changed, saving %d" % (obj.id))
346 def on_norder_changed(self
, obj
, old_norder
):
347 #debug("norder changed, saving %d" % (obj.id))
355 _instance
= FeedManager()