Changes

Jump to: navigation, search

Signals and Callbacks

26 bytes added, 00:09, 2 July 2017
thanks paul very handy
== Overview ==
The Gramps signaling system is used to pass changes in the db, GUI, or other sources to various elements (usually the GUI) that need to be updated when changes occur.
The GUI also emits signals when some user action changes the state; on a given view the 'active-changed' signal indicates that the selected object has changed. In addition, Gtk provides a rich set of signals for their widgets that use the separate (but similar) Gtk signal system.
 
== Callback ==
For the db and most of the GUI, the callback.py module with its Callback class provides much of the functionality. The Callback class is usually a base class for modules that emit and allow connection to callbacks, so its methods become part of the main class. An example is the class DbBsddbRead, or the displaystate.py History class. When emitting or connecting to a callback it is important to use the correct object in calling the method. If your code needs to see a 'databased-changed' and 'person-update' signals, for instance, you might use:
history = self.uistate.get_history(nav_type, self.nav_group) # get history for current view
history.connect("active-changed", method)
 
=== Callback methods ===
emit(signal_name, args=tuple())
There are additional methods in this module (read the code) to enable or disable logging of signals and a few lesser used functions.
 
=== Callback example ===
An example usage of the Callback methods is to get an update of a person object, the db code will at some point do:
# in close or cleanup code make sure to disconnect from db
self.db.disconnect(self.key)
 
== Callman ==
There is also the callman.py which implements the CallbackManager class. This class serves to assist a signal user (typically a GUI element) in registering for callbacks on primary objects (Person, Place etc.) from the db. The CallbackManager acts as a filter, in that it will only pass on a signal to the GUI element if the element has registered for one or more handles it is interested in. This reduces the overhead of signals when there are a lot of GUI elements 'listening', they don't all have to update on every signal. It also assists in keeping track of callbacks so the cleanup process is a bit easier.
 
=== Instantiating the CallbackManager ===
The Callback class is unique to a db and some GUI element. When instantiating the class, the current db is passed in:
self.callman = CallbackManager(database)
When a db is changed, one should destroy the CallbackManager and set up a new one (or delete the GUI element as it shows info from a previous db).
 
=== Registering callbacks with the CallbackManager ===
The CallbackManager allows the programmer to 'register' several callbacks at once:
If the key is only one of the primary object types ('person', 'family', 'tag' etc.), then the function is registered for all of the available db transaction types ('add', 'delete', 'update', 'rebuild').
 
=== Making connections with the CallbackManager ===
The CallbackManager actually makes the connections to the db when the following is executed, so this MUST follow the <code>register_callbacks</code> method in your code. The handles can be registered later on if desired.
connect_all(keys)
This connects all database signals related to the primary objects given in 'keys' to the already registered callbacks. Note that only those callbacks registered with <code>register_callbacks</code> will effectively result in an action, so it is safe to connect to all keys even if not all keys have a registered callback. The parameter 'keys' is a list of keys of primary objects for which to connect the signals, with the default that no connects are done. One can enable signal activity to needed objects by passing a list, e.g. <code>keys=['source', 'place]</code>, or to all with <code>keys=callman.KEYS</code> (which is a list of all the keys)
 
=== Removing connections with the CallbackManager ===
disconnect_all()
This disconnects the GUI element from all signals from the database. This method should always be called before the callback methods become invalid, that is, before closing the GUI element.
 
=== Registering handles for callbacks ===
The CallbackManager allows the programmer to 'register' handles to be monitored in mass, according to the basic object class of each handle.
When directonly is True, this method, will register all directly primary objects (their handles) connected to baseobj with the CallbackManager. So a person objects media, notes, attributes etc. will have their handles returned. If directonly is False, a recursive search is done through the primary objects that have references, and all other referenced handles will also be registered.
Note that the handle for baseobj is not registered itself. Also note that objects that go through a reference object (like Event through EventRef) are not registered.
 
=== Unregister handles with the CallbackManager ===
The following allows the programmer to stop monitoring handles. It uses the same ahandledict as <code>register_handles</code>:
Examples of these signals are 'person-add', 'media-update', 'note-delete'. This type of signal is emitted with a list of handles of the primary objects affected as arguments.
{{man note|Note: |the following only applies to normal transactions, 'batch' transactions do not produce signals.}}
These signals are emitted when one or more commits occur at the end of a transaction. The signals are delayed until the end of the transaction so that they are not emitted if the transaction fails. Because the signals are delayed until after the all the transaction commits are actually complete, it is important for programmers to understand possible side effects.
[[Category:Developers/Tutorials]]
[[Category:Developers/General]]
[[Category:GEPS]]

Navigation menu