changeset 1248:2f9fa5d59e67

Add data_monitor meta-class to monitor accessing on domview_ui. - The monitoring is to prevent from reentry triggered by DOM events. - call 'do*' methods of a monitored class would try to lock domview_ui at first. - The method would not be executed actually if being fault to lock. - You can make monitor to print debug message with environment variable - DATA_MONITOR_DBG=1, or - DATA_MONITOR_DBG=2
author Thinker K.F. Li <thinker@codemud.net>
date Tue, 11 Jan 2011 10:04:14 +0800
parents 45e9566ea5c0
children 16a1166c3850
files pyink/MBScene.py pyink/domview_ui.py
diffstat 2 files changed, 62 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/pyink/MBScene.py	Mon Jan 10 22:15:16 2011 +0800
+++ b/pyink/MBScene.py	Tue Jan 11 10:04:14 2011 +0800
@@ -37,12 +37,68 @@
 #       scene into two scenes with the same content.
 #
 
+## \brief Monitor accessing on the dta model.
+#
+# This class is a meta-class that monitor data accessing for its instance
+# classes.
+#
+# All methods, of instance classes, who's name is prefixed with 'do' are
+# monitored.  When a monitored method was called, monitor will try to lock
+# _domview of the object.  The method is only called if successfully acquiring
+# the lock, or return immediately.  The lock is released after the calling
+# returned.
+#
+class data_monitor(type):
+    def __new__(mclazz, name, bases, clazz_dict):
+	import os
+
+	debug_level = 0
+	if os.environ.has_key('DATA_MONITOR_DBG'):
+	    debug_level = int(os.environ['DATA_MONITOR_DBG'])
+	    pass
+	
+	def gen_sentinel(name, func):
+	    def sentinel(self, *args, **kws):
+		if debug_level >= 1:
+		    print 'calling %s' % (name)
+		    pass
+		if debug_level >= 2:
+		    print '    args: %s' % (repr(args))
+		    print '    kws:  %s' % (repr(kws))
+		    pass
+		
+		if not self._domview.lock(): # can not lock
+		    return
+		
+		try:
+		    func(self, *args, **kws)
+		finally:
+		    self._domview.unlock()
+		    pass
+		pass
+	    return sentinel
+
+	for attr_name in clazz_dict:
+	    if (not attr_name.startswith('do')) or \
+		    (not callable(clazz_dict[attr_name])):
+		continue
+	    clazz_dict[attr_name] = \
+		gen_sentinel(attr_name, clazz_dict[attr_name])
+	    pass
+	
+	clazz = type.__new__(mclazz, name, bases, clazz_dict)
+	
+	return clazz
+    pass
+
 ## \brief MBScene connect GUI and DOM-tree
 #
 # This method accepts user actions and involves domview_ui to update
 # data on the document.
 #
 class MBScene(object):
+    __metaclass__ = data_monitor
+
     _tween_type_names = ('normal', 'scale')
     
     _num_frames_of_line = 100
--- a/pyink/domview_ui.py	Mon Jan 10 22:15:16 2011 +0800
+++ b/pyink/domview_ui.py	Tue Jan 11 10:04:14 2011 +0800
@@ -639,5 +639,11 @@
     @property
     def root(self):
         return self._root
+
+    def lock(self):
+        return True
+
+    def unlock(self):
+        return True
     pass