""" Event.py Module for dispatching Straw-related events. """ __copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc." __license__ = """ GNU General Public License This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ import traceback import sys import error _base_cache = dict() def find_bases(klass): def _find_bases(klass, d = None): if d is None: d = dict() for b in klass.__bases__: if issubclass(b, BaseSignal): d[b] = 1 _find_bases(b, d) return tuple(d.keys()) bases = _base_cache.get(klass, None) if bases is not None: return bases bases = _find_bases(klass) _base_cache[klass] = bases return bases class BaseSignal: def __init__(self, sender): self.sender = sender return class SignalEmitter: recorder = None """Base class for signal emitters""" def __init__(self): self._slots = dict() def initialize_slots(self, *signals): """Initialize signal slots. signals should be a list of signals this emitter is going to send.""" for s in signals: self._slots[s] = dict() bs = find_bases(s) for k in bs: self._slots[k] = dict() def signal_connect(self, signal, handler, data=None): """Connect a handler to a signal in this emitter, and associate data with the callback. This will override previous bindings of signal to handler.""" self._slots[signal][handler] = data return def signal_disconnect(self, signal, handler): """Disconnect handler from signal.""" self._slots[signal][handler] = None del self._slots[signal][handler] return def emit_signal(self, signal): """Emit a signal object. Signal should be an instance of BaseSignal or a subclass.""" sclasses = find_bases(signal.__class__) for sc in sclasses + (signal.__class__,): for handler, data in self._slots.get(sc, {}).items(): if data is not None: args = (signal, data) else: args = (signal,) try: #if self.recorder is not None: # self.recorder.record(sc, handler) apply(handler, args) except: error.log_exc("Caught an exception when trying to " "call a signal handler for " "signal %s\n" % str(signal)) traceback.print_exc() """ def start_recording(klass, recorder): klass.recorder = recorder start_recording = classmethod(start_recording) def stop_recording(klass): if klass.recorder is not None: klass.recorder.stop() klass.recorder = None stop_recording = classmethod(stop_recording) """ # Feed creation and feed list management events class FeedsChangedSignal(BaseSignal): def __init__(self, sender, feed=None): BaseSignal.__init__(self, sender) self.feed = feed class FeedsEmptySignal(BaseSignal): pass class FeedsImportedSignal(FeedsChangedSignal): """ A signal for importing huge amount of feeds from OPML. """ def __init__(self, sender, feeds, parent=None, from_sub=False): FeedsChangedSignal.__init__(self, sender) self.feeds = feeds self.category = parent self.from_sub = from_sub class FeedDeletedSignal(FeedsChangedSignal): def __init__(self, sender, feed): FeedsChangedSignal.__init__(self, sender, feed) self.feed = feed class FeedCreatedSignal(FeedsChangedSignal): def __init__(self, sender, feed, category=None, index=None): FeedsChangedSignal.__init__(self, sender) self.feed = feed self.category = category self.index = index # Feed detail Specific class FeedDetailChangedSignal(BaseSignal): def __init__(self, sender): BaseSignal.__init__(self, sender) class ItemOrderChangedSignal(FeedDetailChangedSignal): pass class FeedPollFrequencyChangedSignal(FeedDetailChangedSignal): def __init__(self, sender): BaseSignal.__init__(self, sender) class FeedNumOfItemsStoredChangedSignal(FeedDetailChangedSignal): def __init__(self, sender): BaseSignal.__init__(self, sender) class FeedErrorStatusChangedSignal(FeedDetailChangedSignal): pass class FeedInfoUpdatedSignal(FeedDetailChangedSignal): """ Feed information like title, description, copyright, etc... """ def __init__(self, sender): BaseSignal.__init__(self, sender) class FeedUnreadChangedSignal(FeedDetailChangedSignal): def __init__(self, sender): BaseSignal.__init__(self, sender) # Feed category specific class FeedCategoriesChangedSignal(BaseSignal): pass class FeedCategoryListChangedSignal(FeedCategoriesChangedSignal): pass class FeedCategoryListLoadedSignal(FeedCategoriesChangedSignal): pass class FeedCategoryAddedSignal(FeedCategoryListChangedSignal): def __init__(self, sender, category): FeedCategoryListChangedSignal.__init__(self, sender) self.category = category class FeedCategoryRemovedSignal(FeedCategoryListChangedSignal): def __init__(self, sender, category): FeedCategoryListChangedSignal.__init__(self, sender) self.category = category class FeedCategoryChangedSignal(FeedCategoriesChangedSignal): """ Called when a Feed Category was modified (i.e. feed added, feed removed, category title changed, etc... """ def __init__(self, sender, feed=None): FeedCategoriesChangedSignal.__init__(self, sender) self.feed = feed class FeedCategorySortedSignal(FeedCategoryChangedSignal): """ Called when a Feed Category has been sorted. """ def __init__(self, sender, reverse=False): FeedCategoryChangedSignal.__init__(self, sender) self.descending = reverse class SubscriptionContentsUpdatedSignal(BaseSignal): pass # Item specific class ItemsAddedSignal(BaseSignal): def __init__(self, sender, items): BaseSignal.__init__(self, sender) self.items = items class ItemDeletedSignal(BaseSignal): def __init__(self, sender, item): BaseSignal.__init__(self, sender) self.item = item class NewItemsSignal(BaseSignal): def __init__(self, sender, items): BaseSignal.__init__(self, sender) self.items = items class ItemStickySignal(BaseSignal): def __init__(self, sender, item=None): BaseSignal.__init__(self, sender) if item is None: item = sender self.item = item class AllItemsReadSignal(BaseSignal): def __init__(self, sender, changed): BaseSignal.__init__(self, sender) self.changed = changed # Other events ... class FeedLastPollChangedSignal(BaseSignal): pass class PollChangedSignal(BaseSignal): def __init__(self, sender): BaseSignal.__init__(self, sender) class FeedPolledSignal(BaseSignal): pass class FeedStatusChangedSignal(BaseSignal): """ Provides a signal for denoting that the polling process has begun or finished. """ pass class ImageUpdatedSignal(BaseSignal): def __init__(self, sender, url, data): BaseSignal.__init__(self, sender) self.url = url self.data = data class NumberOfItemsStoredChangedSignal(BaseSignal): pass class PollFrequencyChangedSignal(PollChangedSignal): """ Global poll frequency """ def __init__(self, sender, value): PollChangedSignal.__init__(self, sender) self.value = value class PollingStoppedSignal(BaseSignal): pass class FeedSelectionChangedSignal(BaseSignal): """ Emitted when a feed has been selected in the feeds tree view. """ def __init__(self, sender, old, new): BaseSignal.__init__(self, sender) self.old = old self.new = new class ItemSelectionChangedSignal(BaseSignal): """ Called when an item has been selected in the item list. Normally this should display the content of the item """ def __init__(self, sender, item): BaseSignal.__init__(self, sender) self.item = item class ItemReadSignal(BaseSignal): """ Called when an item's 'seen' property has been changed (i.e. marked as read) """ def __init__(self, sender, item=None): BaseSignal.__init__(self, sender) if item is None: item = sender self.item = item class CategorySelectionChangedSignal(BaseSignal): """ Emitted when a the user changes categories """ def __init__(self, sender, newcat): BaseSignal.__init__(self, sender) self.current = newcat class OfflineModeChangedSignal(BaseSignal): pass class RefreshFeedDisplaySignal(BaseSignal): pass class StatusDisplaySignal(BaseSignal): pass class FindInterruptSignal(BaseSignal): pass if __name__ == '__main__': print find_bases(ItemReadSignal)