/*! \page pydispatch PyDispatcher library and Signal API by GRASS Development Team (http://grass.osgeo.org) \tableofcontents \section pydispatchIntro Introduction Simple function calls are not sufficient in the GUI, event driven and large environment with many persistent objects because using simple function calls would lead to tightly coupled code. Thus, some better mechanism is needed such as Observer design pattern. We decided to use Signal system which is similar to Signals used in PyQt and other frameworks. As the underlying library, we have chosen PyDispatcher because it provides very general API which enables to implement Signal API, wide and robust functionality which makes implementation and use of Signals easier. Files dispatcher.py, errors.py, robustapply.py, robust.py and saferef.py are part of the original PyDispatcher library. File signal.py is the object-based easy-to-use interface created for GRASS. Signals as a concept (API) does not depend on PyDispatcher, so PyDipacher can be replaced by something else if necessary (in theory even with wx events). Of course, the API of underling library has to be general enough and some small changes in Signal API can occur. Nevertheless, it is important that Signals as a concept can be used with other library. Signals and PyDispatcher do not depend on wxPython, so it can be used even for non-GUI code (this allows to use controller classes to create command line tools). \section pydispatchSignal Signal addition to the original PyDispatcher The python.pydispatch.signal.Signal (grass.pydispatch.signal.Signal) class is the simplified API to the PyDispatcher library. It provides subset of minimal functionality. However, this subset should be enough to solve most of the problems. The main advantages of Signals are the readable syntax and more importantly, the understandable resulting design. Signal represents a message which will be sent at some point. Message usually informs about something which has happened. However, it is not necessary. A message can also say that something will happen or that we want something to happen. The Signal API is similar to Signal as used in PyQt, PySide. Some other frameworks (not necessarily Python one) support the similar set of functions but with more different names. \note Only Signal API should be used from this library to ensure consistency in design and variability in underlying library choice. \section pydispatchObserver Observer design pattern To get complete understanding of the signals system it is advised to understand observer design pattern. This design pattern is sometimes called Listener, Observer/Observable or Publisher/Subscriber. The main point is that it is nothing else than another view of the signals or events mechanisms. The basic schema follows. The Observable object holds the list of registered handlers and Observers register itself (or its methods) as these handlers. Once something interesting happens in the Observable, Observable notifies all its Observers. To avoid ad hoc observer implementation this and there, it is better to have universal reusable system such as Signals. \section pydispatchNaming Naming The occasion when something happens is called event or signal. The preferred word is signal. The word for actual triggering of the event is post, send, emit or notify. The process itself can be called sending a message. The preferred word is emit. The method called when event occurs is called handler, receiver, listener, observer, slot or callback. In some systems, there have to be receiver object and receiver function but in Python this is usually not the case. The preferred word is handler (but may change). The association of the signal to the handler is called connecting, binding, registration or subscription. The preferred word is connecting but registration is also acceptable. \section pydispatchWhyBetter Why are Signals better than wx events Here is the list of points why is the PyDispatcher with the custom Signal API better and more advantageous than wx event system when used to connect newly designed classes in wxGUI code. Some points may overlap, however the main point is that the wx event system is very complicated and cumbersome. As a concluding note, we can say that many of the wx events disadvantages are more or less copied from GRASS documentation where the wx event system was explained. This is pretty scary. \section pydispatchCodeComparison Signals and wx events code comparison \code{.py} # import from grass.pydispatch.signal import Signal # Signal from wx.lib.newevent import NewEvent # wx event # the signal/event definition # usually before class definition gMapCreated, EVT_MAP_CREATED = NewEvent() # wx event # somewhere in the class self.mapCreated = Signal('GConsole.mapCreated') # Signal # in some method which emits signal/event (in some class) # signal self.mapCreated.emit(name=name, ltype=prompt) # wx event mapEvent = gMapCreated(self._guiparent.GetId(), name=name, ltype=prompt) wx.PostEvent(self._guiparent, mapEvent) # connection in some __init__ (in some other class) self._gconsole.mapCreated.connect(self.OnMapCreated) # signal self.Bind(EVT_MAP_CREATED, self.OnMapCreated) # wx event # handler (in the other class) # signal def OnMapCreated(self, name, ltype): doSomethinUseful(name, ltype) # in this case function could be connected directly # wx event def OnMapCreated(self, event): doSomethingUseful(event.name, event.ltype) event.Skip() # sometimes yes, sometimes no \endcode When a method does not take any parameters, no additional work is needed when using Signals. A handler can be connected directly to a signal (even if the signal has some parameters). \code{.py} def someMethod(self): """Method without parameters.""" something.someSignal.connect(self.someMethod) # signal something.Bind(EVT_SOMETHING, lambda event: self.someMethod()) # wx event \endcode \section pydispatchWhereUse Where to use Signals rather than wx events Signals should be used for all non-GUI objects. Moreover, no new wx events shall be defined. The Signals should be used instead. wx events should be used only when binding to existing wxPython GUI objects. For controlling the graphical objects on the library level, the wx events are necessary. \section pydispatchDisadvantages Signals and PyDispatcher disadvantages It must be noted that non-stoppable propagation, no auto-propagation and no information about order of handlers leads to better code design because if you don't rely on these features, you usually write a less tangled code. \section pydispatchAlternatives Alternatives There is wxPython's pubsub module which provides similar functionality to PyDispatcher. However, it has two incompatible APIs which depends on the wxPython version and in the time of writing, GRASS would have to support both these APIs. The only possibility is to include pubsub into GRASS. Whether to use PyDispatcher or pubsub usually depends on personal taste. There are several forks of PyDispatcher, e.g. the fork in Django framework. They provide the same or similar functionality. Of course it is also possible to implement this system from the scratch using e.g., observer pattern. Although it is possible it becomes more complicated when the system has to be generalized. \section pydispatchAuthors Authors Patrick K. O'Brien, Mike C. Fletcher and Contributors (original authors, see pydispatch/license.txt and pydispatch/PKG-INFO for details) Vaclav Petras (signal.py) Anna Kratochilova (signal.py) */