1
2
3
4
5
6
7 """Contains the base classes that many of NVDA's classes such as NVDAObjects, virtualBuffers, appModules, synthDrivers inherit from. These base classes provide such things as auto properties, and methods and properties for scripting and key binding.
8 """
9
10 import weakref
11 from logHandler import log
14
17
19 if not instance:
20 return self
21 return self.fget(instance)
22
24 return property(fget=self._func,fset=func)
25
27 return property(fget=self._func,fdel=func)
28
30
31 - def __get__(self, instance, owner):
35
37
39 super(AutoPropertyType,self).__init__(name,bases,dict)
40
41 cacheByDefault=False
42 try:
43 cacheByDefault=dict["cachePropertiesByDefault"]
44 except KeyError:
45 cacheByDefault=any(getattr(base, "cachePropertiesByDefault", False) for base in bases)
46
47 props=(x[5:] for x in dict.keys() if x[0:5] in ('_get_','_set_','_del_'))
48 for x in props:
49 g=dict.get('_get_%s'%x,None)
50 s=dict.get('_set_%s'%x,None)
51 d=dict.get('_del_%s'%x,None)
52 if x in dict:
53 methodsString=",".join([str(i) for i in g,s,d if i])
54 raise TypeError("%s is already a class attribute, cannot create descriptor with methods %s"%(x,methodsString))
55 if not g:
56
57
58 for base in bases:
59 g = getattr(base,'_get_%s'%x,None)
60 if g:
61 break
62
63 cache=dict.get('_cache_%s'%x,None)
64 if cache is None:
65
66 for base in bases:
67 cache = getattr(base,'_cache_%s'%x,None)
68 if cache is not None:
69 break
70 else:
71 cache=cacheByDefault
72
73 if g and not s and not d:
74 setattr(self,x,(CachingGetter if cache else Getter)(g))
75 else:
76 setattr(self,x,property(fget=g,fset=s,fdel=d))
77
79 """A class that dynamicly supports properties, by looking up _get_* and _set_* methods at runtime.
80 _get_x will make property x with a getter (you can get its value).
81 _set_x will make a property x with a setter (you can set its value).
82 If there is a _get_x but no _set_x then setting x will override the property completely.
83 Properties can also be cached for the duration of one core pump cycle.
84 This is useful if the same property is likely to be fetched multiple times in one cycle. For example, several NVDAObject properties are fetched by both braille and speech.
85 Setting _cache_x to C{True} specifies that x should be cached. Setting it to C{False} specifies that it should not be cached.
86 If _cache_x is not set, L{cachePropertiesByDefault} is used.
87 """
88 __metaclass__=AutoPropertyType
89
90
91
92 __instances=weakref.WeakKeyDictionary()
93
94
95
96 cachePropertiesByDefault = False
97
99
100
101 self._propertyCache={}
102 self.__instances[self]=None
103
105 if not getterMethod:
106 raise ValueError("getterMethod is None")
107 try:
108 val=self._propertyCache[getterMethod]
109 except KeyError:
110 val=getterMethod(self)
111 self._propertyCache[getterMethod]=val
112 return val
113
115 self._propertyCache.clear()
116
117 @classmethod
119 """Invalidate the caches for all current instances.
120 """
121
122
123 for instance in cls.__instances.keys():
124 instance.invalidateCache()
125
127 """A class that implements NVDA's scripting interface.
128 Input gestures are bound to scripts such that the script will be executed when the appropriate input gesture is received.
129 Scripts are methods named with a prefix of C{script_}; e.g. C{script_foo}.
130 They accept an L{inputCore.InputGesture} as their single argument.
131 Gesture bindings can be specified on the class by creating a C{__gestures} dict which maps gesture identifiers to script names.
132 They can also be bound on an instance using the L{bindGesture} method.
133 """
134
136
137
138 self._gestureMap = {}
139
140 for cls in self.__class__.__mro__:
141 try:
142 self.bindGestures(getattr(cls, "_%s__gestures" % cls.__name__))
143 except AttributeError:
144 pass
145 super(ScriptableObject, self).__init__()
146
148 """Bind an input gesture to a script.
149 @param gestureIdentifier: The identifier of the input gesture.
150 @type gestureIdentifier: str
151 @param scriptName: The name of the script, which is the name of the method excluding the C{script_} prefix.
152 @type scriptName: str
153 @raise LookupError: If there is no script with the provided name.
154 """
155
156
157 func = getattr(self.__class__, "script_%s" % scriptName, None)
158 if not func:
159 raise LookupError("No such script: %s" % func)
160
161 import inputCore
162 self._gestureMap[inputCore.normalizeGestureIdentifier(gestureIdentifier)] = func
163
165 """Remove all input gesture bindings from this object.
166 """
167 self._gestureMap.clear()
168
170 """Bind multiple input gestures to scripts.
171 This is a convenience method which simply calls L{bindGesture} for each gesture and script pair, logging any errors.
172 @param gestureMap: A mapping of gesture identifiers to script names.
173 @type gestureMap: dict of str to str
174 """
175 for gestureIdentifier, scriptName in gestureMap.iteritems():
176 try:
177 self.bindGesture(gestureIdentifier, scriptName)
178 except LookupError:
179 log.error("Error binding script %s in %r" % (scriptName, self))
180
182 """Retrieve the script bound to a given gesture.
183 @param gesture: The input gesture in question.
184 @type gesture: L{inputCore.InputGesture}
185 @return: The script function or C{None} if none was found.
186 @rtype: script function
187 """
188 for identifier in gesture.identifiers:
189 try:
190
191 return self._gestureMap[identifier].__get__(self, self.__class__)
192 except KeyError:
193 continue
194 else:
195 return None
196