1 '''
2 Defines the base class for all L{AEOutput} devices.
3
4 @author: Larry Weiss
5 @author: Peter Parente
6 @author: Brett Clippingdale
7 @organization: IBM Corporation
8 @copyright: Copyright (c) 2005, 2007 IBM Corporation
9 @license: The BSD License
10
11 @author: Frank Zenker
12 @author: Martina Weicht
13 @author: Ramona Bunk
14 @organization: IT Science Center Ruegen gGmbH, Germany
15 @copyright: Copyright (c) 2007, 2008 ITSC Ruegen
16 @license: The BSD License
17
18 All rights reserved. This program and the accompanying materials are made
19 available under the terms of the BSD license which accompanies
20 this distribution, and is available at
21 U{http://www.opensource.org/licenses/bsd-license.php}
22 '''
23 import AccessEngine
24 from AccessEngine import AEUserInterface, AEConstants
25 import Style
26
28 '''
29 Suggests the default L{AEOutput}s events to be monitored.
30
31 @return: Names of defaults to monitor
32 @rtype: list of string
33 '''
34 return AEConstants.OUTPUT_COMMAND_NAMES.values()
35
49
50 -class AEOutput(AEUserInterface.AEUserInterface):
51 '''
52 Defines the base class for all output devices. All output devices used by
53 SUE should derive from this class and should implement the methods defined
54 here. All methods defined here raise NotImplementedError to ensure that
55 derived classes create appropriate implementions.
56
57 @cvar STYLE: Style class to use when constructing style objects for this
58 device. A subclass with configurable device settings should
59 override the default value (L{AEOutput.Style}) with a reference to
60 its own default class defining default values for all device properties.
61 @type STYLE: L{AEOutput.Style} class
62 @cvar USE_THREAD: Should this device use a separate thread to queue output?
63 Devices that block while doing output (e.g. serial Braille device) should
64 use a thread to keep the main thread unlocked and responsive. Defaults to
65 None so a subclass must override it with an explicit boolean value.
66 @type USE_THREAD: boolean
67 @cvar COMMAND_CHARS: String of characters that are treated as commands on the
68 device implementing this interface. These characters are replaced with
69 blanks in any string sent to the device.
70 @type COMMAND_CHARS: string
71 @ivar styles: Mapping from arbitrary, immutable keys to style objects
72 @type styles: dictionary
73 '''
74 USE_THREAD = None
75 COMMAND_CHARS = ''
76 STYLE = Style.Style
77
78 ROLE = 'output'
79
81 '''
82 Initializes the styles dictionary and default style object.
83 '''
84 self.styles = {}
85
86
87 self.default_style = self.STYLE()
88
90 '''
91 Gets a list of strings representing the capabilities of this device.
92 Typical output capabilities include "audio" and "braille" though others are
93 certainly possible.
94
95 The L{AEDeviceManager} will only load a device if another device doesn't
96 already provide all of its capabilities.
97
98 @return: Lowercase names of output capabilities
99 @rtype: list of string
100 '''
101 raise NotImplementedError
102
104 '''
105 Called after the L{init} method by the L{AEDeviceManager} to ensure that the
106 device is functioning before time is spent unserializing its style data.
107
108 Calls the init method on the default style object and provides it with a
109 reference to this initialized device. Then tries to load the persisted
110 setting values from disk. If that fails, the L{AEDeviceManager} will try to
111 call L{createDistinctStyles} instead.
112
113 @note: This method should not be overriden by a subclass. See L{postInit}
114 if you need to run code after the styles are created or restored from
115 disk.
116 @raise KeyError: When styles have not previously been persisted for this
117 device
118 @raise OSError: When the profile file cannot be opened or read
119 '''
120 self.default_style.init(self)
121
122 self.styles = AccessEngine.AESettingsManager.loadStyles(self, self.default_style,
123 self.STYLE)
124
126 '''
127 Persists styles to disk. Called after the L{close} method by the
128 L{AEDeviceManager} to ensure the device is properly shutdown before
129 serializing its data.
130
131 @note: This method should not be overriden by a subclass.
132 @raise KeyError: When styles have not previously been persisted for this
133 device
134 @raise OSError: When the profile file cannot be opened or read
135 '''
136
137 AccessEngine.AESettingsManager.saveStyles(self, self.default_style, self.styles)
138
140 '''
141 Stores the style object under the given key. The style object should be
142 one previously generated by this device (e.g. using
143 L{createDistinctStyles}) but it is not an enforced requirement. Always
144 makes the style clean before storing it.
145
146 @param key: Any immutable object
147 @type key: immutable
148 @param style: L{AEOutput} subclass of L{AEState}
149 @type style: L{AEState}
150 '''
151 style.makeClean()
152 self.styles[key] = style
153
155 '''
156 Gets the style object stored under the given key. If the key is unknown,
157 returns an empty flyweight backed by the default style and stores the
158 new style in L{styles}.
159
160 @param key: Any immutable object
161 @type key: immutable
162 @return: L{AEOutput} subclass of L{AEState}
163 @rtype: L{AEState}
164 '''
165 try:
166 return self.styles[key]
167 except KeyError:
168
169 st = self.STYLE(self.default_style)
170
171 st.init(self)
172 self.styles[key] = st
173 return st
174
176 '''
177 Gets the default style of the device.
178
179 @return: Default style of the device
180 @rtype: L{AEOutput.Style}
181 '''
182 return self.default_style
183
185 '''
186 Creates a default set of distinct styles for this device. The device should
187 instantiate L{AEOutput.Style} objects having properties that reflect the
188 capabilities of this device, leaving any unsupported fields set to the
189 value of None. A total number of num_groups + num_layers style objects
190 should be returned.
191
192 The properties of the style object should be set so as to distinguish
193 content presented using the style. For instance, audio devices may
194 distinguish styles in the following recommended manner:
195
196 - Create a total of num_groups styles with different voices and pitches.
197 - If the device supports multiple channels,
198 - Duplicate the styles num_layers times assigning each set of
199 duplicates to the same channel.
200 - If the device does not support multiple channels,
201 - Duplicate the styles num_layers times.
202
203 For Braille and magnification devices, don't implement this method unless
204 you have some creative way of making the device respond differently to the
205 semantic tags defined in L{AEConstants}.
206
207 The total number of requested styles (num_groups * num_layers) must be
208 returned. If the device cannot honor the request for the number of distinct
209 styles it is asked to generate, it may duplicate styles it has already
210 created using L{AEState.Base.AEState.copy} to fulfill the quota.
211
212 The device is B{not} expected to create distinct styles across invocations
213 of this method. This method should only be called once by L{AEDeviceManager}
214 to create a default set of styles for the device if the manager cannot load
215 previously persisted settings from disk. If this method is not implemented,
216 calls to L{getStyle} during normal operation of the L{AEDeviceManager} will
217 end up making copies based on the default style.
218
219 @param num_groups: Number of sematic groups the requestor would like to
220 represent using distinct styles
221 @type num_groups: integer
222 @param num_layers: Number of content origins (e.g. output originating from
223 a background task versus the focus) the requestor would like to represent
224 using distinct styles
225 @type num_layers: integer
226 @return: New styles
227 @rtype: list of L{AEOutput.Style}
228 @raise NotImplementedError: When not overridden in a subclass
229 '''
230 raise NotImplementedError
231
233 '''
234 Called after the instance is created to initialize the device.
235 May be called to re-initialize the device after a call to L{close}.
236
237 @raise NotImplementedError: When not overridden in a subclass
238 @raise Error.InitError: When a communication or state problem exists for
239 the specific device
240 '''
241 raise NotImplementedError
242
243 - def postInit(self):
244 '''
245 Called after the L{init} method and after either L{loadStyles} or
246 L{createDistinctStyles}. Override this method to perform additional
247 initilization after the setting values are available.
248
249 @raise Error.InitError: When a communication or state problem exists for
250 the specific device
251 '''
252 pass
253
255 '''
256 Closes an initialized output device.
257
258 @raise NotImplementedError: When not overridden in a subclass
259 '''
260 raise NotImplementedError
261
263 '''
264 Gets the object that the L{AEDeviceManager} will use to communicate with this
265 device. The returned object may either be a proxy (e.g. a thread) or this
266 device itself.
267
268 @return: An output object that implements this class
269 @rtype: L{AEOutput}
270 @raise NotImplementedError: When not overridden in a subclass
271 '''
272 raise NotImplementedError
273
274 - def send(self, name, value, style=None):
275 '''
276 Sends arbitrary data to a device. The device must recognize the name in
277 order to decide what to do with the value data. If given, the style object
278 is used to decide how the data should be presented if it is content to be
279 rendered.
280
281 This is a generic method which receives all content and commands to be
282 rendered and executed on a device. Standard name identifiers should be
283 used whenever possible. For instance, L{AEConstants.Output.CMD_STOP} and
284 L{AEConstants.Output.CMD_TALK}. However, device specific names and values
285 are certainly possible.
286
287 @param name: Descriptor of the data value sent
288 @type name: object
289 @param value: Content value
290 @type value: object
291 @param style: Style with which this value should be output
292 @type style: L{AEOutput.Style}
293 @return: Return value specific to the given command
294 @rtype: object
295 @raise NotImplementedError: When not overridden in a subclass
296 '''
297 raise NotImplementedError
298
300 '''
301 Indicates whether the device is active (e.g. giving output, has buffered
302 content to output, is otherwise busy) or not.
303
304 @return: True when active, False when not
305 @rtype: boolean
306 @raise NotImplementedError: When not overriden in a subclass
307 '''
308 raise NotImplementedError
309
311 '''
312 Gets the role of this device
313
314 @rtype: string
315 '''
316 return self.ROLE
317