3 Straw module for handling items that belongs to a feed. This modules is
4 responsible for adding,cutting, and deleting items of the current feed.
6 __copyright__
= "Copyright (c) 2002-2005 Free Software Foundation, Inc."
7 __license__
= """GNU General Public License
9 This program is free software; you can redistribute it and/or modify it under the
10 terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 2 of the License, or (at your option) any later
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along with
19 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 Place - Suite 330, Boston, MA 02111-1307, USA. """
31 class FeedItems(object):
32 def __init__(self
, feed
):
34 self
._items
= QueueDict
.ItemQueue()
36 config
= Config
.get_instance()
37 config
.signal_connect(Event
.ItemOrderChangedSignal
, self
.item_order_changed
)
38 config
.signal_connect(Event
.NumberOfItemsStoredChangedSignal
, self
.items_stored_changed
)
40 def _init_items(self
):
41 config
= Config
.get_instance()
43 self
._items
.sort_order
= config
.item_order
44 self
._prefs
_items
_stored
= config
.number_of_items_stored
46 self
._number
_of
_items
= None
51 def number_of_unread():
54 return self
._feed
.n_items_unread
56 self
._feed
.n_items_unread
= n
57 return property(**locals())
60 def number_of_items():
63 if self
._number
_of
_items
:
64 return self
._number
_of
_items
66 error
.log("was loaded but number_of_items was None!")
69 self
._number
_of
_items
= n
70 return property(**locals())
72 def item_order_changed(self
, event
):
73 self
._items
.sort_order
= event
.sender
.item_order
74 self
._feed
.signal_refresh_display()
76 def items_stored_changed(self
, event
):
77 self
._prefs
_items
_stored
= event
.sender
.number_of_items_stored
78 self
._feed
.signal_refresh_display()
80 def add_items(self
, new_items
):
81 cutpoint
= self
._get
_cutpoint
()
82 items
= sorted(new_items
, cmp=self
._cmp
)
85 for x
, item
in enumerate(items
):
86 if item
in self
._items
:
91 item
.feed
= self
._feed
92 if self
._number
_of
_items
< cutpoint
:
93 self
._items
.append(item
)
95 # no point on increasing the number of items here since it's
96 # already over the cutpoint
97 ritem
= self
._items
.replace(item
)
98 removed_items
.append(ritem
)
100 item
.signal_connect(Event
.ItemReadSignal
, self
.item_read
)
101 item
.signal_connect(Event
.ItemStickySignal
, self
._feed
.forward_signal
)
102 self
._idseq
= max(self
._items
.keys())
103 self
.number_of_unread
= len([i
for i
in self
._items
.itervalues() if not i
.seen
])
104 self
.number_of_items
= len(self
._items
)
107 self
._feed
.signal_deleted_item(removed_items
)
109 self
._feed
.signal_new_items(newitems
)
110 self
._feed
.signal_refresh_display()
112 def restore_items(self
, items
):
114 Restores the given items in an ordered form
116 # should we check for duplicates here? Or should that be done
117 # when new items arrive?
120 items
= self
._sort
(items
)
122 cutpoint
= self
._get
_cutpoint
()
123 for x
,item
in enumerate(items
):
124 item
.feed
= self
._feed
125 if item
.sticky
or x
<= cutpoint
:
126 item
.signal_connect(Event
.ItemReadSignal
, self
.item_read
)
127 item
.signal_connect(Event
.ItemStickySignal
, self
._feed
.forward_signal
)
128 self
._items
.append(item
)
131 no_restore
.append(item
)
132 self
._idseq
= max(self
._items
.keys())
133 self
.number_of_unread
= len([i
for i
in self
._items
.itervalues() if not i
.seen
])
134 self
.number_of_items
= len(self
._items
)
136 self
._feed
.signal_deleted_item(no_restore
)
138 def _disconnect_item_signals(self
, item
):
139 item
.signal_disconnect(Event
.ItemReadSignal
, self
.item_read
)
140 item
.signal_disconnect(Event
.ItemStickySignal
, self
._feed
.forward_signal
)
142 def item_read(self
, signal
):
143 if signal
.sender
.seen
:
147 self
.number_of_unread
= self
.number_of_unread
+ change
148 self
._feed
.forward_signal(signal
)
153 return self
._items
.values()
155 def get_item_index(self
, item
):
158 idx
= self
._items
.index(item
.id)
161 def mark_all_read(self
):
164 keys
= self
._items
.keys()
165 changed
= [(keys
.index(key
), value
) for key
, value
in self
._items
if value
.set_seen_quiet()]
166 self
.number_of_unread
= 0
167 self
._feed
.signal_all_items_read(changed
)
172 Loads and restores the items from the data store
177 itemstore
= ItemStore
.get_instance()
178 items
= itemstore
.read_feed_items(self
._feed
)
180 #error.log("load ", self._feed.title, ", number of items: ", len(items), ", number of unread before restore: ", self.number_of_unread)
181 self
.restore_items(items
)
184 #print "No items, not loading ", self._feed.title
190 Unloads the items by disconnecting the signals and reinitialising the
193 TODO: unload seems to lose some circular references. garbage collector
194 will find them, though, so maybe it's not a problem.
198 for key
, item
in self
._items
:
199 self
._disconnect
_item
_signals
(item
)
202 def _get_cutpoint(self
):
204 Returns the current cutpoint
207 if self
._feed
.number_of_items_stored
== Feed
.Feed
.DEFAULT
:
208 cutpoint
= self
._prefs
_items
_stored
210 cutpoint
= self
._feed
.number_of_items_stored
213 def _sort(self
, items
):
215 Sorts the given items according to the sort order
217 items
.sort(self
._cmp
)
218 if self
._items
.sort_order
:
222 def _cmp(self
, a
, b
):
224 Comparator method to compare items based on the item's pub_date attribute
226 If an item doesn't have a pub_date, it uses title and prioritizes the
230 return cmp(a
.pub_date
, b
.pub_date
)
231 except AttributeError:
232 return locale
.strcoll(a
.title
, b
.title
) and not a
.seen
or not b
.seen