pre gobject: 3-pane view, callgraph, feed navigation
[straw.git] / src / lib / Event.py
blobb62da66778179f8edc7c77a95d67655952d7ed6d
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 import pycallgraph
50 filterpy = pycallgraph.GlobbingFilter(exclude=['pycallgraph.*','*.emit_signal'])
52 class SignalEmitter:
53 recorder = None
55 """Base class for signal emitters"""
56 def __init__(self):
57 self._slots = dict()
59 def initialize_slots(self, *signals):
60 """Initialize signal slots.
61 signals should be a list of signals this emitter is going to send."""
62 for s in signals:
63 self._slots[s] = dict()
64 bs = find_bases(s)
65 for k in bs:
66 self._slots[k] = dict()
68 def signal_connect(self, signal, handler, data=None):
69 """Connect a handler to a signal in this emitter, and associate
70 data with the callback. This will override previous bindings of
71 signal to handler."""
72 self._slots[signal][handler] = data
73 return
75 def signal_disconnect(self, signal, handler):
76 """Disconnect handler from signal."""
77 self._slots[signal][handler] = None
78 del self._slots[signal][handler]
79 return
81 def emit_signal(self, signal):
82 """Emit a signal object. Signal should be an instance of BaseSignal or
83 a subclass."""
84 global filterpy
85 sclasses = find_bases(signal.__class__)
86 for sc in sclasses + (signal.__class__,):
87 for handler, data in self._slots.get(sc, {}).items():
88 if data is not None:
89 args = (signal, data)
90 else:
91 args = (signal,)
92 try:
93 #if self.recorder is not None:
94 # self.recorder.record(sc, handler)
95 pycallgraph.start_trace(filter=filterpy)
96 apply(handler, args)
97 pycallgraph.stop_trace()
98 pycallgraph.make_dot_graph('event.png')
99 except:
100 error.log_exc("Caught an exception when trying to "
101 "call a signal handler for "
102 "signal %s\n" %
103 str(signal))
104 traceback.print_exc()
107 def start_recording(klass, recorder):
108 klass.recorder = recorder
109 start_recording = classmethod(start_recording)
111 def stop_recording(klass):
112 if klass.recorder is not None:
113 klass.recorder.stop()
114 klass.recorder = None
115 stop_recording = classmethod(stop_recording)
118 # Feed creation and feed list management events
120 class FeedsChangedSignal(BaseSignal):
121 def __init__(self, sender, feed=None):
122 BaseSignal.__init__(self, sender)
123 self.feed = feed
125 class FeedsEmptySignal(BaseSignal):
126 pass
128 class FeedsImportedSignal(FeedsChangedSignal):
130 A signal for importing huge amount of feeds from OPML.
132 def __init__(self, sender, feeds,
133 parent=None, from_sub=False):
134 FeedsChangedSignal.__init__(self, sender)
135 self.feeds = feeds
136 self.category = parent
137 self.from_sub = from_sub
139 class FeedDeletedSignal(FeedsChangedSignal):
140 def __init__(self, sender, feed):
141 FeedsChangedSignal.__init__(self, sender, feed)
142 self.feed = feed
144 class FeedCreatedSignal(FeedsChangedSignal):
145 def __init__(self, sender, feed, category=None, index=None):
146 FeedsChangedSignal.__init__(self, sender)
147 self.feed = feed
148 self.category = category
149 self.index = index
151 # Feed detail Specific
152 class FeedDetailChangedSignal(BaseSignal):
153 def __init__(self, sender):
154 BaseSignal.__init__(self, sender)
156 class ItemOrderChangedSignal(FeedDetailChangedSignal):
157 pass
159 class FeedPollFrequencyChangedSignal(FeedDetailChangedSignal):
160 def __init__(self, sender):
161 BaseSignal.__init__(self, sender)
163 class FeedNumOfItemsStoredChangedSignal(FeedDetailChangedSignal):
164 def __init__(self, sender):
165 BaseSignal.__init__(self, sender)
167 class FeedErrorStatusChangedSignal(FeedDetailChangedSignal):
168 pass
170 class FeedInfoUpdatedSignal(FeedDetailChangedSignal):
172 Feed information like title, description, copyright, etc...
174 def __init__(self, sender):
175 BaseSignal.__init__(self, sender)
177 class FeedUnreadChangedSignal(FeedDetailChangedSignal):
178 def __init__(self, sender):
179 BaseSignal.__init__(self, sender)
182 # Feed category specific
184 class FeedCategoriesChangedSignal(BaseSignal):
185 pass
187 class FeedCategoryListChangedSignal(FeedCategoriesChangedSignal):
188 pass
190 class FeedCategoryListLoadedSignal(FeedCategoriesChangedSignal):
191 pass
193 class FeedCategoryAddedSignal(FeedCategoryListChangedSignal):
194 def __init__(self, sender, category):
195 FeedCategoryListChangedSignal.__init__(self, sender)
196 self.category = category
198 class FeedCategoryRemovedSignal(FeedCategoryListChangedSignal):
199 def __init__(self, sender, category):
200 FeedCategoryListChangedSignal.__init__(self, sender)
201 self.category = category
203 class FeedCategoryChangedSignal(FeedCategoriesChangedSignal):
204 """ Called when a Feed Category was modified (i.e. feed added, feed
205 removed, category title changed, etc...
207 def __init__(self, sender, feed=None):
208 FeedCategoriesChangedSignal.__init__(self, sender)
209 self.feed = feed
211 class FeedCategorySortedSignal(FeedCategoryChangedSignal):
212 """ Called when a Feed Category has been sorted. """
213 def __init__(self, sender, reverse=False):
214 FeedCategoryChangedSignal.__init__(self, sender)
215 self.descending = reverse
217 class SubscriptionContentsUpdatedSignal(BaseSignal):
218 pass
220 # Item specific
221 class ItemsAddedSignal(BaseSignal):
222 def __init__(self, sender, items):
223 BaseSignal.__init__(self, sender)
224 self.items = items
226 class ItemDeletedSignal(BaseSignal):
227 def __init__(self, sender, item):
228 BaseSignal.__init__(self, sender)
229 self.item = item
231 class NewItemsSignal(BaseSignal):
232 def __init__(self, sender, items):
233 BaseSignal.__init__(self, sender)
234 self.items = items
236 class ItemStickySignal(BaseSignal):
237 def __init__(self, sender, item=None):
238 BaseSignal.__init__(self, sender)
239 if item is None:
240 item = sender
241 self.item = item
243 class AllItemsReadSignal(BaseSignal):
244 def __init__(self, sender, changed):
245 BaseSignal.__init__(self, sender)
246 self.changed = changed
249 # Other events ...
251 class FeedLastPollChangedSignal(BaseSignal):
252 pass
254 class PollChangedSignal(BaseSignal):
255 def __init__(self, sender):
256 BaseSignal.__init__(self, sender)
258 class FeedPolledSignal(BaseSignal):
259 pass
261 class FeedStatusChangedSignal(BaseSignal):
263 Provides a signal for denoting that the polling process
264 has begun or finished.
266 pass
268 class ImageUpdatedSignal(BaseSignal):
269 def __init__(self, sender, url, data):
270 BaseSignal.__init__(self, sender)
271 self.url = url
272 self.data = data
274 class NumberOfItemsStoredChangedSignal(BaseSignal):
275 pass
277 class PollFrequencyChangedSignal(PollChangedSignal):
278 """ Global poll frequency """
279 def __init__(self, sender, value):
280 PollChangedSignal.__init__(self, sender)
281 self.value = value
283 class PollingStoppedSignal(BaseSignal):
284 pass
286 class FeedSelectionChangedSignal(BaseSignal):
288 Emitted when a feed has been selected in the feeds tree view.
290 def __init__(self, sender, old, new):
291 BaseSignal.__init__(self, sender)
292 self.old = old
293 self.new = new
295 class ItemSelectionChangedSignal(BaseSignal):
296 """ Called when an item has been selected in the item list.
297 Normally this should display the content of the item
299 def __init__(self, sender, item):
300 BaseSignal.__init__(self, sender)
301 self.item = item
303 class ItemReadSignal(BaseSignal):
304 """ Called when an item's 'seen' property has been changed
305 (i.e. marked as read)
307 def __init__(self, sender, item=None):
308 BaseSignal.__init__(self, sender)
309 if item is None:
310 item = sender
311 self.item = item
313 class CategorySelectionChangedSignal(BaseSignal):
315 Emitted when a the user changes categories
317 def __init__(self, sender, newcat):
318 BaseSignal.__init__(self, sender)
319 self.current = newcat
321 class OfflineModeChangedSignal(BaseSignal):
322 pass
324 class RefreshFeedDisplaySignal(BaseSignal):
325 pass
327 class StatusDisplaySignal(BaseSignal):
328 pass
330 class FindInterruptSignal(BaseSignal):
331 pass
334 if __name__ == '__main__':
335 print find_bases(ItemReadSignal)