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  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>" 
 42  __license__ = 'GPL v2 or later (details at http://www.gnu.org)' 
 43   
 44  import wx 
 45   
 46  #=========================================================================== 
47 -class cRegetOnPaintMixin:
48 """Mixin to add redisplay_data-on-wx.EVT_PAINT aspect. 49 50 Any code mixing in this class will gain the mechanism 51 to reget data on wxPaint events. The code must be an 52 instance of a wx.Window and must implement a 53 _populate_with_data() method. It must also call 54 _schedule_data_reget() at appropriate times. 55 """
56 - def __init__(self):
57 self._data_stale = True 58 try: 59 wx.EVT_PAINT(self, self.__on_paint_event) 60 except: 61 print 'you likely need to call "cRegetOnPaintMixin.__init__(self)" later in %s__init__()' % self.__class__.__name__ 62 raise
63 #-----------------------------------------------------
64 - def __on_paint_event(self, event):
65 """Called just before the widget is repainted. 66 67 Checks whether data needs to be refetched. 68 """ 69 self.__repopulate_ui() 70 event.Skip()
71 #-----------------------------------------------------
72 - def __repopulate_ui(self):
73 """Checks whether data must be refetched and does so 74 75 Called on different occasions such as "notebook page 76 raised" or "paint event received". 77 """ 78 if not self._data_stale: 79 return True 80 repopulated = self._populate_with_data() 81 self._data_stale = (repopulated is False) 82 return repopulated
83 #----------------------------------------------------- 84 # API for child classes 85 #-----------------------------------------------------
86 - def _populate_with_data(self):
87 """Actually fills the UI with data. 88 89 This must be overridden in child classes ! 90 91 Must return True/False. 92 """ 93 raise NotImplementedError, "[%s] _populate_with_data() not implemented" % self.__class__.__name__
94 #-----------------------------------------------------
95 - def _schedule_data_reget(self):
96 """Flag data as stale and schedule refetch/redisplay. 97 98 - if not visible schedules refetch only 99 - if visible redisplays immediately (virtue of Refresh() 100 calling __on_paint_event() if visible) thereby invoking 101 the actual data refetch 102 103 Called by the child class whenever it learns of data changes 104 such as from database listener threads, dispatcher signals etc. 105 """ 106 self._data_stale = True 107 108 # Master Robin Dunn sayeth this is The Way(tm) but 109 # neither this: 110 #wx.GetApp().GetTopWindow().Refresh() 111 # nor this: 112 #top_parent = wx.GetTopLevelParent(self) 113 #top_parent.Refresh() 114 # appear to work as expected :-( 115 # The issues I have with them are: 116 # 1) It appears to cause refreshes "too often", eg whenever 117 # *any* child of self calls this method - but this may 118 # not matter much as only those that have self._data_stale 119 # set to True will trigger backend refetches. 120 # 2) Even this does not in all cases cause a proper redraw 121 # of the visible widgets - likely because nothing has 122 # really changed in them, visually. 123 124 # further testing by Hilmar revealed that the 125 # following appears to work: 126 self.Refresh() 127 # the logic should go like this: 128 # database insert -> after-insert trigger 129 # -> notify 130 # -> middleware listener 131 # -> flush optional middleware cache 132 # -> dispatcher signal to frontend listener*s* 133 # -> frontend listeners schedule a data reget and a Refresh() 134 # problem: those that are not visible are refreshed, too 135 # FIXME: is this last assumption true ? 136 return True
137 #----------------------------------------------------- 138 # notebook plugin API if needed 139 #-----------------------------------------------------
140 - def repopulate_ui(self):
141 """Just a glue method to make this compatible with notebook plugins.""" 142 self.__repopulate_ui()
143 #=========================================================================== 144 # main 145 #--------------------------------------------------------------------------- 146 if __name__ == '__main__': 147 print "no unit test available" 148