def test_negativeMergedStatesOutput(self): obj = PlaceholderNVDAObject() obj.role = controlTypes.Role.CHECKBOX obj.states = { controlTypes.State.FOCUSABLE, controlTypes.State.FOCUSED, controlTypes.State.SELECTED, controlTypes.State.SELECTABLE } self.assertEqual( controlTypes.processAndLabelStates(obj.role, obj.states, controlTypes.OutputReason.FOCUS, obj.states, None), [controlTypes.State.CHECKED.negativeDisplayString])
def test_negativeMergedStatesOutput(self): obj = PlaceholderNVDAObject() obj.role = controlTypes.ROLE_CHECKBOX obj.states = { controlTypes.STATE_FOCUSABLE, controlTypes.STATE_FOCUSED, controlTypes.STATE_SELECTED, controlTypes.STATE_SELECTABLE } self.assertEqual( controlTypes.processAndLabelStates(obj.role, obj.states, controlTypes.REASON_FOCUS, obj.states, None), [controlTypes.negativeStateLabels[controlTypes.STATE_CHECKED]])
def getSpeechTextForProperties(reason=controlTypes.REASON_QUERY,**propertyValues): oldTreeLevel = speech.oldTreeLevel oldTableID = speech.oldTableID oldRowNumber = speech.oldRowNumber oldRowSpan = speech.oldRowSpan oldColumnNumber = speech.oldColumnNumber oldColumnSpan = speech.oldColumnSpan global _enableTranslation if not _enableTranslation: return _nvdaGetSpeechTextForProperties(reason, **propertyValues) textList=[] name=propertyValues.get('name') if name: textList.append(translate(name.replace("&", ""))) if 'role' in propertyValues: role=propertyValues['role'] speakRole=True elif '_role' in propertyValues: speakRole=False role=propertyValues['_role'] else: speakRole=False role=controlTypes.ROLE_UNKNOWN value = propertyValues.get('value') if role not in controlTypes.silentValuesForRoles else None cellCoordsText=propertyValues.get('cellCoordsText') rowNumber=propertyValues.get('rowNumber') columnNumber=propertyValues.get('columnNumber') includeTableCellCoords=propertyValues.get('includeTableCellCoords',True) if role==controlTypes.ROLE_CHARTELEMENT: speakRole=False roleText=propertyValues.get('roleText') if speakRole and (roleText or reason not in (controlTypes.REASON_SAYALL,controlTypes.REASON_CARET,controlTypes.REASON_FOCUS) or not (name or value or cellCoordsText or rowNumber or columnNumber) or role not in controlTypes.silentRolesOnFocus) and (role!=controlTypes.ROLE_MATH or reason not in (controlTypes.REASON_CARET,controlTypes.REASON_SAYALL)): textList.append(translate(roleText) if roleText else controlTypes.roleLabels[role]) if value: textList.append(translate(value)) states=propertyValues.get('states',set()) realStates=propertyValues.get('_states',states) negativeStates=propertyValues.get('negativeStates',set()) if states or negativeStates: textList.extend(controlTypes.processAndLabelStates(role, realStates, reason, states, negativeStates)) if 'description' in propertyValues: textList.append(translate(propertyValues['description'])) if 'keyboardShortcut' in propertyValues: textList.append(propertyValues['keyboardShortcut']) if includeTableCellCoords and cellCoordsText: textList.append(cellCoordsText) if cellCoordsText or rowNumber or columnNumber: tableID = propertyValues.get("_tableID") # Always treat the table as different if there is no tableID. sameTable = (tableID and tableID == oldTableID) # Don't update the oldTableID if no tableID was given. if tableID and not sameTable: oldTableID = tableID rowSpan = propertyValues.get("rowSpan") columnSpan = propertyValues.get("columnSpan") if rowNumber and (not sameTable or rowNumber != oldRowNumber or rowSpan != oldRowSpan): rowHeaderText = propertyValues.get("rowHeaderText") if rowHeaderText: textList.append(translate(rowHeaderText)) if includeTableCellCoords and not cellCoordsText: # Translators: Speaks current row number (example output: row 3). textList.append(_("row %s")%rowNumber) if rowSpan>1 and columnSpan<=1: # Translators: Speaks the row span added to the current row number (example output: through 5). textList.append(_("through %s")%(rowNumber+rowSpan-1)) oldRowNumber = rowNumber oldRowSpan = rowSpan if columnNumber and (not sameTable or columnNumber != oldColumnNumber or columnSpan != oldColumnSpan): columnHeaderText = propertyValues.get("columnHeaderText") if columnHeaderText: textList.append(translate(columnHeaderText)) if includeTableCellCoords and not cellCoordsText: # Translators: Speaks current column number (example output: column 3). textList.append(_("column %s")%columnNumber) if columnSpan>1 and rowSpan<=1: # Translators: Speaks the column span added to the current column number (example output: through 5). textList.append(_("through %s")%(columnNumber+columnSpan-1)) oldColumnNumber = columnNumber oldColumnSpan = columnSpan if includeTableCellCoords and not cellCoordsText and rowSpan>1 and columnSpan>1: # Translators: Speaks the row and column span added to the current row and column numbers # (example output: through row 5 column 3). textList.append(_("through row {row} column {column}").format( row=rowNumber+rowSpan-1, column=columnNumber+columnSpan-1 )) rowCount=propertyValues.get('rowCount',0) columnCount=propertyValues.get('columnCount',0) if rowCount and columnCount: # Translators: Speaks number of columns and rows in a table (example output: with 3 rows and 2 columns). textList.append(_("with {rowCount} rows and {columnCount} columns").format(rowCount=rowCount,columnCount=columnCount)) elif columnCount and not rowCount: # Translators: Speaks number of columns (example output: with 4 columns). textList.append(_("with %s columns")%columnCount) elif rowCount and not columnCount: # Translators: Speaks number of rows (example output: with 2 rows). textList.append(_("with %s rows")%rowCount) 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: try: textList.append(controlTypes.isCurrentLabels[ariaCurrent]) except KeyError: log.debugWarning("Aria-current value not handled: %s"%ariaCurrent) textList.append(controlTypes.isCurrentLabels[True]) placeholder = propertyValues.get('placeholder', None) if placeholder: textList.append(placeholder) indexInGroup=propertyValues.get('positionInfo_indexInGroup',0) similarItemsInGroup=propertyValues.get('positionInfo_similarItemsInGroup',0) if 0<indexInGroup<=similarItemsInGroup: # Translators: Spoken to indicate the position of an item in a group of items (such as a list). # {number} is replaced with the number of the item in the group. # {total} is replaced with the total number of items in the group. textList.append(_("{number} of {total}").format(number=indexInGroup, total=similarItemsInGroup)) if 'positionInfo_level' in propertyValues: level=propertyValues.get('positionInfo_level',None) role=propertyValues.get('role',None) if level is not None: if role in (controlTypes.ROLE_TREEVIEWITEM,controlTypes.ROLE_LISTITEM) and level!=oldTreeLevel: textList.insert(0,_("level %s")%level) oldTreeLevel=level else: # Translators: Speaks the item level in treeviews (example output: level 2). textList.append(_('level %s')%propertyValues['positionInfo_level']) speech.oldTreeLevel = oldTreeLevel speech.oldTableID = oldTableID speech.oldRowNumber = oldRowNumber speech.oldRowSpan = oldRowSpan speech.oldColumnNumber = oldColumnNumber speech.oldColumnSpan = oldColumnSpan return speech.CHUNK_SEPARATOR.join([x for x in textList if x])
def getPropertiesSpeech( # noqa: C901 reason=controlTypes.OutputReason.QUERY, **propertyValues): global oldTreeLevel, oldTableID, oldRowNumber, oldRowSpan, oldColumnNumber, oldColumnSpan textList: List[str] = [] name: Optional[str] = propertyValues.get('name') if name: textList.append(translate(name)) if 'role' in propertyValues: role = propertyValues['role'] speakRole = True elif '_role' in propertyValues: speakRole = False role = propertyValues['_role'] else: speakRole = False role = controlTypes.ROLE_UNKNOWN value: Optional[str] = propertyValues.get( 'value') if role not in controlTypes.silentValuesForRoles else None cellCoordsText: Optional[str] = propertyValues.get('cellCoordsText') rowNumber = propertyValues.get('rowNumber') columnNumber = propertyValues.get('columnNumber') includeTableCellCoords = propertyValues.get('includeTableCellCoords', True) if role == controlTypes.ROLE_CHARTELEMENT: speakRole = False roleText: Optional[str] = propertyValues.get('roleText') if (speakRole and (roleText or reason not in (controlTypes.OutputReason.SAYALL, controlTypes.OutputReason.CARET, controlTypes.OutputReason.FOCUS) or not (name or value or cellCoordsText or rowNumber or columnNumber) or role not in controlTypes.silentRolesOnFocus) and (role != controlTypes.ROLE_MATH or reason not in (controlTypes.OutputReason.CARET, controlTypes.OutputReason.SAYALL))): textList.append( translate(roleText) if roleText else controlTypes.roleLabels[role]) if value: textList.append(translate(value)) states = propertyValues.get('states', set()) realStates = propertyValues.get('_states', states) negativeStates = propertyValues.get('negativeStates', set()) if states or negativeStates: labelStates = controlTypes.processAndLabelStates( role, realStates, reason, states, negativeStates) textList.extend(labelStates) # sometimes description key is present but value is None description: Optional[str] = propertyValues.get('description') if description: textList.append(translate(description)) # sometimes keyboardShortcut key is present but value is None keyboardShortcut: Optional[str] = propertyValues.get('keyboardShortcut') if keyboardShortcut: textList.append(keyboardShortcut) if includeTableCellCoords and cellCoordsText: textList.append(cellCoordsText) if cellCoordsText or rowNumber or columnNumber: tableID = propertyValues.get("_tableID") # Always treat the table as different if there is no tableID. sameTable = (tableID and tableID == oldTableID) # Don't update the oldTableID if no tableID was given. if tableID and not sameTable: oldTableID = tableID # When fetching row and column span # default the values to 1 to make further checks a lot simpler. # After all, a table cell that has no rowspan implemented is assumed to span one row. rowSpan = propertyValues.get("rowSpan") or 1 columnSpan = propertyValues.get("columnSpan") or 1 if rowNumber and (not sameTable or rowNumber != oldRowNumber or rowSpan != oldRowSpan): rowHeaderText: Optional[str] = propertyValues.get("rowHeaderText") if rowHeaderText: textList.append(rowHeaderText) if includeTableCellCoords and not cellCoordsText: # Translators: Speaks current row number (example output: row 3). rowNumberTranslation: str = _("row %s") % rowNumber textList.append(rowNumberTranslation) if rowSpan > 1 and columnSpan <= 1: # Translators: Speaks the row span added to the current row number (example output: through 5). rowSpanAddedTranslation: str = _("through %s") % ( rowNumber + rowSpan - 1) textList.append(rowSpanAddedTranslation) oldRowNumber = rowNumber oldRowSpan = rowSpan if columnNumber and (not sameTable or columnNumber != oldColumnNumber or columnSpan != oldColumnSpan): columnHeaderText: Optional[str] = propertyValues.get( "columnHeaderText") if columnHeaderText: textList.append(translate(columnHeaderText)) if includeTableCellCoords and not cellCoordsText: # Translators: Speaks current column number (example output: column 3). colNumberTranslation: str = _("column %s") % columnNumber textList.append(colNumberTranslation) if columnSpan > 1 and rowSpan <= 1: # Translators: Speaks the column span added to the current column number (example output: through 5). colSpanAddedTranslation: str = _("through %s") % ( columnNumber + columnSpan - 1) textList.append(colSpanAddedTranslation) oldColumnNumber = columnNumber oldColumnSpan = columnSpan if includeTableCellCoords and not cellCoordsText and rowSpan > 1 and columnSpan > 1: # Translators: Speaks the row and column span added to the current row and column numbers # (example output: through row 5 column 3). rowColSpanTranslation: str = _( "through row {row} column {column}").format( row=rowNumber + rowSpan - 1, column=columnNumber + columnSpan - 1) textList.append(rowColSpanTranslation) rowCount = propertyValues.get('rowCount', 0) columnCount = propertyValues.get('columnCount', 0) if rowCount and columnCount: # Translators: Speaks number of columns and rows in a table (example output: with 3 rows and 2 columns). rowAndColCountTranslation: str = _( "with {rowCount} rows and {columnCount} columns").format( rowCount=rowCount, columnCount=columnCount) textList.append(rowAndColCountTranslation) elif columnCount and not rowCount: # Translators: Speaks number of columns (example output: with 4 columns). columnCountTransation: str = _("with %s columns") % columnCount textList.append(columnCountTransation) elif rowCount and not columnCount: # Translators: Speaks number of rows (example output: with 2 rows). rowCountTranslation: str = _("with %s rows") % rowCount textList.append(rowCountTranslation) 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: try: ariaCurrentLabel = controlTypes.isCurrentLabels[ariaCurrent] textList.append(ariaCurrentLabel) except KeyError: log.debugWarning("Aria-current value not handled: %s" % ariaCurrent) ariaCurrentLabel = controlTypes.isCurrentLabels[True] textList.append(ariaCurrentLabel) placeholder: Optional[str] = propertyValues.get('placeholder', None) if placeholder: textList.append(translate(placeholder)) indexInGroup = propertyValues.get('positionInfo_indexInGroup', 0) similarItemsInGroup = propertyValues.get( 'positionInfo_similarItemsInGroup', 0) if 0 < indexInGroup <= similarItemsInGroup: # Translators: Spoken to indicate the position of an item in a group of items (such as a list). # {number} is replaced with the number of the item in the group. # {total} is replaced with the total number of items in the group. itemPosTranslation: str = _("{number} of {total}").format( number=indexInGroup, total=similarItemsInGroup) textList.append(itemPosTranslation) if 'positionInfo_level' in propertyValues: level = propertyValues.get('positionInfo_level', None) role = propertyValues.get('role', None) if level is not None: # Translators: Speaks the item level in treeviews (example output: level 2). levelTranslation: str = _('level %s') % level if role in (controlTypes.ROLE_TREEVIEWITEM, controlTypes.ROLE_LISTITEM) and level != oldTreeLevel: textList.insert(0, levelTranslation) oldTreeLevel = level else: textList.append(levelTranslation) types.logBadSequenceTypes(textList) global _lastTranslatedText _lastTranslatedText = " ".join(e for e in textList) return textList
def test_negativeMergedStatesOutput(self): obj = PlaceholderNVDAObject() obj.role = controlTypes.ROLE_CHECKBOX obj.states = set((controlTypes.STATE_FOCUSABLE, controlTypes.STATE_FOCUSED, controlTypes.STATE_SELECTED, controlTypes.STATE_SELECTABLE)) self.assertEqual(controlTypes.processAndLabelStates(obj.role, obj.states, controlTypes.REASON_FOCUS, obj.states, None), [controlTypes.stateLabels[controlTypes.STATE_SELECTED],controlTypes.negativeStateLabels[controlTypes.STATE_CHECKED]])