From 258dc82cce79ca77dcd9d59472fca9c40b080fac Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Tue, 24 Jan 2017 17:19:22 +0800 Subject: [PATCH 1/9] Support for aria-current in focus mode for chrome --- source/NVDAObjects/IAccessible/ia2Web.py | 4 ++++ source/NVDAObjects/__init__.py | 6 ++++++ source/speech.py | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/source/NVDAObjects/IAccessible/ia2Web.py b/source/NVDAObjects/IAccessible/ia2Web.py index 94a49f0654e..4d7cc01583b 100644 --- a/source/NVDAObjects/IAccessible/ia2Web.py +++ b/source/NVDAObjects/IAccessible/ia2Web.py @@ -26,6 +26,10 @@ def _get_positionInfo(self): info['level']=level return info + def getValueForAriaCurrent(self): + current = self.IA2Attributes.get("current", False) + return current + class Document(Ia2Web): value = None diff --git a/source/NVDAObjects/__init__.py b/source/NVDAObjects/__init__.py index 85fd8aec044..d4c96e3f06b 100644 --- a/source/NVDAObjects/__init__.py +++ b/source/NVDAObjects/__init__.py @@ -798,6 +798,12 @@ def _get_statusBar(self): """ return None + def getValueForAriaCurrent(self): + """Gets the value for aria-current. Normally returns False. If this object is current + it will return one of the following values: True, "page", "step", "location", "date", "time" + """ + return False + def reportFocus(self): """Announces this object in a way suitable such that it gained focus. """ diff --git a/source/speech.py b/source/speech.py index dbb50905197..8369d27be16 100755 --- a/source/speech.py +++ b/source/speech.py @@ -307,6 +307,7 @@ def speakObjectProperties(obj,reason=controlTypes.REASON_QUERY,index=None,**allo newPropertyValues["_tableID"]=obj.tableID except NotImplementedError: pass + newPropertyValues['_current']=obj.getValueForAriaCurrent() #Get the speech text for the properties we want to speak, and then speak it text=getSpeechTextForProperties(reason,**newPropertyValues) if text: @@ -1001,6 +1002,12 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues if rowCount or columnCount: # The caller is entering a table, so ensure that it is treated as a new table, even if the previous table was the same. oldTableID = None + ariaCurrent = propertyValues.get('_current', False) + if ariaCurrent != False: + if ariaCurrent=="page": + textList.append(_("current page")) + else: + textList.append(_("current")) indexInGroup=propertyValues.get('positionInfo_indexInGroup',0) similarItemsInGroup=propertyValues.get('positionInfo_similarItemsInGroup',0) if 0 Date: Wed, 25 Jan 2017 19:45:50 +0800 Subject: [PATCH 2/9] Support for aria-current in focus mode for IE11 --- source/NVDAObjects/IAccessible/MSHTML.py | 3 +++ source/speech.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/source/NVDAObjects/IAccessible/MSHTML.py b/source/NVDAObjects/IAccessible/MSHTML.py index c00d04d42ec..d1ed0bf1308 100644 --- a/source/NVDAObjects/IAccessible/MSHTML.py +++ b/source/NVDAObjects/IAccessible/MSHTML.py @@ -511,6 +511,9 @@ def _get_treeInterceptorClass(self): return virtualBuffers.MSHTML.MSHTML return super(MSHTML,self).treeInterceptorClass + def getValueForAriaCurrent(self): + return self.HTMLAttributes["aria-current"] + def _get_HTMLAttributes(self): return HTMLAttribCache(self.HTMLNode) diff --git a/source/speech.py b/source/speech.py index 8369d27be16..ee98eb1029b 100755 --- a/source/speech.py +++ b/source/speech.py @@ -1003,7 +1003,7 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues # The caller is entering a table, so ensure that it is treated as a new table, even if the previous table was the same. oldTableID = None ariaCurrent = propertyValues.get('_current', False) - if ariaCurrent != False: + if ariaCurrent is not None and ariaCurrent != False: if ariaCurrent=="page": textList.append(_("current page")) else: From 0b23b86cef2bd64e443e3c43a50d76f232a08d62 Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Wed, 25 Jan 2017 22:24:32 +0800 Subject: [PATCH 3/9] Add support for aria-current in focus mode to Edge --- source/NVDAObjects/UIA/edge.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/NVDAObjects/UIA/edge.py b/source/NVDAObjects/UIA/edge.py index ccba7ab0579..b25548824cf 100644 --- a/source/NVDAObjects/UIA/edge.py +++ b/source/NVDAObjects/UIA/edge.py @@ -387,6 +387,13 @@ def _get_description(self): pass return super(EdgeNode,self).description + def getValueForAriaCurrent(self): + ariaProperties=self.UIAElement.currentAriaProperties + if 'current=' in ariaProperties: + # We are not able to get the value for aria-current property + return True + return False + class EdgeList(EdgeNode): # non-focusable lists are readonly lists (ensures correct NVDA presentation category) From 75c28c6772e5ad235ce2b9c0a6223f86c65ffc13 Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Fri, 27 Jan 2017 15:49:13 +0800 Subject: [PATCH 4/9] Added support for aria-current values with edge While in focus mode, we can now get the values for aria-current rather than just the presence of the property. --- source/NVDAObjects/UIA/edge.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/source/NVDAObjects/UIA/edge.py b/source/NVDAObjects/UIA/edge.py index b25548824cf..6b8e4cc1231 100644 --- a/source/NVDAObjects/UIA/edge.py +++ b/source/NVDAObjects/UIA/edge.py @@ -11,11 +11,11 @@ import config import controlTypes import cursorManager +import re import aria import textInfos import UIAHandler from UIABrowseMode import UIABrowseModeDocument, UIABrowseModeDocumentTextInfo -import aria from UIAUtils import * from . import UIA, UIATextInfo @@ -389,9 +389,12 @@ def _get_description(self): def getValueForAriaCurrent(self): ariaProperties=self.UIAElement.currentAriaProperties - if 'current=' in ariaProperties: - # We are not able to get the value for aria-current property - return True + match = re.match("current=(\w+);", ariaProperties) + log.debug("aria props = %s" % ariaProperties) + if match: + valueOfAriaCurrent = match.group(1) + log.debug("aria current value = %s" % valueOfAriaCurrent) + return valueOfAriaCurrent return False class EdgeList(EdgeNode): From 8ff0d42e9ca8a199e7cb90655be797829bc8a8d1 Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Mon, 6 Feb 2017 13:56:46 +0000 Subject: [PATCH 5/9] aria current working in IE while in browse mode --- nvdaHelper/vbufBackends/mshtml/mshtml.cpp | 1 + source/speech.py | 8 +++++--- source/virtualBuffers/MSHTML.py | 3 +++ source/virtualBuffers/__init__.py | 6 ++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/nvdaHelper/vbufBackends/mshtml/mshtml.cpp b/nvdaHelper/vbufBackends/mshtml/mshtml.cpp index 8644a784c2f..6a4bfc1d84d 100755 --- a/nvdaHelper/vbufBackends/mshtml/mshtml.cpp +++ b/nvdaHelper/vbufBackends/mshtml/mshtml.cpp @@ -489,6 +489,7 @@ inline void getAttributesFromHTMLDOMNode(IHTMLDOMNode* pHTMLDOMNode,wstring& nod macro_addHTMLAttributeToMap(L"aria-relevant",false,pHTMLAttributeCollection2,attribsMap,tempVar,tempAttribNode); macro_addHTMLAttributeToMap(L"aria-busy",false,pHTMLAttributeCollection2,attribsMap,tempVar,tempAttribNode); macro_addHTMLAttributeToMap(L"aria-atomic",false,pHTMLAttributeCollection2,attribsMap,tempVar,tempAttribNode); + macro_addHTMLAttributeToMap(L"aria-current",false,pHTMLAttributeCollection2,attribsMap,tempVar,tempAttribNode); pHTMLAttributeCollection2->Release(); } diff --git a/source/speech.py b/source/speech.py index ee98eb1029b..2c368a7be3b 100755 --- a/source/speech.py +++ b/source/speech.py @@ -307,7 +307,7 @@ def speakObjectProperties(obj,reason=controlTypes.REASON_QUERY,index=None,**allo newPropertyValues["_tableID"]=obj.tableID except NotImplementedError: pass - newPropertyValues['_current']=obj.getValueForAriaCurrent() + newPropertyValues['current']=obj.getValueForAriaCurrent() #Get the speech text for the properties we want to speak, and then speak it text=getSpeechTextForProperties(reason,**newPropertyValues) if text: @@ -1002,7 +1002,7 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues if rowCount or columnCount: # The caller is entering a table, so ensure that it is treated as a new table, even if the previous table was the same. oldTableID = None - ariaCurrent = propertyValues.get('_current', False) + ariaCurrent = propertyValues.get('current', False) if ariaCurrent is not None and ariaCurrent != False: if ariaCurrent=="page": textList.append(_("current page")) @@ -1042,6 +1042,7 @@ def getControlFieldSpeech(attrs,ancestorAttrs,fieldType,formatConfig=None,extraD role=attrs.get('role',controlTypes.ROLE_UNKNOWN) states=attrs.get('states',set()) keyboardShortcut=attrs.get('keyboardShortcut', "") + ariaCurrent=attrs.get('current', None) value=attrs.get('value',"") if reason==controlTypes.REASON_FOCUS or attrs.get('alwaysReportDescription',False): description=attrs.get('description',"") @@ -1057,6 +1058,7 @@ def getControlFieldSpeech(attrs,ancestorAttrs,fieldType,formatConfig=None,extraD roleText=getSpeechTextForProperties(reason=reason,role=role) stateText=getSpeechTextForProperties(reason=reason,states=states,_role=role) keyboardShortcutText=getSpeechTextForProperties(reason=reason,keyboardShortcut=keyboardShortcut) if config.conf["presentation"]["reportKeyboardShortcuts"] else "" + ariaCurrentText=getSpeechTextForProperties(reason=reason,current=ariaCurrent) nameText=getSpeechTextForProperties(reason=reason,name=name) valueText=getSpeechTextForProperties(reason=reason,value=value) descriptionText=(getSpeechTextForProperties(reason=reason,description=description) @@ -1119,7 +1121,7 @@ def getControlFieldSpeech(attrs,ancestorAttrs,fieldType,formatConfig=None,extraD content = attrs.get("content") if content and speakContentFirst: out.append(content) - out.extend(x for x in (nameText,(stateText if speakStatesFirst else roleText),(roleText if speakStatesFirst else stateText),valueText,descriptionText,levelText,keyboardShortcutText) if x) + out.extend(x for x in (nameText,(stateText if speakStatesFirst else roleText),(roleText if speakStatesFirst else stateText),ariaCurrentText,valueText,descriptionText,levelText,keyboardShortcutText) if x) if content and not speakContentFirst: out.append(content) return CHUNK_SEPARATOR.join(out) diff --git a/source/virtualBuffers/MSHTML.py b/source/virtualBuffers/MSHTML.py index d6a28bc3011..f584060b84b 100644 --- a/source/virtualBuffers/MSHTML.py +++ b/source/virtualBuffers/MSHTML.py @@ -50,6 +50,9 @@ def _normalizeFormatField(self, attrs): def _normalizeControlField(self,attrs): level=None + ariaCurrent = attrs.get('HTMLAttrib::aria-current', None) + if ariaCurrent is not None: + attrs['current']=ariaCurrent accRole=attrs.get('IAccessible::role',0) accRole=int(accRole) if isinstance(accRole,basestring) and accRole.isdigit() else accRole nodeName=attrs.get('IHTMLDOMNode::nodeName',"") diff --git a/source/virtualBuffers/__init__.py b/source/virtualBuffers/__init__.py index d87d0510a6c..46a3aa77fdf 100644 --- a/source/virtualBuffers/__init__.py +++ b/source/virtualBuffers/__init__.py @@ -257,6 +257,12 @@ def _getParagraphOffsets(self,offset): return lineStart.value,lineEnd.value def _normalizeControlField(self,attrs): + + ariaCurrent = attrs.get("IAccessible2::attribute_current") + if ariaCurrent != None: + attrs['current']= ariaCurrent + del attrs["IAccessible2::attribute_current"] + tableLayout=attrs.get('table-layout') if tableLayout: attrs['table-layout']=tableLayout=="1" From 248e278d12ef4a7e823a7300edcf8a046b7c1cba Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Wed, 8 Feb 2017 06:44:32 +0000 Subject: [PATCH 6/9] Aria-current now reported in browse mode for Edge --- source/NVDAObjects/UIA/edge.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/NVDAObjects/UIA/edge.py b/source/NVDAObjects/UIA/edge.py index 6b8e4cc1231..d7e9068bc34 100644 --- a/source/NVDAObjects/UIA/edge.py +++ b/source/NVDAObjects/UIA/edge.py @@ -147,6 +147,8 @@ def _getControlFieldForObject(self,obj,isEmbedded=False,startOfNode=False,endOfN # Combo boxes with a text pattern are editable if obj.role==controlTypes.ROLE_COMBOBOX and obj.UIATextPattern: field['states'].add(controlTypes.STATE_EDITABLE) + # report if the field is 'current' + field['current']=obj.getValueForAriaCurrent() # For certain controls, if ARIA overrides the label, then force the field's content (value) to the label # Later processing in Edge's getTextWithFields will remove descendant content from fields with a content attribute. ariaProperties=obj.UIAElement.currentAriaProperties From 43bc53499056535ececc17f30fa1dc196473c750 Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Wed, 8 Feb 2017 06:47:28 +0000 Subject: [PATCH 7/9] Support other values of aria-current --- source/speech.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/speech.py b/source/speech.py index 2c368a7be3b..da58d13f387 100755 --- a/source/speech.py +++ b/source/speech.py @@ -1006,6 +1006,14 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues if ariaCurrent is not None and ariaCurrent != False: if ariaCurrent=="page": textList.append(_("current page")) + elif ariaCurrent=="step": + textList.append(_("current step")) + elif ariaCurrent=="location": + textList.append(_("current location")) + elif ariaCurrent=="date": + textList.append(_("current date")) + elif ariaCurrent=="time": + textList.append(_("current time")) else: textList.append(_("current")) indexInGroup=propertyValues.get('positionInfo_indexInGroup',0) From 9a7987a0957f77c6c973fe8a22546b57dbc12953 Mon Sep 17 00:00:00 2001 From: Reef Turner Date: Fri, 17 Feb 2017 14:39:30 +0100 Subject: [PATCH 8/9] Review actions for #6860 - ensure that aria-current is output to braille. - make `getValueForAriaCurrent` a property called isCurrent - use a compiled regex - simplify `if` statement - move text labels for 'aria-current' values to a dictionary and translate - handle aria-current in list items and tables --- source/NVDAObjects/IAccessible/MSHTML.py | 2 +- source/NVDAObjects/IAccessible/ia2Web.py | 2 +- source/NVDAObjects/UIA/edge.py | 12 ++++-- source/NVDAObjects/__init__.py | 5 ++- source/braille.py | 47 ++++++++++++++++-------- source/controlTypes.py | 17 +++++++++ source/speech.py | 36 +++++++++--------- source/virtualBuffers/__init__.py | 6 --- source/virtualBuffers/gecko_ia2.py | 3 ++ 9 files changed, 82 insertions(+), 48 deletions(-) diff --git a/source/NVDAObjects/IAccessible/MSHTML.py b/source/NVDAObjects/IAccessible/MSHTML.py index d1ed0bf1308..b2ae40ff1f3 100644 --- a/source/NVDAObjects/IAccessible/MSHTML.py +++ b/source/NVDAObjects/IAccessible/MSHTML.py @@ -511,7 +511,7 @@ def _get_treeInterceptorClass(self): return virtualBuffers.MSHTML.MSHTML return super(MSHTML,self).treeInterceptorClass - def getValueForAriaCurrent(self): + def _get_isCurrent(self): return self.HTMLAttributes["aria-current"] def _get_HTMLAttributes(self): diff --git a/source/NVDAObjects/IAccessible/ia2Web.py b/source/NVDAObjects/IAccessible/ia2Web.py index 4d7cc01583b..a0215ffd603 100644 --- a/source/NVDAObjects/IAccessible/ia2Web.py +++ b/source/NVDAObjects/IAccessible/ia2Web.py @@ -26,7 +26,7 @@ def _get_positionInfo(self): info['level']=level return info - def getValueForAriaCurrent(self): + def _get_isCurrent(self): current = self.IA2Attributes.get("current", False) return current diff --git a/source/NVDAObjects/UIA/edge.py b/source/NVDAObjects/UIA/edge.py index d7e9068bc34..bbbe0b38d74 100644 --- a/source/NVDAObjects/UIA/edge.py +++ b/source/NVDAObjects/UIA/edge.py @@ -148,7 +148,7 @@ def _getControlFieldForObject(self,obj,isEmbedded=False,startOfNode=False,endOfN if obj.role==controlTypes.ROLE_COMBOBOX and obj.UIATextPattern: field['states'].add(controlTypes.STATE_EDITABLE) # report if the field is 'current' - field['current']=obj.getValueForAriaCurrent() + field['current']=obj.isCurrent # For certain controls, if ARIA overrides the label, then force the field's content (value) to the label # Later processing in Edge's getTextWithFields will remove descendant content from fields with a content attribute. ariaProperties=obj.UIAElement.currentAriaProperties @@ -389,9 +389,15 @@ def _get_description(self): pass return super(EdgeNode,self).description - def getValueForAriaCurrent(self): + # RegEx to get the value for the aria-current property. This will be looking for a the value of 'current' + # in a list of strings like "something=true;current=date;". We want to capture one group, after the '=' + # character and before the ';' character. + # This could be one of: True, "page", "step", "location", "date", "time" + RE_ARIA_CURRENT_PROP_VALUE = re.compile("current=(\w+);") + + def _get_isCurrent(self): ariaProperties=self.UIAElement.currentAriaProperties - match = re.match("current=(\w+);", ariaProperties) + match = self.RE_ARIA_CURRENT_PROP_VALUE.match(ariaProperties) log.debug("aria props = %s" % ariaProperties) if match: valueOfAriaCurrent = match.group(1) diff --git a/source/NVDAObjects/__init__.py b/source/NVDAObjects/__init__.py index d4c96e3f06b..2d485232b0a 100644 --- a/source/NVDAObjects/__init__.py +++ b/source/NVDAObjects/__init__.py @@ -798,8 +798,9 @@ def _get_statusBar(self): """ return None - def getValueForAriaCurrent(self): - """Gets the value for aria-current. Normally returns False. If this object is current + def _get_isCurrent(self): + """Gets the value that indicates whether this object is the current element in a set of related + elements. This maps to aria-current. Normally returns False. If this object is current it will return one of the following values: True, "page", "step", "location", "date", "time" """ return False diff --git a/source/braille.py b/source/braille.py index f572752f22a..874ab93e285 100644 --- a/source/braille.py +++ b/source/braille.py @@ -388,6 +388,9 @@ ) SELECTION_SHAPE = 0xC0 #: Dots 7 and 8 +# used to separate chunks of text when programmatically joined +TEXT_SEPARATOR = " " + def NVDAObjectHasUsefulText(obj): import displayModel role = obj.role @@ -630,9 +633,16 @@ def getBrailleTextForProperties(**propertyValues): # Translators: Displayed in braille for a table cell column number. # %s is replaced with the column number. textList.append(_("c%s") % columnNumber) + ariaCurrent = propertyValues.get('current', False) + if ariaCurrent: + try: + textList.append(controlTypes.isCurrentLabels[ariaCurrent]) + except KeyError: + log.debugWarning("Aria-current value not handled: %s"%ariaCurrent) + textList.append(controlTypes.isCurrentLabels[True]) if includeTableCellCoords and cellCoordsText: textList.append(cellCoordsText) - return " ".join([x for x in textList if x]) + return TEXT_SEPARATOR.join([x for x in textList if x]) class NVDAObjectRegion(Region): """A region to provide a braille representation of an NVDAObject. @@ -655,7 +665,7 @@ def update(self): obj = self.obj presConfig = config.conf["presentation"] role = obj.role - text = getBrailleTextForProperties(name=obj.name, role=role, + text = getBrailleTextForProperties(name=obj.name, role=role, current=obj.isCurrent, value=obj.value if not NVDAObjectHasUsefulText(obj) else None , states=obj.states, description=obj.description if presConfig["reportObjectDescriptions"] else None, @@ -668,7 +678,7 @@ def update(self): mathPres.ensureInit() if mathPres.brailleProvider: try: - text += " " + mathPres.brailleProvider.getBrailleForMathMl( + text += TEXT_SEPARATOR + mathPres.brailleProvider.getBrailleForMathMl( obj.mathMl) except (NotImplementedError, LookupError): pass @@ -698,12 +708,16 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): role = field.get("role", controlTypes.ROLE_UNKNOWN) states = field.get("states", set()) value=field.get('value',None) + ariaCurrent=field.get('current', None) if presCat == field.PRESCAT_LAYOUT: + text = [] # The only item we report for these fields is clickable, if present. if controlTypes.STATE_CLICKABLE in states: - return getBrailleTextForProperties(states={controlTypes.STATE_CLICKABLE}) - return None + text.append(getBrailleTextForProperties(states={controlTypes.STATE_CLICKABLE})) + if ariaCurrent: + text.append(getBrailleTextForProperties(current=ariaCurrent)) + return TEXT_SEPARATOR.join(text) if len(text) != 0 else None elif role in (controlTypes.ROLE_TABLECELL, controlTypes.ROLE_TABLECOLUMNHEADER, controlTypes.ROLE_TABLEROWHEADER) and field.get("table-id"): # Table cell. @@ -713,7 +727,8 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): "states": states, "rowNumber": field.get("table-rownumber"), "columnNumber": field.get("table-columnnumber"), - "includeTableCellCoords": reportTableCellCoords + "includeTableCellCoords": reportTableCellCoords, + "current": ariaCurrent, } if reportTableHeaders: props["columnHeaderText"] = field.get("table-columnheadertext") @@ -724,7 +739,7 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): # Don't report the role for math here. # However, we still need to pass it (hence "_role"). "_role" if role == controlTypes.ROLE_MATH else "role": role, - "states": states,"value":value} + "states": states,"value":value, "current":ariaCurrent} if config.conf["presentation"]["reportKeyboardShortcuts"]: kbShortcut = field.get("keyboardShortcut") if kbShortcut: @@ -736,7 +751,7 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): content = field.get("content") if content: if text: - text += " " + text += TEXT_SEPARATOR text += content elif role == controlTypes.ROLE_MATH: import mathPres @@ -744,7 +759,7 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): if mathPres.brailleProvider: try: if text: - text += " " + text += TEXT_SEPARATOR text += mathPres.brailleProvider.getBrailleForMathMl( info.getMathMl(field)) except (NotImplementedError, LookupError): @@ -772,7 +787,7 @@ def getFormatFieldBraille(field, isAtStart, formatConfig): # Translators: Displayed in braille for a heading with a level. # %s is replaced with the level. textList.append(_("h%s")%headingLevel) - return " ".join([x for x in textList if x]) + return TEXT_SEPARATOR.join([x for x in textList if x]) class TextInfoRegion(Region): @@ -836,7 +851,7 @@ def _getTypeformFromFormatField(self, field): def _addFieldText(self, text, contentPos): if self.rawText: # Separate this field text from the rest of the text. - text = " " + text + text = TEXT_SEPARATOR + text self.rawText += text textLen = len(text) self.rawTextTypeforms.extend((louis.plain_text,) * textLen) @@ -854,7 +869,7 @@ def _addTextWithFields(self, info, formatConfig, isSelection=False): if self._endsWithField: # The last item added was a field, # so add a space before the content. - self.rawText += " " + self.rawText += TEXT_SEPARATOR self.rawTextTypeforms.append(louis.plain_text) self._rawToContentPos.append(self._currentContentPos) if isSelection and self.selectionStart is None: @@ -982,7 +997,7 @@ def update(self): # There is no text left after stripping line ending characters, # or the last item added can be navigated with a cursor. # Add a space in case the cursor is at the end of the reading unit. - self.rawText += " " + self.rawText += TEXT_SEPARATOR rawTextLen += 1 self.rawTextTypeforms.append(louis.plain_text) self._rawToContentPos.append(self._currentContentPos) @@ -1373,7 +1388,7 @@ def getFocusContextRegions(obj, oldFocusRegions=None): for index, parent in enumerate(ancestors[newAncestorsStart:ancestorsEnd], newAncestorsStart): if not parent.isPresentableFocusAncestor: continue - region = NVDAObjectRegion(parent, appendText=" ") + region = NVDAObjectRegion(parent, appendText=TEXT_SEPARATOR) region._focusAncestorIndex = index region.update() yield region @@ -1404,7 +1419,7 @@ def getFocusRegions(obj, review=False): region2 = None if isinstance(obj, TreeInterceptor): obj = obj.rootNVDAObject - region = NVDAObjectRegion(obj, appendText=" " if region2 else "") + region = NVDAObjectRegion(obj, appendText=TEXT_SEPARATOR if region2 else "") region.update() yield region if region2: @@ -1423,7 +1438,7 @@ def formatCellsForLog(cells): # optimisation: This gets called a lot, so needs to be as efficient as possible. # List comprehensions without function calls are faster than loops. # For str.join, list comprehensions are faster than generator comprehensions. - return " ".join([ + return TEXT_SEPARATOR.join([ "".join([str(dot + 1) for dot in xrange(8) if cell & (1 << dot)]) if cell else "-" for cell in cells]) diff --git a/source/controlTypes.py b/source/controlTypes.py index 4a64cdd86b9..3831f145eab 100644 --- a/source/controlTypes.py +++ b/source/controlTypes.py @@ -613,6 +613,23 @@ REASON_ONLYCACHE="onlyCache" #} +# Text to use for 'current' values. These describe if an item is the current item +# within a particular kind of selection. +isCurrentLabels = { + # Translators: Presented when an item is marked as current in a collection of items + True:_("current"), + # Translators: Presented when a page item is marked as current in a collection of page items + "page":_("current page"), + # Translators: Presented when a step item is marked as current in a collection of step items + "step":_("current step"), + # Translators: Presented when a location item is marked as current in a collection of location items + "location":_("current location"), + # Translators: Presented when a date item is marked as current in a collection of date items + "date":_("current date"), + # Translators: Presented when a time item is marked as current in a collection of time items + "time":_("current time"), +} + def processPositiveStates(role, states, reason, positiveStates): positiveStates = positiveStates.copy() # The user never cares about certain states. diff --git a/source/speech.py b/source/speech.py index da58d13f387..a7e1c7657c8 100755 --- a/source/speech.py +++ b/source/speech.py @@ -307,7 +307,7 @@ def speakObjectProperties(obj,reason=controlTypes.REASON_QUERY,index=None,**allo newPropertyValues["_tableID"]=obj.tableID except NotImplementedError: pass - newPropertyValues['current']=obj.getValueForAriaCurrent() + newPropertyValues['current']=obj.isCurrent #Get the speech text for the properties we want to speak, and then speak it text=getSpeechTextForProperties(reason,**newPropertyValues) if text: @@ -1003,19 +1003,12 @@ def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues # The caller is entering a table, so ensure that it is treated as a new table, even if the previous table was the same. oldTableID = None ariaCurrent = propertyValues.get('current', False) - if ariaCurrent is not None and ariaCurrent != False: - if ariaCurrent=="page": - textList.append(_("current page")) - elif ariaCurrent=="step": - textList.append(_("current step")) - elif ariaCurrent=="location": - textList.append(_("current location")) - elif ariaCurrent=="date": - textList.append(_("current date")) - elif ariaCurrent=="time": - textList.append(_("current time")) - else: - textList.append(_("current")) + if ariaCurrent: + try: + textList.append(controlTypes.isCurrentLabels[ariaCurrent]) + except KeyError: + log.debugWarning("Aria-current value not handled: %s"%ariaCurrent) + textList.append(controlTypes.isCurrentLabels[True]) indexInGroup=propertyValues.get('positionInfo_indexInGroup',0) similarItemsInGroup=propertyValues.get('positionInfo_similarItemsInGroup',0) if 0 Date: Thu, 23 Feb 2017 16:06:13 +0100 Subject: [PATCH 9/9] Further review actions for #6860 --- source/braille.py | 18 +++++++++--------- source/controlTypes.py | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/braille.py b/source/braille.py index 874ab93e285..84c840808ed 100644 --- a/source/braille.py +++ b/source/braille.py @@ -633,12 +633,12 @@ def getBrailleTextForProperties(**propertyValues): # Translators: Displayed in braille for a table cell column number. # %s is replaced with the column number. textList.append(_("c%s") % columnNumber) - ariaCurrent = propertyValues.get('current', False) - if ariaCurrent: + current = propertyValues.get('current', False) + if current: try: - textList.append(controlTypes.isCurrentLabels[ariaCurrent]) + textList.append(controlTypes.isCurrentLabels[current]) except KeyError: - log.debugWarning("Aria-current value not handled: %s"%ariaCurrent) + log.debugWarning("Aria-current value not handled: %s"%current) textList.append(controlTypes.isCurrentLabels[True]) if includeTableCellCoords and cellCoordsText: textList.append(cellCoordsText) @@ -708,15 +708,15 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): role = field.get("role", controlTypes.ROLE_UNKNOWN) states = field.get("states", set()) value=field.get('value',None) - ariaCurrent=field.get('current', None) + current=field.get('current', None) if presCat == field.PRESCAT_LAYOUT: text = [] # The only item we report for these fields is clickable, if present. if controlTypes.STATE_CLICKABLE in states: text.append(getBrailleTextForProperties(states={controlTypes.STATE_CLICKABLE})) - if ariaCurrent: - text.append(getBrailleTextForProperties(current=ariaCurrent)) + if current: + text.append(getBrailleTextForProperties(current=current)) return TEXT_SEPARATOR.join(text) if len(text) != 0 else None elif role in (controlTypes.ROLE_TABLECELL, controlTypes.ROLE_TABLECOLUMNHEADER, controlTypes.ROLE_TABLEROWHEADER) and field.get("table-id"): @@ -728,7 +728,7 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): "rowNumber": field.get("table-rownumber"), "columnNumber": field.get("table-columnnumber"), "includeTableCellCoords": reportTableCellCoords, - "current": ariaCurrent, + "current": current, } if reportTableHeaders: props["columnHeaderText"] = field.get("table-columnheadertext") @@ -739,7 +739,7 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig): # Don't report the role for math here. # However, we still need to pass it (hence "_role"). "_role" if role == controlTypes.ROLE_MATH else "role": role, - "states": states,"value":value, "current":ariaCurrent} + "states": states,"value":value, "current":current} if config.conf["presentation"]["reportKeyboardShortcuts"]: kbShortcut = field.get("keyboardShortcut") if kbShortcut: diff --git a/source/controlTypes.py b/source/controlTypes.py index 3831f145eab..f6f3bf8e67a 100644 --- a/source/controlTypes.py +++ b/source/controlTypes.py @@ -613,8 +613,8 @@ REASON_ONLYCACHE="onlyCache" #} -# Text to use for 'current' values. These describe if an item is the current item -# within a particular kind of selection. +#: Text to use for 'current' values. These describe if an item is the current item +#: within a particular kind of selection. isCurrentLabels = { # Translators: Presented when an item is marked as current in a collection of items True:_("current"),