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

Source Code for Module editableText

  1  #editableText.py 
  2  #A part of NonVisual Desktop Access (NVDA) 
  3  #This file is covered by the GNU General Public License. 
  4  #See the file COPYING for more details. 
  5  #Copyright (C) 2006-2010 Michael Curran <mick@kulgan.net>, James Teh <jamie@jantrid.net> 
  6   
  7  """Common support for editable text. 
  8  @note: If you want editable text functionality for an NVDAObject, 
  9          you should use the EditableText classes in L{NVDAObjects.behaviors}. 
 10  """ 
 11   
 12  import time 
 13  import api 
 14  from baseObject import ScriptableObject 
 15  import braille 
 16  import speech 
 17  import config 
 18  import eventHandler 
 19  from scriptHandler import isScriptWaiting 
 20  import textInfos 
 21   
22 -class EditableText(ScriptableObject):
23 """Provides scripts to report appropriately when moving the caret in editable text fields. 24 This does not handle the selection change keys. 25 To have selection changes reported, the object must notify of selection changes. 26 If the object supports selection but does not notify of selection changes, L{EditableTextWithoutAutoSelectDetection} should be used instead. 27 28 If the object notifies of selection changes, the following should be done: 29 * When the object gains focus, L{initAutoSelectDetection} must be called. 30 * When the object notifies of a possible selection change, L{detectPossibleSelectionChange} must be called. 31 * Optionally, if the object notifies of changes to its content, L{hasContentChangedSinceLastSelection} should be set to C{True}. 32 @ivar hasContentChangedSinceLastSelection: Whether the content has changed since the last selection occurred. 33 @type hasContentChangedSinceLastSelection: bool 34 """ 35 36 #: Whether to fire caretMovementFailed events when the caret doesn't move in response to a caret movement key. 37 shouldFireCaretMovementFailedEvents = False 38
39 - def _hasCaretMoved(self, bookmark, retryInterval=0.01, timeout=0.03):
40 """ 41 Waits for the caret to move, for a timeout to elapse, or for a new focus event or script to be queued. 42 @param bookmark: a bookmark representing the position of the caret before it was instructed to move 43 @type bookmark: bookmark 44 @param retryInterval: the interval of time in seconds this method should wait before checking the caret each time. 45 @type retryInterval: float 46 @param timeout: the over all amount of time in seconds the method should wait before giving up completely. 47 @type timeout: float 48 @return: a tuple containing a boolean denoting whether this method timed out, and a TextInfo representing the old or updated caret position or None if interupted by a script or focus event. 49 @rtype: tuple 50 """ 51 elapsed = 0 52 newInfo=None 53 while elapsed < timeout: 54 if isScriptWaiting(): 55 return (False,None) 56 api.processPendingEvents(processEventQueue=False) 57 if eventHandler.isPendingEvents("gainFocus"): 58 return (True,None) 59 #The caret may stop working as the focus jumps, we want to stay in the while loop though 60 try: 61 newInfo = self.makeTextInfo(textInfos.POSITION_CARET) 62 newBookmark = newInfo.bookmark 63 except (RuntimeError,NotImplementedError): 64 newInfo=None 65 else: 66 if newBookmark!=bookmark: 67 return (True,newInfo) 68 time.sleep(retryInterval) 69 elapsed += retryInterval 70 return (False,newInfo)
71
72 - def _caretScriptPostMovedHelper(self, speakUnit, info=None):
73 if isScriptWaiting(): 74 return 75 if not info: 76 try: 77 info = self.makeTextInfo(textInfos.POSITION_CARET) 78 except: 79 return 80 if config.conf["reviewCursor"]["followCaret"] and api.getNavigatorObject() is self: 81 api.setReviewPosition(info) 82 if speakUnit: 83 info.expand(speakUnit) 84 speech.speakTextInfo(info, unit=speakUnit, reason=speech.REASON_CARET)
85
86 - def _caretMovementScriptHelper(self, gesture, unit):
87 try: 88 info=self.makeTextInfo(textInfos.POSITION_CARET) 89 except: 90 gesture.send() 91 return 92 bookmark=info.bookmark 93 gesture.send() 94 caretMoved,newInfo=self._hasCaretMoved(bookmark) 95 if not caretMoved and self.shouldFireCaretMovementFailedEvents: 96 eventHandler.executeEvent("caretMovementFailed", self, gesture=gesture) 97 self._caretScriptPostMovedHelper(unit,newInfo)
98
99 - def script_caret_moveByLine(self,gesture):
101
102 - def script_caret_moveByCharacter(self,gesture):
104
105 - def script_caret_moveByWord(self,gesture):
107
108 - def script_caret_moveByParagraph(self,gesture):
110
111 - def _backspaceScriptHelper(self,unit,gesture):
112 try: 113 oldInfo=self.makeTextInfo(textInfos.POSITION_CARET) 114 except: 115 gesture.send() 116 return 117 oldBookmark=oldInfo.bookmark 118 testInfo=oldInfo.copy() 119 res=testInfo.move(textInfos.UNIT_CHARACTER,-1) 120 if res<0: 121 testInfo.expand(unit) 122 delChunk=testInfo.text 123 else: 124 delChunk="" 125 gesture.send() 126 caretMoved,newInfo=self._hasCaretMoved(oldBookmark) 127 if not caretMoved: 128 return 129 if len(delChunk)>1: 130 speech.speakMessage(delChunk) 131 else: 132 speech.speakSpelling(delChunk) 133 self._caretScriptPostMovedHelper(None,newInfo)
134
135 - def script_caret_backspaceCharacter(self,gesture):
137
138 - def script_caret_backspaceWord(self,gesture):
140
141 - def script_caret_delete(self,gesture):
142 try: 143 info=self.makeTextInfo(textInfos.POSITION_CARET) 144 except: 145 gesture.send() 146 return 147 bookmark=info.bookmark 148 gesture.send() 149 # We'll try waiting for the caret to move, but we don't care if it doesn't. 150 caretMoved,newInfo=self._hasCaretMoved(bookmark) 151 self._caretScriptPostMovedHelper(textInfos.UNIT_CHARACTER,newInfo) 152 braille.handler.handleCaretMove(self)
153 154 __gestures = { 155 "kb:upArrow": "caret_moveByLine", 156 "kb:downArrow": "caret_moveByLine", 157 "kb:leftArrow": "caret_moveByCharacter", 158 "kb:rightArrow": "caret_moveByCharacter", 159 "kb:pageUp": "caret_moveByLine", 160 "kb:pageDown": "caret_moveByLine", 161 "kb:control+leftArrow": "caret_moveByWord", 162 "kb:control+rightArrow": "caret_moveByWord", 163 "kb:control+upArrow": "caret_moveByParagraph", 164 "kb:control+downArrow": "caret_moveByParagraph", 165 "kb:home": "caret_moveByCharacter", 166 "kb:end": "caret_moveByCharacter", 167 "kb:control+home": "caret_moveByLine", 168 "kb:control+end": "caret_moveByLine", 169 "kb:delete": "caret_delete", 170 "kb:numpadDelete": "caret_delete", 171 "kb:backspace": "caret_backspaceCharacter", 172 "kb:control+backspace": "caret_backspaceWord", 173 } 174
175 - def initAutoSelectDetection(self):
176 """Initialise automatic detection of selection changes. 177 This should be called when the object gains focus. 178 """ 179 try: 180 self._lastSelectionPos=self.makeTextInfo(textInfos.POSITION_SELECTION) 181 except: 182 self._lastSelectionPos=None 183 self.hasContentChangedSinceLastSelection=False
184
186 """Detects if the selection has been changed, and if so it speaks the change. 187 """ 188 try: 189 newInfo=self.makeTextInfo(textInfos.POSITION_SELECTION) 190 except: 191 # Just leave the old selection, which is usually better than nothing. 192 return 193 oldInfo=getattr(self,'_lastSelectionPos',None) 194 self._lastSelectionPos=newInfo.copy() 195 if not oldInfo: 196 # There's nothing we can do, but at least the last selection will be right next time. 197 return 198 hasContentChanged=getattr(self,'hasContentChangedSinceLastSelection',False) 199 self.hasContentChangedSinceLastSelection=False 200 speech.speakSelectionChange(oldInfo,newInfo,generalize=hasContentChanged)
201
202 -class EditableTextWithoutAutoSelectDetection(EditableText):
203 """In addition to L{EditableText}, provides scripts to report appropriately when the selection changes. 204 This should be used when an object does not notify of selection changes. 205 """ 206
207 - def script_caret_changeSelection(self,gesture):
208 try: 209 oldInfo=self.makeTextInfo(textInfos.POSITION_SELECTION) 210 except: 211 gesture.send() 212 return 213 gesture.send() 214 if isScriptWaiting() or eventHandler.isPendingEvents("gainFocus"): 215 return 216 api.processPendingEvents(processEventQueue=False) 217 try: 218 newInfo=self.makeTextInfo(textInfos.POSITION_SELECTION) 219 except: 220 return 221 speech.speakSelectionChange(oldInfo,newInfo)
222 223 __changeSelectionGestures = ( 224 "kb:shift+upArrow", 225 "kb:shift+downArrow", 226 "kb:shift+leftArrow", 227 "kb:shift+rightArrow", 228 "kb:shift+pageUp", 229 "kb:shift+pageDown", 230 "kb:shift+control+leftArrow", 231 "kb:shift+control+rightArrow", 232 "kb:shift+control+upArrow", 233 "kb:shift+control+downArrow", 234 "kb:shift+home", 235 "kb:shift+end", 236 "kb:shift+control+home", 237 "kb:shift+control+end", 238 "kb:control+a", 239 ) 240
241 - def initClass(self):
242 for gesture in self.__changeSelectionGestures: 243 self.bindGesture(gesture, "caret_changeSelection")
244