1 from JobManager
import Job
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
18 fm
.init_storage(_storage_path
)
20 def setup(storage_path
= None):
22 _storage_path
= storage_path
24 def import_opml(path
, category
):
26 fm
.import_opml(path
, category
)
28 def export_opml(root_id
, filename
):
30 fm
.export_opml(root_id
, filename
)
32 def lookup_feed(id, ctg_id
):
34 return fm
.lookup_feed(id, ctg_id
)
36 def lookup_category(ctg_id
):
38 return fm
.lookup_category(ctg_id
)
40 def get_feed_items(id):
42 return fm
.get_feed_items(id)
44 def get_category_items(id):
46 return fm
.get_category_items(id)
52 def update_all_feeds(observers
, feeds
= None):
54 return fm
.update_all_feeds(observers
, feeds
)
56 def is_update_all_running():
58 return fm
.update_all_running
60 def save_category(category
):
62 return fm
.save_category(category
)
66 result
= fm
.save_feed(feed
)
69 def save_all(save_list
):
71 fm
.save_all(save_list
)
77 def categories(root_id
= 1):
80 if not nodes
.has_key(root_id
):
85 for node
in nodes
[root_id
].children
:
87 for child
in categories(node
.id):
90 def move_node(node
, target_path
):
92 fm
.move_node(node
, target_path
)
94 def delete_nodes(node_ids
):
96 fm
.delete_nodes(node_ids
)
98 class FeedManager(GObject
):
100 "item-added" : (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, (gobject
.TYPE_PYOBJECT
,)),
101 "feed-added" : (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, (gobject
.TYPE_PYOBJECT
,)),
102 "category-added" : (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, (gobject
.TYPE_PYOBJECT
,)),
103 "update-all-done" : (gobject
.SIGNAL_RUN_LAST
, gobject
.TYPE_NONE
, ())
107 GObject
.__init
__(self
)
110 self
.update_all_running
= False
112 def init_storage(self
, path
):
113 self
.storage
= Storage(path
)
114 self
.dao
= DAO(self
.storage
)
115 self
.nodes
= self
.dao
.get_nodes()
117 self
._prepare
_model
()
119 def _prepare_model(self
):
120 for node
in self
.nodes
.values():
121 self
._setup
_node
_signals
(node
)
123 if node
.parent_id
!= None:
124 node
.parent
= self
.nodes
[node
.parent_id
]
125 node
.parent
.append_child(node
)
129 def _setup_node_signals(self
, node
):
130 node
.connect("parent-changed", self
.on_parent_changed
)
131 node
.connect("norder-changed", self
.on_norder_changed
)
133 def import_opml(self
, path
, category
):
134 job
= Job("opml-parse")
135 job
.data
= (path
, category
)
136 job
.observers
= [ { "job-done": [ self
.import_opml_save
] } ]
138 JobManager
.start_job(job
)
140 def import_opml_save(self
, handler
, opml_data
):
141 save_list
, category
= opml_data
144 self
.save_all(save_list
)
147 def export_opml(self
, root_id
, filename
):
148 if not self
.nodes
.has_key(root_id
):
151 opml
.export(self
.nodes
[root_id
], filename
)
153 def _model_add_node(self
, node
):
154 self
.nodes
[node
.parent_id
].add_child(node
)
156 def move_node(self
, node
, target_path
):
157 debug("fm:move_node %d to %s" % (node
.id, str(target_path
)))
158 new_parent
= self
.nodes
[1].get_by_path(target_path
[:-1])
161 new_parent
= self
.nodes
[1]
163 node
.move(new_parent
, target_path
[-1:][0])
165 def delete_nodes(self
, node_ids
):
173 def delete_node(self
, id):
174 if not self
.nodes
.has_key(id):
177 node
= self
.nodes
[id]
179 children
= list(node
.children
)
182 for child_node
in children
:
183 self
.delete_node(child_node
.id)
185 node
.parent
.remove_child(node
)
189 debug("deleting F %s" % id)
190 self
.dao
.delete_feed(id)
191 elif node
.type == "C":
192 debug("deleting C %s" % id)
193 self
.dao
.delete_category(id)
195 def save_all(self
, save_list
):
196 for item
in save_list
:
197 if isinstance(item
, Feed
):
201 item
.parent_id
= item
.parent
.id
204 item
.parent
= self
.nodes
[1]
209 item
.parent_id
= item
.parent
.id
212 item
.parent
= self
.nodes
[1]
214 self
.save_category(item
)
216 def lookup_feed(self
, id):
217 return self
.nodes
[id]
219 def lookup_category(self
, id):
220 return self
.nodes
[id]
222 def save_feed(self
, feed
):
223 if not feed
.parent_id
:
226 category
= self
.lookup_category(feed
.parent_id
)
231 result
= self
.dao
.save(feed
)
233 self
.nodes
[feed
.id] = feed
234 self
._model
_add
_node
(feed
)
235 self
._setup
_node
_signals
(feed
)
236 self
.emit("feed-added", feed
)
240 def update_all_feeds(self
, observers
, feeds
= None):
242 feeds
= [node
for node
in self
.nodes
.values() if node
.type == "F"]
244 self
.update_all_running
= True
246 FeedUpdater
.update_feeds(feeds
, [{
247 "job-done": [ self
._on
_update
_all
_done
],
248 "task-start": [ self
._on
_update
_feed
_start
],
249 "task-done": [ self
._on
_update
_feed
_done
]
252 def _on_update_all_done(self
, handler
, data
):
253 self
.update_all_running
= False
254 self
.emit("update-all-done")
256 def _on_update_feed_start(self
, handler
, feed
):
257 feed
.props
.status
= straw
.FS_UPDATING
259 def _on_update_feed_done(self
, handler
, data
):
260 feed
= data
.task_info
.data
["feed"]
261 feed
.props
.status
= straw
.FS_IDLE
268 for item
in data
.result
.items
:
269 item
.feed_id
= feed
.id
271 if not self
.feed_item_exists(item
):
273 feed
.props
.unread_count
+= 1
274 self
.emit("item-added", item
)
280 def save_category(self
, category
):
281 debug("saving category %s with parent %s" % (category
.name
, str(category
.parent_id
)))
283 if category
.parent
and not category
.parent_id
:
284 category
.parent_id
= category
.parent
.id
288 self
.dao
.save(category
)
289 self
._model
_add
_node
(category
)
290 self
.dao
.save(category
)
294 self
.nodes
[category
.id] = category
296 self
._setup
_node
_signals
(category
)
297 self
.emit("category-added", category
)
299 def get_feed_items(self
, id):
300 feed
= self
.lookup_feed(id)
301 feed
.items
= self
.dao
.get(Item
, " WHERE feed_id = %d" % feed
.id)
302 for item
in feed
.items
:
304 item
.connect("is-read-changed", feed
.on_is_read_changed
)
305 item
.connect("is-read-changed", self
.on_item_is_read_changed
)
308 def get_category_items(self
, id):
309 category
= self
.lookup_category(id)
314 def _get_children_feeds(category_id
):
315 feed_ids
= [str(node
.id) for node
in self
.lookup_category(category_id
).children
if node
.type == "F"]
316 children_categories
= [node
.id for node
in self
.lookup_category(category_id
).children
if node
.type == "C"]
318 for ctg_id
in children_categories
:
319 feed_ids
.extend(_get_children_feeds(ctg_id
))
323 in_str
= ", ".join(_get_children_feeds(id))
325 items
= self
.dao
.get(Item
, " WHERE feed_id IN(%s) ORDER BY id" % in_str
)
328 feed
= self
.lookup_feed(item
.feed_id
)
330 item
.connect("is-read-changed", feed
.on_is_read_changed
)
331 item
.connect("is-read-changed", self
.on_item_is_read_changed
)
335 def feed_item_exists(self
, item
):
336 result
= self
.dao
.get(Item
, " WHERE feed_id = ? AND title = ?", (item
.feed_id
, item
.title
,))
337 return len(result
) > 0
339 def on_item_is_read_changed(self
, obj
, is_read
):
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()