File: gmRegetMixin.py

package info (click to toggle)
gnumed-client 0.2.8.10-1
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 5,028 kB
  • ctags: 4,693
  • sloc: python: 38,024; sh: 286; makefile: 67
file content (237 lines) | stat: -rw-r--r-- 8,234 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
"""gmRegetMixin - GNUmed data change callback mixin.

Widget code can mix in this class as a base class and
thus gain the infrastructure to update it's display
when data changes. If the widget is not visible it will
only schedule refetching data from the business layer.
If it *is* visible it will immediately fetch and redisplay.

You must call cRegetOnPaintMixin.__init__() in your own
__init__() after calling __init__() on the appropriate
wx.Widgets class your widget inherits from.

You must then make sure to call _schedule_data_reget()
whenever you learn of backend data changes. This will
in most cases happen after you receive a gmDispatcher
signal indicating a change in the backend.

The _populate_with_data(self) method must be overriden in the
including class and must return True if the UI was successfully
repopulated with content.

@copyright: authors
"""
#===========================================================================
# $Source: /sources/gnumed/gnumed/gnumed/client/wxpython/gmRegetMixin.py,v $
# $Id: gmRegetMixin.py,v 1.27 2007/10/29 13:19:07 ncq Exp $
__version__ = "$Revision: 1.27 $"
__author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
__license__ = 'GPL (details at http://www.gnu.org)'

import wx

#===========================================================================
class cRegetOnPaintMixin:
	"""Mixin to add redisplay_data-on-wx.EVT_PAINT aspect.

	Any code mixing in this class will gain the mechanism
	to reget data on wxPaint events. The code must be an
	instance of a wx.Window and must implement a
	_populate_with_data() method. It must also call
	_schedule_data_reget() at appropriate times.
	"""
	def __init__(self):
		self._data_stale = True
		try:
			wx.EVT_PAINT(self, self._on_paint_event)
		except:
			print 'you likely need to call "cRegetOnPaintMixin.__init__(self)" later in %s__init__()' % self.__class__.__name__
			raise
#		wx.EVT_SET_FOCUS(self, self._on_focus_event)
	#-----------------------------------------------------
	def _on_paint_event(self, event):
		"""Called just before the widget is repainted.

		Checks whether data needs to be refetched.
		"""
		self.repopulate_ui()
		event.Skip()
	#-----------------------------------------------------
#	def _on_focus_event(self, event):
#		"""Doubtful whether that's the proper way to do it but seems OK."""
#		print "cRegetOnPaintMixin._on_focus_event() for", self.__class__.__name__
#		self.Refresh()
#		event.Skip()
	#-----------------------------------------------------
	def repopulate_ui(self):
		"""Checks whether data must be refetched and 

		Called on different occasions such as "notebook page
		raised" or "paint event received".
		"""
		if self._data_stale:
			if self._populate_with_data():
				self._data_stale = False
				return True
			self._data_stale = True
			return False
		return True
	#-----------------------------------------------------
	def _populate_with_data(self):
		"""Actually fills the UI with data.

		This must be overridden in child classes !
		"""
		raise NotImplementedError, "[%s] _populate_with_data() not implemented" % self.__class__.__name__
		return False
	#-----------------------------------------------------
	def _schedule_data_reget(self):
		"""Flag data as stale and schedule refetch/redisplay.

		- if not visible schedules reget only
		- if visible redisplays immediately (virtue of Refresh() calling _on_paint_event() if visible)

		Called whenever data changes become known such as from
		database listener threads, dispatcher signals etc.
		"""
		self._data_stale = True

		# Master Robin Dunn says this is The Way(tm) but
		# neither this:
#		wx.GetApp().GetTopWindow().Refresh()
		# nor this:
		#top_parent = wx.GetTopLevelParent(self)
		#top_parent.Refresh()
		# appear to work as expected :-(
		# The issues I have with them are:
		# 1) It appears to cause refreshes "too often", eg whenever
		#    *any*  child of self calls this method - but this may
		#    not matter much as only those that have self._data_stale
		#    set to True will trigger backend refetches.
		# 2) Even this does not in all cases cause a proper redraw
		#    of the visible widgets - likely because nothing has
		#    really changed in them, visually.

		# further testing by Hilmar revealed, that the
		# following appears to work:
		self.Refresh()
		# the logic should go like this:
		# database insert -> after-insert trigger
		# -> notify
		# -> middleware listener
		# -> flush middleware cache
		# -> dispatcher signal to frontend listener*s*
		# -> frontend listeners schedule a data reget and a Refresh()
		# problem: those that are not visible are refreshed, too
		# FIXME: is this last assumption true ?
		return True
