@@ -58,9 +58,20 @@ class MozillaCompoundTextInfo(CompoundTextInfo):
5858 def __init__ (self , obj , position ):
5959 super (MozillaCompoundTextInfo , self ).__init__ (obj , position )
6060 if isinstance (position , NVDAObject ):
61- # FIXME
62- position = textInfos .POSITION_CARET
63- if isinstance (position , self .__class__ ):
61+ try :
62+ self ._start , self ._startObj = self ._findContentDescendant (position , textInfos .POSITION_FIRST )
63+ self ._end , self ._endObj = self ._findContentDescendant (position , textInfos .POSITION_LAST )
64+ # This is the last character. Move to the end.
65+ self ._end .move (textInfos .UNIT_CHARACTER , 1 )
66+ except LookupError :
67+ # This might be an embedded object that doesn't support text such as a graphic.
68+ if position not in obj :
69+ raise ValueError ("Object %s not in document" % position )
70+ # Use the point where this is embedded.
71+ self ._start = self ._end = self ._getEmbedding (position )
72+ self ._startObj = self ._endObj = self ._start .obj
73+ self ._normalizeStartAndEnd ()
74+ elif isinstance (position , self .__class__ ):
6475 self ._start = position ._start .copy ()
6576 self ._startObj = position ._startObj
6677 if position ._end is position ._start :
@@ -92,26 +103,9 @@ def __init__(self, obj, position):
92103 self ._start = self ._end = caretTi
93104 self ._startObj = self ._endObj = caretObj
94105 elif position == textInfos .POSITION_SELECTION :
95- # The caret is usually within the selection,
96- # so start from the caret for better performance/tolerance of server brokenness.
97- tempTi , tempObj = self ._findContentDescendant (obj , textInfos .POSITION_CARET )
98- try :
99- tempTi = self ._makeRawTextInfo (tempObj , position )
100- except RuntimeError :
101- # The caret is just before this object.
102- # There is never a selection in this case.
103- pass
104- else :
105- if tempTi .isCollapsed :
106- # No selection, but perhaps the caret is at the start of the next/previous object.
107- # This happens when you, for example, press shift+rightArrow at the end of a block.
108- # Try from the root.
109- rootTi = self ._makeRawTextInfo (obj , position )
110- if not rootTi .isCollapsed :
111- # There is definitely a selection.
112- tempTi , tempObj = rootTi , obj
106+ tempTi , tempObj = self ._getSelectionBase ()
113107 if tempTi .isCollapsed :
114- # No selection, so use the caret.
108+ # No selection, so return the caret.
115109 self ._start = self ._end = tempTi
116110 self ._startObj = self ._endObj = tempObj
117111 else :
@@ -130,6 +124,46 @@ def __init__(self, obj, position):
130124 else :
131125 raise NotImplementedError
132126
127+ def _getSelectionBase (self ):
128+ """Get an NVDAObject and TextInfo somewhere within the selection.
129+ This is just a base point to start from.
130+ It will often be necessary to expand outwards and/or descend to get the complete selection.
131+ """
132+ # The caret is usually within the selection,
133+ # so start from the caret for better performance/tolerance of server brokenness.
134+ try :
135+ ti , obj = self ._findContentDescendant (self .obj , textInfos .POSITION_CARET )
136+ except LookupError :
137+ # No caret.
138+ ti = None
139+ else :
140+ try :
141+ ti = self ._makeRawTextInfo (obj , textInfos .POSITION_SELECTION )
142+ except RuntimeError :
143+ # The caret is just before this object.
144+ # There is never a selection in this case.
145+ return ti , obj
146+ else :
147+ if not ti .isCollapsed :
148+ # There was a selection on the caret object.
149+ return ti , obj
150+ # At this point, we're in one of two situations:
151+ # 1. There was no caret.
152+ # This happens for non-navigable text; e.g. Kindle.
153+ # However, this doesn't mean there's no selection.
154+ # 2. There was a caret, but there was no selection on the caret object.
155+ # Perhaps the caret is at the start of the next/previous object.
156+ # This happens when you, for example, press shift+rightArrow at the end of a block.
157+ # Try from the root.
158+ rootTi = self ._makeRawTextInfo (self .obj , textInfos .POSITION_SELECTION )
159+ if not rootTi .isCollapsed :
160+ # There is definitely a selection.
161+ return rootTi , self .obj
162+ if ti :
163+ # No selection, but there's a caret, so return that.
164+ return ti , obj
165+ raise RuntimeError ("No selection or caret" )
166+
133167 def _makeRawTextInfo (self , obj , position ):
134168 return _getRawTextInfo (obj )(obj , position )
135169
@@ -201,14 +235,17 @@ def _iterRecursiveText(self, ti, controlStack, formatConfig):
201235 yield item
202236 elif isinstance (item , int ): # Embedded object.
203237 embedded = _getEmbedded (ti .obj , item )
238+ notText = _getRawTextInfo (embedded ) is NVDAObjectTextInfo
204239 if controlStack is not None :
205240 controlField = self ._getControlFieldForObject (embedded )
206241 controlStack .append (controlField )
207242 if controlField :
243+ if notText :
244+ controlField ["content" ] = embedded .name
208245 controlField ["_startOfNode" ] = True
209246 yield textInfos .FieldCommand ("controlStart" , controlField )
210- if _getRawTextInfo ( embedded ) is NVDAObjectTextInfo : # No text
211- yield embedded . basicText
247+ if notText :
248+ yield u" "
212249 else :
213250 for subItem in self ._iterRecursiveText (self ._makeRawTextInfo (embedded , textInfos .POSITION_ALL ), controlStack , formatConfig ):
214251 yield subItem
@@ -509,7 +546,10 @@ def move(self, unit, direction, endPoint=None):
509546 # Find the edge of the current unit in the requested direction.
510547 moveTi , moveObj = self ._findUnitEndpoints (moveTi , unit , findStart = moveBack , findEnd = not moveBack )
511548
512- if not moveBack :
549+ if moveBack :
550+ # Collapse to the start of the previous unit.
551+ moveTi .collapse ()
552+ else :
513553 # Collapse to the start of the next unit.
514554 moveTi .collapse (end = True )
515555 if moveTi .compareEndPoints (self ._makeRawTextInfo (moveObj , textInfos .POSITION_ALL ), "endToEnd" ) == 0 :
0 commit comments