Module BrailleMonitor
[hide private]
[frames] | no frames]

Source Code for Module BrailleMonitor

  1  # coding=utf-8 
  2  ''' 
  3  This device provides a little Gtk window to monitor braille output onscreen. 
  4  It receives the exact same output as the BrlAPIDevice (if connected) and relys 
  5  on the exact same default settings inherited from L{Braille.BrailleStyle}. 
  6   
  7  Since a window is not exactly a device, we're kind of bending our own rules 
  8  here. However, implementing the braille monitor as a device seemed the most 
  9  suitable solution. 
 10   
 11  @author: Martina Weicht 
 12  @organization: IT Science Center Ruegen gGmbH, Germany 
 13  @copyright: Copyright (c) 2007, 2008 ITSC Ruegen 
 14  @license: The BSD License 
 15   
 16  All rights reserved. This program and the accompanying materials are made 
 17  available under the terms of the BSD license which accompanies 
 18  this distribution, and is available at 
 19  U{http://www.opensource.org/licenses/bsd-license.php} 
 20  ''' 
 21  import pygtk 
 22  pygtk.require('2.0') 
 23  import gtk, gobject 
 24  import os, time, logging,  array, string, re 
 25  import pango 
 26  from AccessEngine import AEInput 
 27  import Braille 
 28  from Tools.i18n import _ 
 29  from AccessEngine.AEConstants import * 
 30   
 31  __uie__ = dict(kind='device') 
 32   
 33  log = logging.getLogger('BrailleMonitor') 
 34   
