Package Gnumed :: Package wxpython :: Module gmRegetMixin |
[frames] | no frames]

# Source Code for Module Gnumed.wxpython.gmRegetMixin

      1  """gmRegetMixin - GNUmed data change callback mixin.
      2
      3  Widget code can mix in this class as a base class and
      4  thus gain the infrastructure to update it's display
      5  when data changes. If the widget is not visible it will
      6  only schedule refetching data from the business layer.
      7  If it *is* visible it will immediately fetch and redisplay.
      8
      9  You must call cRegetOnPaintMixin.__init__() in your own
     10  __init__() after calling __init__() on the appropriate
     11  wx.Widgets class your widget inherits from.
     12
     13  You must then make sure to call _schedule_data_reget()
     14  whenever you learn of backend data changes. This will
     15  in most cases happen after you receive a gmDispatcher
     16  signal indicating a change in the backend.
     17
     18  The _populate_with_data(self) method must be overriden in the
     19  including class and must return True if the UI was successfully
     20  repopulated with content.
     21
     22  @copyright: authors
     23
     24  Template for users:
     25
     26          #-----------------------------------------------------
     27          # reget-on-paint mixin API
     28          #-----------------------------------------------------
     29          # remember to call
     30          #       self._schedule_data_reget()
     31          # whenever you learn of data changes from database listener
     32          # threads, dispatcher signals etc.
     33          def _populate_with_data(self):
     34                  # fill the UI with data
     35                  print "need to implement _populate_with_data"
     36                  return False
     37                  return True
     38          #-----------------------------------------------------
     39  """
     40  #===========================================================================
     41  # $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/wxpython/gmRegetMixin.py,v $
     42  # $Id: gmRegetMixin.py,v 1.30 2009-05-08 08:01:36 ncq Exp $
     43  __version__ = "$Revision: 1.30 $"
     44  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
     45  __license__ = 'GPL v2 or later (details at http://www.gnu.org)'
     46
     47  import wx
     48
     49  #===========================================================================
     50 -class cRegetOnPaintMixin:
     51          """Mixin to add redisplay_data-on-wx.EVT_PAINT aspect.
     52
     53          Any code mixing in this class will gain the mechanism
     54          to reget data on wxPaint events. The code must be an
     55          instance of a wx.Window and must implement a
     56          _populate_with_data() method. It must also call
     57          _schedule_data_reget() at appropriate times.
     58          """
     59 -        def __init__(self):
     60                  self._data_stale = True
     61                  try:
     62                          wx.EVT_PAINT(self, self.__on_paint_event)
     63                  except:
     64                          print 'you likely need to call "cRegetOnPaintMixin.__init__(self)" later in %s__init__()' % self.__class__.__name__
     65                          raise
     66          #-----------------------------------------------------
     67 -        def __on_paint_event(self, event):
     68                  """Called just before the widget is repainted.
     69
     70                  Checks whether data needs to be refetched.
     71                  """
     72                  self.__repopulate_ui()
     73                  event.Skip()
     74          #-----------------------------------------------------
     75 -        def __repopulate_ui(self):
     76                  """Checks whether data must be refetched and does so
     77
     78                  Called on different occasions such as "notebook page
     79                  raised" or "paint event received".
     80                  """
     81                  if self._data_stale:
     82                          self._data_stale = not self._populate_with_data()
     83
     84                  return not self._data_stale
     85          #-----------------------------------------------------
     86          # API for child classes
     87          #-----------------------------------------------------
     88 -        def _populate_with_data(self):
     89                  """Actually fills the UI with data.
     90
     91                  This must be overridden in child classes !
     92
     93                  Must return True/False.
     94                  """
     95                  raise NotImplementedError, "[%s] _populate_with_data() not implemented" % self.__class__.__name__
     96          #-----------------------------------------------------
     97 -        def _schedule_data_reget(self):
     98                  """Flag data as stale and schedule refetch/redisplay.
     99
    100                  - if not visible schedules refetch only
    101                  - if visible redisplays immediately (virtue of Refresh()
    102                    calling __on_paint_event() if visible) thereby invoking
    103                    the actual data refetch
    104
    105                  Called by the child class whenever it learns of data changes
    106                  such as from database listener threads, dispatcher signals etc.
    107                  """
    108                  self._data_stale = True
    109
    110                  # Master Robin Dunn sayeth this is The Way(tm) but
    111                  # neither this:
    112                  #wx.GetApp().GetTopWindow().Refresh()
    113                  # nor this:
    114                  #top_parent = wx.GetTopLevelParent(self)
    115                  #top_parent.Refresh()
    116                  # appear to work as expected :-(
    117                  # The issues I have with them are:
    118                  # 1) It appears to cause refreshes "too often", eg whenever
    119                  #    *any*  child of self calls this method - but this may
    120                  #    not matter much as only those that have self._data_stale
    121                  #    set to True will trigger backend refetches.
    122                  # 2) Even this does not in all cases cause a proper redraw
    123                  #    of the visible widgets - likely because nothing has
    124                  #    really changed in them, visually.
    125
    126                  # further testing by Hilmar revealed that the
    127                  # following appears to work:
    128                  self.Refresh()
    129                  # the logic should go like this:
    130                  # database insert -> after-insert trigger
    131                  # -> notify
    132                  # -> middleware listener
    133                  # -> flush optional middleware cache
    134                  # -> dispatcher signal to frontend listener*s*
    135                  # -> frontend listeners schedule a data reget and a Refresh()
    136                  # problem: those that are not visible are refreshed, too
    137                  # FIXME: is this last assumption true ?
    138                  return True
    139          #-----------------------------------------------------
    140          # notebook plugin API if needed
    141          #-----------------------------------------------------
    142 -        def repopulate_ui(self):
    143                  """Just a glue method to make this compatible with notebook plugins."""
    144                  self.__repopulate_ui()
    145  #===========================================================================
    146  # main
    147  #---------------------------------------------------------------------------
    148  if __name__ == '__main__':
    149          print "no unit test available"
    150
    151  #===========================================================================
    152