feed list view and feed/category event handling fixes
[straw.git] / src / lib / Event.py
blob5d6745b72d3a480ba393e8653241d089839e7acf
1 """ Event.py
3 Module for dispatching Straw-related events.
4 """
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
11 version.
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. """
21 import traceback
22 import sys
23 import error
26 _base_cache = dict()
28 def find_bases(klass):
29 def _find_bases(klass, d = None):
30 if d is None:
31 d = dict()
32 for b in klass.__bases__:
33 if issubclass(b, BaseSignal):
34 d[b] = 1
35 _find_bases(b, d)
36 return tuple(d.keys())
37 bases = _base_cache.get(klass, None)
38 if bases is not None:
39 return bases
40 bases = _find_bases(klass)
41 _base_cache[klass] = bases
42 return bases
44 class BaseSignal:
45 def __init__(self, sender):
46 self.sender = sender
47 return
49 class SignalEmitter:
50 recorder = None
52 """Base class for signal emitters"""
53 def __init__(self):
54 self._slots = dict()
56 def initialize_slots(self, *signals):
57 """Initialize signal slots.
58 signals should be a list of signals this emitter is going to send."""
59 for s in signals:
60 self._slots[s] = dict()
61 bs = find_bases(s)
62 for k in bs:
63 self._slots[k] = dict()
65 def signal_connect(self, signal, handler, data=None):
66 """Connect a handler to a signal in this emitter, and associate
67 data with the callback. This will override previous bindings of
68 signal to handler."""
69 self._slots[signal][handler] = data
70 return
72 def signal_disconnect(self, signal, handler):
73 """Disconnect handler from signal."""
74 self._slots[signal][handler] = None
75 del self._slots[signal][handler]
76 return
78 def emit_signal(self, signal):
79 """Emit a signal object. Signal should be an instance of BaseSignal or
80 a subclass."""
81 global filterpy
82 sclasses = find_bases(signal.__class__)
83 for sc in sclasses + (signal.__class__,):
84 for handler, data in self._slots.get(sc, {}).items():
85 if data is not None:
86 args = (signal, data)
87 else:
88 args = (signal,)
89 try:
90 #if self.recorder is not None:
91 # self.recorder.record(sc, handler)
92 apply(handler, args)
93 except:
94 error.log_exc("Caught an exception when trying to "
95 "call a signal handler for "
96 "signal %s\n" %
97 str(signal))
98 traceback.print_exc()
101 def start_recording(klass, recorder):
102 klass.recorder = recorder
103 start_recording = classmethod(start_recording)
105 def stop_recording(klass):
106 if klass.recorder is not None:
107 klass.recorder.stop()
108 klass.recorder = None
109 stop_recording = classmethod(stop_recording)
112 # Feed creation and feed list management events
114 class FeedsChangedSignal(BaseSignal):
115 def __init__(self, sender, feed=None):
116 BaseSignal.__init__(self, sender)
117 self.feed = feed
119 class FeedsEmptySignal(BaseSignal):
120 pass
122 class FeedsImportedSignal(FeedsChangedSignal):
124 A signal for importing huge amount of feeds from OPML.
126 def __init__(self, sender, feeds,
127 parent=None, from_sub=False):
128 FeedsChangedSignal.__init__(self, sender)
129 self.feeds = feeds
130 self.category = parent
131 self.from_sub = from_sub
133 class FeedDeletedSignal(FeedsChangedSignal):
134 def __init__(self, sender, feed):
135 FeedsChangedSignal.__init__(self, sender, feed)
136 self.feed = feed
138 class FeedCreatedSignal(FeedsChangedSignal):
139 def __init__(self, sender, feed, category=None, index=None):
140 FeedsChangedSignal.__init__(self, sender)
141 self.feed = feed
142 self.category = category
143 self.index = index
145 # Feed detail Specific
146 class FeedDetailChangedSignal(BaseSignal):
147 def __init__(self, sender):
148 BaseSignal.__init__(self, sender)
150 class ItemOrderChangedSignal(FeedDetailChangedSignal):
151 pass
153 class FeedPollFrequencyChangedSignal(FeedDetailChangedSignal):
154 def __init__(self, sender):
155 BaseSignal.__init__(self, sender)
157 class FeedNumOfItemsStoredChangedSignal(FeedDetailChangedSignal):
158 def __init__(self, sender):
159 BaseSignal.__init__(self, sender)
161 class FeedErrorStatusChangedSignal(FeedDetailChangedSignal):
162 pass
164 class FeedInfoUpdatedSignal(FeedDetailChangedSignal):
166 Feed information like title, description, copyright, etc...
168 def __init__(self, sender):
169 BaseSignal.__init__(self, sender)
171 class FeedUnreadChangedSignal(FeedDetailChangedSignal):
172 def __init__(self, sender):
173 BaseSignal.__init__(self, sender)
176 # Feed category specific
178 class FeedCategoriesChangedSignal(BaseSignal):
179 pass
181 class FeedCategoryListChangedSignal(FeedCategoriesChangedSignal):
182 pass
184 class FeedCategoryListLoadedSignal(FeedCategoriesChangedSignal):
185 pass
187 class FeedCategoryAddedSignal(FeedCategoryListChangedSignal):
188 def __init__(self, sender, category):
189 FeedCategoryListChangedSignal.__init__(self, sender)
190 self.category = category
192 class FeedCategoryRemovedSignal(FeedCategoryListChangedSignal):
193 def __init__(self, sender, category):
194 FeedCategoryListChangedSignal.__init__(self, sender)
195 self.category = category
197 class FeedCategoryChangedSignal(FeedCategoriesChangedSignal):
198 """ Called when a Feed Category was modified (i.e. feed added, feed
199 removed, category title changed, etc...
201 def __init__(self, sender, feed=None):
202 FeedCategoriesChangedSignal.__init__(self, sender)
203 self.feed = feed
205 class FeedCategorySortedSignal(FeedCategoryChangedSignal):
206 """ Called when a Feed Category has been sorted. """
207 def __init__(self, sender, reverse=False):
208 FeedCategoryChangedSignal.__init__(self, sender)
209 self.descending = reverse
211 class SubscriptionContentsUpdatedSignal(BaseSignal):
212 pass
214 # Item specific
215 class ItemsAddedSignal(BaseSignal):
216 def __init__(self, sender, items):
217 BaseSignal.__init__(self, sender)
218 self.items = items
220 class ItemDeletedSignal(BaseSignal):
221 def __init__(self, sender, item):
222 BaseSignal.__init__(self, sender)
223 self.item = item
225 class NewItemsSignal(BaseSignal):
226 def __init__(self, sender, items):
227 BaseSignal.__init__(self, sender)
228 self.items = items
230 class ItemStickySignal(BaseSignal):
231 def __init__(self, sender, item=None):
232 BaseSignal.__init__(self, sender)
233 if item is None:
234 item = sender
235 self.item = item
237 class AllItemsReadSignal(BaseSignal):
238 def __init__(self, sender, changed):
239 BaseSignal.__init__(self, sender)
240 self.changed = changed
243 # Other events ...
245 class FeedLastPollChangedSignal(BaseSignal):
246 pass
248 class PollChangedSignal(BaseSignal):
249 def __init__(self, sender):
250 BaseSignal.__init__(self, sender)
252 class FeedPolledSignal(BaseSignal):
253 pass
255 class FeedStatusChangedSignal(BaseSignal):
257 Provides a signal for denoting that the polling process
258 has begun or finished.
260 pass
262 class ImageUpdatedSignal(BaseSignal):
263 def __init__(self, sender, url, data):
264 BaseSignal.__init__(self, sender)
265 self.url = url
266 self.data = data
268 class NumberOfItemsStoredChangedSignal(BaseSignal):
269 pass
271 class PollFrequencyChangedSignal(PollChangedSignal):
272 """ Global poll frequency """
273 def __init__(self, sender, value):
274 PollChangedSignal.__init__(self, sender)
275 self.value = value
277 class PollingStoppedSignal(BaseSignal):
278 pass
280 class FeedSelectionChangedSignal(BaseSignal):
282 Emitted when a feed has been selected in the feeds tree view.
284 def __init__(self, sender, old, new):
285 BaseSignal.__init__(self, sender)
286 self.old = old
287 self.new = new
289 class ItemSelectionChangedSignal(BaseSignal):
290 """ Called when an item has been selected in the item list.
291 Normally this should display the content of the item
293 def __init__(self, sender, item):
294 BaseSignal.__init__(self, sender)
295 self.item = item
297 class ItemReadSignal(BaseSignal):
298 """ Called when an item's 'seen' property has been changed
299 (i.e. marked as read)
301 def __init__(self, sender, item=None):
302 BaseSignal.__init__(self, sender)
303 if item is None:
304 item = sender
305 self.item = item
307 class CategorySelectionChangedSignal(BaseSignal):
309 Emitted when a the user changes categories
311 def __init__(self, sender, newcat):
312 BaseSignal.__init__(self, sender)
313 self.current = newcat
315 class OfflineModeChangedSignal(BaseSignal):
316 pass
318 class RefreshFeedDisplaySignal(BaseSignal):
319 pass
321 class StatusDisplaySignal(BaseSignal):
322 pass
324 class FindInterruptSignal(BaseSignal):
325 pass
328 if __name__ == '__main__':
329 print find_bases(ItemReadSignal)