35 -class BrailleMonitorStyle(Braille.BrailleStyle):
36 ''' 37 Settings for BrailleMonitor 38 @note: These are only phony settings for now. 39 40 BrailleMonitor (bool): Show braille output on braille monitor? 41 '''
42 - def init(self, device):
43 self.newBool('ShowMonitor', True, _('Show braille monitor?'), 44 _('When set, the braille monitor will be visible on-screen.')) 45 self.newBool('LargeFont', True, _('Use large font?'), 46 _('When set, a large font will be used to show Braille output \ 47 on braille monitor.')) 48 self.newBool('SmallFont', False, _('Use small font?'), 49 _('When set, a small font will be used to show Braille output \ 50 on braille monitor.'))
51 52 ''' 53 Overrides the base L{Braille.BrailleStyle} class. 54 All properties currently reside in base class. 55 '''
56 - def getGroups(self):
57 ''' 58 Gets configurable absolute settings affecting all output from this device. 59 60 @return: Root group of all configurable settings 61 @rtype: L{AEState.Setting.Group} 62 ''' 63 root = self.newGroup() 64 #if self.isDefault(): 65 ## generate a group for standard braille settings 66 #self._newBrailleGroup(root) 67 # brauchen wir die Standard-Braille-Einstellungen für den Fall, dass keine 68 # Braillezeile angeschlossen ist? Was passiert dann, wenn es eine 69 # Braillezeile gibt? Werden die Einstellungen dann doppelt geführt? 70 # Überlassen wir gemeinsame Einstellungen für Braillezeile und -monitor dann 71 # lieber dem BasicBrailleScript? 72 73 # MW: Fake-Einstellungen, zu Test- und Demozwecken 74 root.append('ShowMonitor') 75 76 g = root.newGroup(_('Font Size')) 77 g.append('LargeFont') 78 g.append('SmallFont') 79 return root
80
81 -class BrailleMonitor(Braille.Braille):
82 83 USE_THREAD = False 84 BRL_MODULE_CNT = 80 85 LABEL_MARKUP = "<span size='large'><b><tt>%s</tt></b></span>" 86 CARET_MARKUP = "<span foreground='blue' size='large'><u><b><tt>%s</tt></b></u></span>" 87 STYLE = BrailleMonitorStyle 88 # mw: roles in addition to capabilities - auslagern in Konstanten! 89 # update: braille braucht keine Role mehr! 90 # ROLE = 'monitor' 91 EOL = '\xc2\xb6' 92 TAB = ' ' 93 BRLMON_VISIBLE = False 94
95 - def init(self):
96 ''' 97 Creates and shows the monitor window and its components. 98 ''' 99 self.commands = [] 100 self.last_style = None 101 self.caretpos = 0 102 103 # populate display size properties 104 self.default_style.DisplayColumns = self.BRL_MODULE_CNT 105 self.default_style.DisplayRows = 1 106 self.default_style.TotalCells = self.BRL_MODULE_CNT 107 108 # only show BrailleMonitor if the user requested so 109 #if self.getStyle('BrailleMonitor').getSettingVal('BrailleMonitor') \ 110 # and not BrailleMonitor.BRLMON_VISIBLE: 111 if not self.BRLMON_VISIBLE: 112 self._createMonitorWindow() 113 self.BRLMON_VISIBLE = True
114 # else: can we destroy the BrailleMonitor instance? 115
116 - def postInit(self):
117 ''' 118 Called after the L{init} method and after either 119 L{AccessEngine.AEDevice.AEOutput.Base.AEOutput.loadStyles} or 120 L{AccessEngine.AEDevice.AEOutput.Base.AEOutput.createDistinctStyles}. 121 missingcellcnt is the number of missing (broken) cells defined by the user 122 and stored in the L{Setting} string "CellMask". 123 124 @note: MW: This CellMask setting is part of Braille.BrailleStyle. Since 125 BrailleMonitor inherits from Braille.Braille as does BrlAPIDevice, we are 126 able to access the braille display's settings from here. If no braille 127 display is connected, we do not want any missing cell mask set to our 128 braille monitor. Further testing is needed for this case. 129 130 @raise Error.InitError: When a communication or state problem exists for 131 the specific device 132 ''' 133 self.default_style.missingcellcnt = self.default_style.CellMask.count('0')
134 135
136 - def getDescription(self):
137 return _('Shows braille output on screen')
138
139 - def sendGetMissingCellCount(self):
140 ''' 141 @return: integer containing missing cell count 142 @rtype: integer 143 @raise NotImplementedError: When not overridden in a subclass 144 ''' 145 return self.default_style.missingcellcnt
146
147 - def sendGetEllipsisSizes(self, style):
148 ''' 149 @param style: Style with which the ellipsis are defined 150 @type style: L{AccessEngine.AEOutput.AEOutput.Style} 151 @return: tuple containing length of left and right ellipsis 152 @rtype: tuple 153 @raise NotImplementedError: When not overridden in a subclass 154 ''' 155 left = 0 156 right = 0 157 158 if self.default_style.EllipsisLeft: 159 left = len(self.EllipsisStyles[self.default_style.EllipsisStyle][0]) 160 if self.default_style.EllipsisRight: 161 right = len(self.EllipsisStyles[self.default_style.EllipsisStyle][1]) 162 163 return (left, right)
164
165 - def _createMonitorWindow(self):
166 ''' 167 Creates the window for the braille monitor by setting up as many labels as 168 there are braille modules requested along with the same number of drawing 169 areas so at some point the braille dot pattern per character may be shown 170 underneath the labels. Showing those braille dots should be made optional, 171 so the user decides whether she wants to see them or not. 172 ''' 173 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) 174 #self.window.set_keep_above(True) 175 self.window.set_transient_for(None) 176 self.window.set_title(_('BrailleMonitor')) 177 self.window.set_accept_focus(False) 178 179 # zuerst 3 vertikale Bereiche: Menuezeile, Braillebuttons und 180 # Braillepunkte (letztere sollte zu- und wegschaltbar werden!) 181 # homogeneous - all objects of same size 182 main_vbox = gtk.VBox(False, 0) 183 main_vbox.set_border_width(1) 184 self.window.add(main_vbox) 185 186 # erster Eintrag in vbox: 187 # menue fuer den Braillemonitor 188 189 # menuezeile, an die die menuepunkte angehaengt werden 190 #menu_bar = gtk.MenuBar() 191 #main_vbox.pack_start(menu_bar, False, False, 2) 192 193 ## uebergeordneter Menuepunkt 194 #file_menu = gtk.MenuItem(_("Settings")) 195 196 ## Untermenue 197 #menu = gtk.Menu() 198 199 #for i in range(3): 200 #buf = "Test-submenu - %d" % i 201 #menu_items = gtk.MenuItem(buf) 202 #menu.append(menu_items) 203 #menu_items.connect("activate", self.print_hello, buf) 204 205 ## Unterpunkte anhaengen 206 #file_menu.set_submenu(menu) 207 ## menupunkt an menuezeile anhaengen 208 #menu_bar.append(file_menu) 209 210 # zweiter eintrag in vbox: 211 # HBox fuer Braillebuttons 212 btnbox = gtk.HBox(False, 0) 213 214 # Create as many labels as there are braille modules 215 self.braillemodules = [] 216 i = 0 217 while i < self.BRL_MODULE_CNT: 218 self.braillemodules.append( gtk.Label() ) 219 self.braillemodules[i].set_markup( self.LABEL_MARKUP % ' ') 220 btnbox.pack_start( self.braillemodules[i], True, True, 0) 221 222 if i < (self.BRL_MODULE_CNT - 1): 223 btnbox.pack_start( gtk.VSeparator(), True, True, 0) 224 225 i += 1 226 227 main_vbox.add(btnbox) 228 229 # dritter Abschnitt sind genauso viele DrawingAreas wie Braillemodule, 230 # damit die Braillepunkte unterhalb der Buttons dargestellt werden koennen 231 #brlbox = gtk.HBox(True, 0) 232 233 #drawingAreas = [] 234 #i = 0 235 #while i < BrailleMonitor.BRL_MODULE_CNT: 236 #drawingAreas.append( gtk.DrawingArea() ) 237 ##self.draw_points(drawingAreas[i], 0, 0) 238 #brlbox.pack_start( drawingAreas[i], True, True, 0) 239 #i += 1 240 241 #main_vbox.add( brlbox ) 242 243 self.window.show_all()
244 245
246 - def sendString(self, text, style):
247 ''' 248 Adds the given text and associated style to command list. Text will be 249 output to the braille device in sendTalk. 250 251 @param text: String to be output 252 @type text: string 253 @param style: Style with which this string should be output; None means no 254 style change should be applied 255 @type style: integer 256 ''' 257 self.commands.append((CMD_STRING, text, style))
258
259 - def sendTalk(self, style=None):
260 ''' 261 Iterates through list of commands and builds output string including user 262 selected ellipsis and caret. 263 264 @param style: Ignored 265 @type style: L{AccessEngine.AEOutput.AEOutput.Style} 266 ''' 267 stream = [] 268 truncateleft = False 269 truncateright = False 270 # iterate through commands and build pre-output string and set local vars 271 for command, value, style in self.commands: 272 if style is not None and (style.isDirty() or self.last_style != style): 273 self.last_style = style 274 if command is CMD_STRING: 275 if value is not None: 276 stream.append(value) 277 elif command is CMD_TRUNCATE: 278 truncateleft = value[0] 279 truncateright = value[1] 280 281 # get preliminary output string as an array of unicode 282 outarray = array.array('u', ''.join(stream)) 283 284 self._clear() 285 self._showText(outarray) 286 287 self.commands = []
288 289
290 - def sendStop(self, style=None):
291 ''' 292 Stops braille output immediately. 293 294 @param style: Ignored 295 @type style: L{AccessEngine.AEOutput.AEOutput.Style} 296 ''' 297 self.commands = []
298 299
300 - def print_hello(self, x, data):
301 ''' 302 Nur zum Testen der Untermenüs 303 ''' 304 print 'Test submenu'
305 306
307 - def _clear(self):
308 ''' 309 Clears Braille monitor of all contents. 310 ''' 311 i = 0 312 while i < self.BRL_MODULE_CNT: 313 self.braillemodules[i].set_label( ' ' ) 314 i += 1
315 316
317 - def _showText(self, textArray):
318 ''' 319 Set the given text as labels 320 321 @note: MW: For now the caret on the BrailleMonitor will be styled according 322 to some fixed mark-up. Once a settings dialog has been created for the 323 BrailleMonitor, this needs to be changed. 324 325 @param textArray: The text do be displayed 326 @type textArray: array 327 ''' 328 # TODO: in gcalc Focus auf Button < 329 # Fehler: 347: GtkWarning: 330 # Failed to set text from markup due to error parsing markup: 331 # Fehler in Zeile 1, Zeichen 36: »<« ist kein gültiges Zeichen nach 332 # einem »<«-Zeichen; es darf keinen Elementnamen beginnen 333 # self.braillemodules[i].set_markup( self.LABEL_MARKUP % textArray[i] ) 334 335 i = 0 336 while i < len(textArray) and i < self.BRL_MODULE_CNT: 337 if i == self.caretpos: 338 self.braillemodules[i].set_markup( self.CARET_MARKUP % textArray[i] ) 339 else: 340 self.braillemodules[i].set_markup( self.LABEL_MARKUP % textArray[i] ) 341 i += 1
342 343
344 - def parseString(self, text, style, por, sem):
345 ''' 346 Overwrites the same method in Braille.Braille 347 Is this the correct place to replace tab and eol characters? 348 349 @param text: Text to be parsed 350 @type text: string 351 @param style: Style object defining how the text should be parsed 352 @type style: L{AccessEngine.AEOutput.AEOutput.Style} 353 @param por: Point of regard for the first character in the text, or None if 354 the text is not associated with a POR 355 @type por: L{AEPor} 356 @param sem: Semantic tag for the text 357 @type sem: integer 358 @return: Parsed words 359 @rtype: 3-tuple of lists of string, L{AEPor}, 360 L{AccessEngine.AEOutput.AEOutput.Style} 361 ''' 362 # parse the string using the current style 363 # Sonderzeichen einstellbar machen? 364 text = text.replace('\n', self.EOL) 365 text = text.replace('\t', self.TAB) 366 367 return [(text, por, style)]
368 369
370 - def sendCaret(self, pos, style):
371 ''' 372 Sends the current caret position relative to the first cell (zero-offset) 373 on the device. The style object is used by the device in deciding how the 374 caret should be presented. 375 376 @note: braille monitor is zero-based. No offset here. 377 @param pos: Zero-offset cell position of the caret, up to the device to 378 change to one-offset if need be 379 @type pos: string 380 @param style: Style with which the caret should be indicated 381 @type style: L{AccessEngine.AEOutput.AEOutput.Style} 382 @raise NotImplementedError: When not overridden in a subclass 383 ''' 384 self.caretpos = pos
385
386 - def close(self):
387 ''' 388 Closes the braille monitor. 389 ''' 390 self.window.destroy() 391 self.window = None 392 self.commands = [] 393 self.BRLMON_VISIBLE = False
394