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

Source Code for Module cursorManager

  1  #cursorManager.py 
  2  #A part of NonVisual Desktop Access (NVDA) 
  3  #Copyright (C) 2006-2008 NVDA Contributors <http://www.nvda-project.org/> 
  4  #This file is covered by the GNU General Public License. 
  5  #See the file COPYING for more details. 
  6   
  7  """ 
  8  Implementation of cursor managers. 
  9  A cursor manager provides caret navigation and selection commands for a virtual text range. 
 10  """ 
 11   
 12  import wx 
 13  import baseObject 
 14  import gui 
 15  import textInfos 
 16  import api 
 17  import speech 
 18  import config 
 19  import braille 
 20   
21 -class CursorManager(baseObject.ScriptableObject):
22 """ 23 A mix-in providing caret navigation and selection commands for the object's virtual text range. 24 This is required where a text range is not linked to a physical control and thus does not provide commands to move the cursor, select and copy text, etc. 25 This base cursor manager requires that the text range being used stores its own caret and selection information. 26 27 This is a mix-in class; i.e. it should be inherited alongside another L{baseObject.ScriptableObject}. 28 The class into which it is inherited must provide a C{makeTextInfo(position)} method. 29 30 @ivar selection: The current caret/selection range. 31 @type selection: L{textInfos.TextInfo} 32 """ 33 34 _lastFindText="" 35
36 - def __init__(self, *args, **kwargs):
37 super(CursorManager, self).__init__(*args, **kwargs) 38 self.initCursorManager()
39
40 - def initOverlayClass(self):
41 """Performs automatic initialisation if this is being used as an overlay class.""" 42 self.initCursorManager()
43
44 - def initCursorManager(self):
45 """Initialise this cursor manager. 46 This must be called before the cursor manager functionality can be used. 47 It is normally called by L{__init__} or L{initOverlayClass}. 48 """ 49 self._lastSelectionMovedStart=False
50
51 - def _get_selection(self):
53
54 - def _set_selection(self, info):
57
58 - def _caretMovementScriptHelper(self,unit,direction=None,posConstant=textInfos.POSITION_SELECTION,posUnit=None,posUnitEnd=False,extraDetail=False,handleSymbols=False):
59 oldInfo=self.makeTextInfo(posConstant) 60 info=oldInfo.copy() 61 info.collapse(end=not self._lastSelectionMovedStart) 62 if not self._lastSelectionMovedStart and not oldInfo.isCollapsed: 63 info.move(textInfos.UNIT_CHARACTER,-1) 64 if posUnit is not None: 65 info.expand(posUnit) 66 info.collapse(end=posUnitEnd) 67 if posUnitEnd: 68 info.move(textInfos.UNIT_CHARACTER,-1) 69 if direction is not None: 70 info.expand(unit) 71 info.collapse(end=posUnitEnd) 72 info.move(unit,direction) 73 self.selection=info 74 info.expand(unit) 75 speech.speakTextInfo(info,unit=unit,reason=speech.REASON_CARET) 76 if not oldInfo.isCollapsed: 77 speech.speakSelectionChange(oldInfo,self.selection)
78
79 - def doFindTextDialog(self):
80 d = wx.TextEntryDialog(gui.mainFrame, _("Type the text you wish to find"), _("Find"), defaultValue=self._lastFindText) 81 def callback(result): 82 if result == wx.ID_OK: 83 # Make sure this happens after focus returns to the document. 84 wx.CallLater(100, self.doFindText, d.GetValue())
85 gui.runScriptModalDialog(d, callback)
86
87 - def doFindText(self,text,reverse=False):
88 if not text: 89 return 90 info=self.makeTextInfo(textInfos.POSITION_CARET) 91 res=info.find(text,reverse=reverse) 92 if res: 93 self.selection=info 94 speech.cancelSpeech() 95 info.move(textInfos.UNIT_LINE,1,endPoint="end") 96 speech.speakTextInfo(info,reason=speech.REASON_CARET) 97 else: 98 wx.CallAfter(gui.messageBox,_('text "%s" not found')%text,_("Find Error"),wx.OK|wx.ICON_ERROR) 99 CursorManager._lastFindText=text
100
101 - def script_find(self,gesture):
102 self.doFindTextDialog() 103 script_find.__doc__ = _("find a text string from the current cursor position") 104
105 - def script_findNext(self,gesture):
106 if not self._lastFindText: 107 self.doFindTextDialog() 108 return 109 self.doFindText(self._lastFindText)
110 script_findNext.__doc__ = _("find the next occurrence of the previously entered text string from the current cursor's position") 111
112 - def script_findPrevious(self,gesture):
113 if not self._lastFindText: 114 self.doFindTextDialog() 115 return 116 self.doFindText(self._lastFindText,reverse=True)
117 script_findPrevious.__doc__ = _("find the previous occurrence of the previously entered text string from the current cursor's position") 118
119 - def script_moveByPage_back(self,gesture):
120 self._caretMovementScriptHelper(textInfos.UNIT_LINE,-config.conf["virtualBuffers"]["linesPerPage"],extraDetail=False)
121
122 - def script_moveByPage_forward(self,gesture):
123 self._caretMovementScriptHelper(textInfos.UNIT_LINE,config.conf["virtualBuffers"]["linesPerPage"],extraDetail=False)
124
125 - def script_moveByCharacter_back(self,gesture):
126 self._caretMovementScriptHelper(textInfos.UNIT_CHARACTER,-1,extraDetail=True,handleSymbols=True)
127
128 - def script_moveByCharacter_forward(self,gesture):
129 self._caretMovementScriptHelper(textInfos.UNIT_CHARACTER,1,extraDetail=True,handleSymbols=True)
130
131 - def script_moveByWord_back(self,gesture):
132 self._caretMovementScriptHelper(textInfos.UNIT_WORD,-1,extraDetail=True,handleSymbols=True)
133
134 - def script_moveByWord_forward(self,gesture):
135 self._caretMovementScriptHelper(textInfos.UNIT_WORD,1,extraDetail=True,handleSymbols=True)
136
137 - def script_moveByLine_back(self,gesture):
138 self._caretMovementScriptHelper(textInfos.UNIT_LINE,-1)
139
140 - def script_moveByLine_forward(self,gesture):
141 self._caretMovementScriptHelper(textInfos.UNIT_LINE,1)
142
143 - def script_moveByParagraph_back(self,gesture):
144 self._caretMovementScriptHelper(textInfos.UNIT_PARAGRAPH,-1)
145
146 - def script_moveByParagraph_forward(self,gesture):
147 self._caretMovementScriptHelper(textInfos.UNIT_PARAGRAPH,1)
148
149 - def script_startOfLine(self,gesture):
150 self._caretMovementScriptHelper(textInfos.UNIT_CHARACTER,posUnit=textInfos.UNIT_LINE,extraDetail=True,handleSymbols=True)
151
152 - def script_endOfLine(self,gesture):
153 self._caretMovementScriptHelper(textInfos.UNIT_CHARACTER,posUnit=textInfos.UNIT_LINE,posUnitEnd=True,extraDetail=True,handleSymbols=True)
154
155 - def script_topOfDocument(self,gesture):
156 self._caretMovementScriptHelper(textInfos.UNIT_LINE,posConstant=textInfos.POSITION_FIRST)
157
158 - def script_bottomOfDocument(self,gesture):
159 self._caretMovementScriptHelper(textInfos.UNIT_LINE,posConstant=textInfos.POSITION_LAST)
160
161 - def _selectionMovementScriptHelper(self,unit=None,direction=None,toPosition=None):
162 oldInfo=self.makeTextInfo(textInfos.POSITION_SELECTION) 163 if toPosition: 164 newInfo=self.makeTextInfo(toPosition) 165 if newInfo.compareEndPoints(oldInfo,"startToStart")>0: 166 newInfo.setEndPoint(oldInfo,"startToStart") 167 if newInfo.compareEndPoints(oldInfo,"endToEnd")<0: 168 newInfo.setEndPoint(oldInfo,"endToEnd") 169 elif unit: 170 newInfo=oldInfo.copy() 171 if unit: 172 if self._lastSelectionMovedStart: 173 newInfo.move(unit,direction,endPoint="start") 174 else: 175 newInfo.move(unit,direction,endPoint="end") 176 self.selection = newInfo 177 if newInfo.compareEndPoints(oldInfo,"startToStart")!=0: 178 self._lastSelectionMovedStart=True 179 else: 180 self._lastSelectionMovedStart=False 181 if newInfo.compareEndPoints(oldInfo,"endToEnd")!=0: 182 self._lastSelectionMovedStart=False 183 speech.speakSelectionChange(oldInfo,newInfo)
184
185 - def script_selectCharacter_forward(self,gesture):
186 self._selectionMovementScriptHelper(unit=textInfos.UNIT_CHARACTER,direction=1)
187
188 - def script_selectCharacter_back(self,gesture):
189 self._selectionMovementScriptHelper(unit=textInfos.UNIT_CHARACTER,direction=-1)
190
191 - def script_selectWord_forward(self,gesture):
192 self._selectionMovementScriptHelper(unit=textInfos.UNIT_WORD,direction=1)
193
194 - def script_selectWord_back(self,gesture):
195 self._selectionMovementScriptHelper(unit=textInfos.UNIT_WORD,direction=-1)
196
197 - def script_selectLine_forward(self,gesture):
198 self._selectionMovementScriptHelper(unit=textInfos.UNIT_LINE,direction=1)
199
200 - def script_selectLine_back(self,gesture):
201 self._selectionMovementScriptHelper(unit=textInfos.UNIT_LINE,direction=-1)
202
203 - def script_selectPage_forward(self,gesture):
204 self._selectionMovementScriptHelper(unit=textInfos.UNIT_LINE,direction=config.conf["virtualBuffers"]["linesPerPage"])
205
206 - def script_selectPage_back(self,gesture):
207 self._selectionMovementScriptHelper(unit=textInfos.UNIT_LINE,direction=-config.conf["virtualBuffers"]["linesPerPage"])
208
209 - def script_selectParagraph_forward(self, gesture):
210 self._selectionMovementScriptHelper(unit=textInfos.UNIT_PARAGRAPH, direction=1)
211
212 - def script_selectParagraph_back(self, gesture):
213 self._selectionMovementScriptHelper(unit=textInfos.UNIT_PARAGRAPH, direction=-1)
214
215 - def script_selectToBeginningOfLine(self,gesture):
216 curInfo=self.makeTextInfo(textInfos.POSITION_SELECTION) 217 curInfo.collapse() 218 tempInfo=curInfo.copy() 219 tempInfo.expand(textInfos.UNIT_LINE) 220 if curInfo.compareEndPoints(tempInfo,"startToStart")>0: 221 self._selectionMovementScriptHelper(unit=textInfos.UNIT_LINE,direction=-1)
222
223 - def script_selectToEndOfLine(self,gesture):
224 curInfo=self.makeTextInfo(textInfos.POSITION_SELECTION) 225 curInfo.collapse() 226 tempInfo=curInfo.copy() 227 curInfo.expand(textInfos.UNIT_CHARACTER) 228 tempInfo.expand(textInfos.UNIT_LINE) 229 if curInfo.compareEndPoints(tempInfo,"endToEnd")<0: 230 self._selectionMovementScriptHelper(unit=textInfos.UNIT_LINE,direction=1)
231
232 - def script_selectToTopOfDocument(self,gesture):
233 self._selectionMovementScriptHelper(toPosition=textInfos.POSITION_FIRST)
234
235 - def script_selectToBottomOfDocument(self,gesture):
236 self._selectionMovementScriptHelper(toPosition=textInfos.POSITION_LAST,unit=textInfos.UNIT_CHARACTER,direction=1)
237
238 - def script_selectAll(self,gesture):
239 self._selectionMovementScriptHelper(toPosition=textInfos.POSITION_ALL)
240
241 - def script_copyToClipboard(self,gesture):
242 info=self.makeTextInfo(textInfos.POSITION_SELECTION) 243 if info.isCollapsed: 244 speech.speakMessage(_("no selection")) 245 return 246 if info.copyToClipboard(): 247 speech.speakMessage(_("copied to clipboard"))
248 249 __gestures = { 250 "kb:pageUp": "moveByPage_back", 251 "kb:pageDown": "moveByPage_forward", 252 "kb:upArrow": "moveByLine_back", 253 "kb:downArrow": "moveByLine_forward", 254 "kb:leftArrow": "moveByCharacter_back", 255 "kb:rightArrow": "moveByCharacter_forward", 256 "kb:control+leftArrow": "moveByWord_back", 257 "kb:control+rightArrow": "moveByWord_forward", 258 "kb:control+upArrow": "moveByParagraph_back", 259 "kb:control+downArrow": "moveByParagraph_forward", 260 "kb:home": "startOfLine", 261 "kb:end": "endOfLine", 262 "kb:control+home": "topOfDocument", 263 "kb:control+end": "bottomOfDocument", 264 "kb:shift+rightArrow": "selectCharacter_forward", 265 "kb:shift+leftArrow": "selectCharacter_back", 266 "kb:shift+control+rightArrow": "selectWord_forward", 267 "kb:shift+control+leftArrow": "selectWord_back", 268 "kb:shift+downArrow": "selectLine_forward", 269 "kb:shift+upArrow": "selectLine_back", 270 "kb:shift+pageDown": "selectPage_forward", 271 "kb:shift+pageUp": "selectPage_back", 272 "kb:shift+control+downArrow": "selectParagraph_forward", 273 "kb:shift+control+upArrow": "selectParagraph_back", 274 "kb:shift+end": "selectToEndOfLine", 275 "kb:shift+home": "selectToBeginningOfLine", 276 "kb:shift+control+end": "selectToBottomOfDocument", 277 "kb:shift+control+home": "selectToTopOfDocument", 278 "kb:control+a": "selectAll", 279 "kb:control+c": "copyToClipboard", 280 "kb:NVDA+Control+f": "find", 281 "kb:NVDA+f3": "findNext", 282 "kb:NVDA+shift+f3": "findPrevious", 283 } 284
285 -class _ReviewCursorManagerTextInfo(textInfos.TextInfo):
286 """For use with L{ReviewCursorManager}. 287 Overrides L{updateCaret} and L{updateSelection} to use the selection property on the underlying object. 288 """ 289
290 - def updateCaret(self):
291 self.obj.selection = self
292
293 - def updateSelection(self):
294 self.obj.selection = self
295
296 -class ReviewCursorManager(CursorManager):
297 """ 298 A cursor manager used for review. 299 This cursor manager maintains its own caret and selection information. 300 Thus, the underlying text range need not support updating the caret or selection. 301 """ 302
303 - def initCursorManager(self):
304 super(ReviewCursorManager, self).initCursorManager() 305 realTI = self.TextInfo 306 self.TextInfo = type("ReviewCursorManager_%s" % realTI.__name__, (_ReviewCursorManagerTextInfo, realTI), {}) 307 self._selection = self.makeTextInfo(textInfos.POSITION_FIRST)
308
309 - def makeTextInfo(self, position):
310 if position == textInfos.POSITION_SELECTION: 311 return self.selection 312 elif position == textInfos.POSITION_CARET: 313 sel = self.selection 314 sel.collapse() 315 return sel 316 return super(ReviewCursorManager, self).makeTextInfo(position)
317
318 - def _get_selection(self):
319 return self._selection.copy()
320
321 - def _set_selection(self, info):
322 self._selection = info.copy() 323 braille.handler.handleCaretMove(self)
324