#===========================================================================
# main
#---------------------------------------------------------------------------
if __name__ == '__main__':
	print "no unit test available"

#===========================================================================
# $Log: gmRegetMixin.py,v $
# Revision 1.27  2007/10/29 13:19:07  ncq
# - cleanup
#
# Revision 1.26  2006/05/31 09:48:14  ncq
# - cleanup
#
# Revision 1.25  2006/05/28 16:14:18  ncq
# - cleanup, remove gmLog dependancy, improve docs
# - comment out on-set-focus listening
# - lots of debugging help for the time being
# - add repopulate_ui() for external callers
#
# Revision 1.24  2005/09/28 21:27:30  ncq
# - a lot of wx2.6-ification
#
# Revision 1.23  2005/09/28 15:57:48  ncq
# - a whole bunch of wx.Foo -> wx.Foo
#
# Revision 1.22  2005/09/27 20:44:59  ncq
# - wx.wx* -> wx.*
#
# Revision 1.21  2005/09/26 18:01:51  ncq
# - use proper way to import wx26 vs wx2.4
# - note: THIS WILL BREAK RUNNING THE CLIENT IN SOME PLACES
# - time for fixup
#
# Revision 1.20  2005/08/03 20:02:11  ncq
# - Hilmar eventually seems to have found a way to
#   update data in visible widgets immediately
#
# Revision 1.19  2005/07/31 16:23:27  ncq
# - Hilmar's latest refresh fixes
#
# Revision 1.18  2005/07/27 09:53:30  ncq
# - petty cleanup
#
# Revision 1.17  2005/07/26 19:24:26  hinnef
# - fixed refresh bug on MSW platform
#
# Revision 1.16  2005/06/07 09:05:53  ncq
# - better docs
#
# Revision 1.15  2005/05/29 22:06:19  ncq
# - unsuccessfully try yet another technique for forcing a repaint
#
# Revision 1.14  2005/05/24 19:46:47  ncq
# - call top level window refresh at the end of _schedule_data_reget()
#   which should cause a repaint of the visible widgets, which in turn
#   will cause them to reget data from the business objects which in
#   turn will cause those to reload from the backend, suggested by
#   Robin Dunn
#
# Revision 1.13  2005/05/17 08:07:19  ncq
# - cleanup
#
# Revision 1.12  2005/05/08 21:42:17  ncq
# - import gmLog
#
# Revision 1.11  2005/05/06 15:31:03  ncq
# - slightly improved docs
#
# Revision 1.10  2005/05/05 06:35:02  ncq
# - add some device context measurements in _schedule_data_reget
#   so we can maybe find a way to detect whether we are indeed
#   visible or obscured
#
# Revision 1.9  2005/04/30 13:32:14  sjtan
#
# if current wxWindow that inherits gmRegetMixin IsShown() is true, then it requires
# refresh, so Reget is not scheduled , but immediate.
#
# Revision 1.8  2005/03/20 17:51:41  ncq
# - although not sure whether conceptually it's the right thing to do it
#   sure seems appropriated to Refresh() on focus events
#
# Revision 1.7  2005/01/13 14:27:33  ncq
# - grammar fix
#
# Revision 1.6  2004/10/17 15:52:21  ncq
# - cleanup
#
# Revision 1.5  2004/10/17 00:05:36  sjtan
#
# fixup for paint event re-entry when notification dialog occurs over medDocTree graphics
# area, and triggers another paint event, and another notification dialog , in a loop.
# Fixup is set flag to stop _repopulate_tree, and to only unset this flag when
# patient activating signal gmMedShowDocs to schedule_reget, which is overridden
# to include resetting of flag, before calling mixin schedule_reget.
#
# Revision 1.4  2004/09/05 14:55:19  ncq
# - improve comments, some cleanup
#
# Revision 1.3  2004/08/04 17:12:06  ncq
# - fix comment
#
# Revision 1.2  2004/08/02 17:52:54  hinnef
# Added hint to _repopulate_with_data return value
#
# Revision 1.1  2004/07/28 15:27:31  ncq
# - first checkin, used in gmVaccWidget
#
#