From 8e1bea5c05b5536bd2f4416bd7715ff3f169c9b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Fri, 29 May 2020 12:20:48 +0200 Subject: [PATCH 01/11] Braille tables improvements: groups, settings, etc. --- .../globalPlugins/brailleExtender/__init__.py | 95 +-- .../brailleExtender/brailleTablesExt.py | 578 ++++++++++++++++++ .../globalPlugins/brailleExtender/configBE.py | 55 +- .../brailleExtender/dictionaries.py | 58 +- .../globalPlugins/brailleExtender/settings.py | 254 +------- .../brailleExtender/undefinedChars.py | 19 +- addon/globalPlugins/brailleExtender/utils.py | 34 +- 7 files changed, 716 insertions(+), 377 deletions(-) create mode 100644 addon/globalPlugins/brailleExtender/brailleTablesExt.py diff --git a/addon/globalPlugins/brailleExtender/__init__.py b/addon/globalPlugins/brailleExtender/__init__.py index ade7faee..389ef98f 100644 --- a/addon/globalPlugins/brailleExtender/__init__.py +++ b/addon/globalPlugins/brailleExtender/__init__.py @@ -49,6 +49,7 @@ from . import utils from .updateCheck import * from . import advancedInputMode +from . import brailleTablesExt from . import dictionaries from . import huc from . import patchs @@ -173,8 +174,7 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin): _pGestures = OrderedDict() rotorGES = {} noKC = None - if not configBE.noUnicodeTable: - backupInputTable = brailleInput.handler.table + backupInputTable = brailleInput.handler.table backupMessageTimeout = None backupShowCursor = False backupTether = utils.getTether() @@ -201,13 +201,13 @@ def __init__(self): self.backup__addTextWithFields = braille.TextInfoRegion._addTextWithFields self.backup__update = braille.TextInfoRegion.update self.backup__getTypeformFromFormatField = braille.TextInfoRegion._getTypeformFromFormatField - self.backup__brailleTableDict = config.conf["braille"]["translationTable"] braille.TextInfoRegion._addTextWithFields = decorator(braille.TextInfoRegion._addTextWithFields, "addTextWithFields") braille.TextInfoRegion.update = decorator(braille.TextInfoRegion.update, "update") braille.TextInfoRegion._getTypeformFromFormatField = decorator(braille.TextInfoRegion._getTypeformFromFormatField, "_getTypeformFromFormatField") if config.conf["brailleExtender"]["reverseScrollBtns"]: self.reverseScrollBtns() self.createMenu() advancedInputMode.initialize() + brailleTablesExt.initializeGroups() log.info(f"{addonName} {addonVersion} loaded ({round(time.time()-startTime, 2)}s)") def event_gainFocus(self, obj, nextHandler): @@ -247,7 +247,6 @@ def event_gainFocus(self, obj, nextHandler): configBE.curBD = braille.handler.display.name self.onReload(None, 1) - if self.backup__brailleTableDict != config.conf["braille"]["translationTable"]: self.reloadBrailleTables() nextHandler() return @@ -304,7 +303,6 @@ def createMenu(self): self.submenu_item = gui.mainFrame.sysTrayIcon.menu.InsertMenu(2, wx.ID_ANY, "%s (%s)" % (_("&Braille Extender"), addonVersion), self.submenu) def reloadBrailleTables(self): - self.backup__brailleTableDict = config.conf["braille"]["translationTable"] dictionaries.setDictTables() dictionaries.notifyInvalidTables() if config.conf["brailleExtender"]["tabSpace"]: @@ -320,7 +318,7 @@ def onDefaultDictionary(evt): @staticmethod def onTableDictionary(evt): - outTable = configBE.tablesTR[configBE.tablesFN.index(config.conf["braille"]["translationTable"])] + outTable = brailleTablesExt.listTablesDisplayName()[brailleTablesExt.listTablesFileName().index(config.conf["braille"]["translationTable"])] gui.mainFrame._popupSettingsDialog(dictionaries.DictionaryDlg, _("Table dictionary")+(" (%s)" % outTable), "table") @staticmethod @@ -628,7 +626,7 @@ def script_reportExtraInfos(self, gesture): def script_getTableOverview(self, gesture): inTable = brailleInput.handler.table.displayName - ouTable = configBE.tablesTR[configBE.tablesFN.index(config.conf["braille"]["translationTable"])] + ouTable = brailleTablesExt.listTablesDisplayName()[brailleTablesExt.listTablesFileName().index(config.conf["braille"]["translationTable"])] t = (_(" Input table")+": %s\n"+_("Output table")+": %s\n\n") % (inTable+' (%s)' % (brailleInput.handler.table.fileName), ouTable+' (%s)' % (config.conf["braille"]["translationTable"])) t += utils.getTableOverview() ui.browseableMessage("
%s
" % t, _("Table overview (%s)" % brailleInput.handler.table.displayName), True) @@ -855,54 +853,70 @@ def script_decreaseDelayAutoScroll(self, gesture): script_decreaseDelayAutoScroll.__doc__ = _("Decrease autoscroll delay") def script_switchInputBrailleTable(self, gesture): - if configBE.noUnicodeTable: - return ui.message(_("Please use NVDA 2017.3 minimum for this feature")) - if len(configBE.inputTables) < 2: - return ui.message(_("You must choose at least two tables for this feature. Please fill in the settings")) - if not config.conf["braille"]["inputTable"] in configBE.inputTables: - configBE.inputTables.append(config.conf["braille"]["inputTable"]) - tid = configBE.inputTables.index(config.conf["braille"]["inputTable"]) - nID = tid + 1 if tid + 1 < len(configBE.inputTables) else 0 - brailleInput.handler.table = brailleTables.listTables( - )[configBE.tablesFN.index(configBE.inputTables[nID])] - ui.message(_("Input: %s") % brailleInput.handler.table.displayName) - return + usableIn = brailleTablesExt.USABLE_INPUT + choices = brailleTablesExt.getPreferredTables()[0] + brailleTablesExt.getGroups(0)[0] + if len(choices) < 2: + return ui.message(_("Please fill at least two tables and/or groups of tables for this feature first")) + newGroup = brailleTablesExt.getGroup( + position=brailleTablesExt.POSITION_NEXT, + usableIn=usableIn + ) + res = brailleTablesExt.setTableOrGroup( + usableIn=usableIn, + e=newGroup + ) + table = brailleTablesExt.getTable(newGroup.members[0] if newGroup else config.conf["braille"]["inputTable"]) + if table: brailleInput.handler._table = table + if not res: raise RuntimeError("error") + self.reloadBrailleTables() + utils.refreshBD() + dictionaries.setDictTables() + desc = (newGroup.name + (" (%s)" % _("group") if len(newGroup.members) > 1 else '') if newGroup else _("Default") + " (%s)" % brailleInput.handler.table.displayName) + ui.message(_("Input: %s") % desc) - script_switchInputBrailleTable.__doc__ = _( - "Switch between his favorite input braille tables") + script_switchInputBrailleTable.__doc__ = _("Switch between your favorite input braille tables including groups") def script_switchOutputBrailleTable(self, gesture): - if configBE.noUnicodeTable: - return ui.message( - _("Please use NVDA 2017.3 minimum for this feature")) - if len(configBE.outputTables) < 2: - return ui.message(_("You must choose at least two tables for this feature. Please fill in the settings")) - if not config.conf["braille"]["translationTable"] in configBE.outputTables: - configBE.outputTables.append(config.conf["braille"]["translationTable"]) - tid = configBE.outputTables.index( - config.conf["braille"]["translationTable"]) - nID = tid + 1 if tid + 1 < len(configBE.outputTables) else 0 - config.conf["braille"]["translationTable"] = configBE.outputTables[nID] + usableIn = brailleTablesExt.USABLE_OUTPUT + choices = brailleTablesExt.getPreferredTables()[1] + brailleTablesExt.getGroups(0)[1] + if len(choices) < 2: + return ui.message(_("Please fill at least two tables and/or groups of tables for this feature first")) + newGroup = brailleTablesExt.getGroup( + position=brailleTablesExt.POSITION_NEXT, + usableIn=usableIn + ) + res = brailleTablesExt.setTableOrGroup( + usableIn=usableIn, + e=newGroup + ) + if not res: raise RuntimeError("error") + self.reloadBrailleTables() utils.refreshBD() dictionaries.setDictTables() - ui.message(_("Output: %s") % configBE.tablesTR[configBE.tablesFN.index(config.conf["braille"]["translationTable"])]) - return + desc = (newGroup.name + (" (%s)" % _("group") if len(newGroup.members) > 1 else '') if newGroup else (_("Default") + " (%s)" % brailleTablesExt.fileName2displayName([config.conf["braille"]["translationTable"]])[0])) + ui.message(_("Output: %s") % desc) - script_switchOutputBrailleTable.__doc__ = _("Switch between his favorite output braille tables") + script_switchOutputBrailleTable.__doc__ = _("Switch between your favorite output braille tables including groups") def script_currentBrailleTable(self, gesture): - inTable = brailleInput.handler.table.displayName - ouTable = configBE.tablesTR[configBE.tablesFN.index(config.conf["braille"]["translationTable"])] + inTable = None + ouTable = None + if brailleTablesExt.groupEnabled(): + i = brailleTablesExt.getGroup(brailleTablesExt.USABLE_INPUT) + o = brailleTablesExt.getGroup(brailleTablesExt.USABLE_OUTPUT) + if i: inTable = i.name + if o: ouTable = o.name + if not inTable: inTable = brailleInput.handler.table.displayName + if not ouTable: ouTable = brailleTablesExt.listTablesDisplayName()[brailleTablesExt.listTablesFileName().index(config.conf["braille"]["translationTable"])] if ouTable == inTable: braille.handler.message(_("I⣿O:{I}").format(I=inTable, O=ouTable)) speech.speakMessage(_("Input and output: {I}.").format(I=inTable, O=ouTable)) else: braille.handler.message(_("I:{I} ⣿ O: {O}").format(I=inTable, O=ouTable)) speech.speakMessage(_("Input: {I}; Output: {O}").format(I=inTable, O=ouTable)) - return script_currentBrailleTable.__doc__ = _( - "Announce the current input and output braille tables") + "Announce the current input and output braille tables and/or groups") def script_brlDescChar(self, gesture): utils.currentCharDesc() @@ -1322,8 +1336,7 @@ def terminate(self): self.removeMenu() self.restorReviewCursorTethering() configBE.discardRoleLabels() - if configBE.noUnicodeTable: - brailleInput.handler.table = self.backupInputTable + brailleInput.handler.table = self.backupInputTable if self.hourDatePlayed: self.hourDateTimer.Stop() if configBE.noMessageTimeout: diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/brailleTablesExt.py new file mode 100644 index 00000000..83723cf9 --- /dev/null +++ b/addon/globalPlugins/brailleExtender/brailleTablesExt.py @@ -0,0 +1,578 @@ +# coding: utf-8 +# brailleTablesExt.py +# Part of BrailleExtender addon for NVDA +# Copyright 2016-2020 André-Abush CLAUSE, released under GPL. + +import codecs +import json +import gui +import wx + +import addonHandler +import brailleTables +import config +from collections import namedtuple +from itertools import permutations +from typing import Optional, List, Tuple +from brailleTables import listTables +from logHandler import log +from . import configBE +from .common import * + +addonHandler.initTranslation() + +POSITION_CURRENT = "c" +POSITION_PREVIOUS = "p" +POSITION_NEXT = "n" +POSITIONS = [POSITION_CURRENT, POSITION_PREVIOUS, POSITION_NEXT] + +USABLE_INPUT = 'i' +USABLE_OUTPUT = 'o' +USABLE_LIST = [USABLE_INPUT, USABLE_OUTPUT] + +GroupTables = namedtuple("GroupTables", ("name", "members", "usableIn")) + +listContractedTables = lambda tables=None: [table for table in (tables or listTables()) if table.contracted] +listUncontractedTables = lambda tables=None: [table for table in (tables or listTables()) if not table.contracted] +listInputTables = lambda tables=None: [table for table in (tables or listTables()) if table.input] +listUncontractedInputTables = listInputTables(listUncontractedTables()) +listOutputTables = lambda tables=None: [table for table in (tables or listTables()) if table.output] +listTablesFileName = lambda tables=None: [table.fileName for table in (tables or listTables())] +listTablesDisplayName = lambda tables=None: [table.displayName for table in (tables or listTables())] + +def fileName2displayName(l): + allTablesFileName = listTablesFileName() + o = [] + for e in l: + if e in allTablesFileName: o.append(allTablesFileName.index(e)) + return [listTables()[e].displayName for e in o] + +def listTablesIndexes(l, tables): + if not tables: tables = listTables() + tables = listTablesFileName(tables) + return [tables.index(e) for e in l if e in tables] + +def getPreferredTables() -> Tuple[List[str]]: + allInputTablesFileName = listTablesFileName(listInputTables()) + allOutputTablesFileName = listTablesFileName(listOutputTables()) + preferredInputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredInput"].split('|') + preferredOutputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredOutput"].split('|') + inputTables = [fn for fn in preferredInputTablesFileName if fn in allInputTablesFileName] + outputTables = [fn for fn in preferredOutputTablesFileName if fn in allOutputTablesFileName] + return inputTables, outputTables + +def getPreferredTablesIndexes() -> List[int]: + preferredInputTables, preferredOutputTables = getPreferredTables() + inputTables = listTablesFileName(listInputTables()) + outputTables = listTablesFileName(listOutputTables()) + o = [] + for a, b in [(preferredInputTables, inputTables), (preferredOutputTables, outputTables)]: + o_ = [] + for e in a: + if e in b: o_.append(b.index(e)) + o.append(o_) + return o + +def getCustomBrailleTables(): + return [config.conf["brailleExtender"]["brailleTables"][k].split('|', 3) for k in config.conf["brailleExtender"]["brailleTables"]] + +def isContractedTable(fileName): + return fileName in listTablesFileName(listContractedTables()) +def getTable(fileName, tables=None): + if not tables: tables = listTables() + for table in tables: + if table.fileName == fileName: return table + return None + +def getTablesFilenameByID(l: List[int], tables=None) -> List[int]: + tablesFileName = [table.fileName for table in (tables or listTables())] + o = [] + size = len(tablesFileName) + for i in l: + if i < size: o.append(tablesFileName[i]) + return o + +def translateUsableIn(s): + labels = { + 'i': _("input"), + 'o': _("output"), + 'io': _("input and output") + } + return labels[s] if s in labels.keys() else _("None") + +def translateUsableInIndexes(usableIn): + o = [] + if 'i' in usableIn: o.append(0) + if 'o' in usableIn: o.append(1) + return o + +def setDict(newGroups): + global _groups + _groups = newGroups + +def getPathGroups(): + return f"{configDir}/groups-tables.json" + +def initializeGroups(): + global _groups + _groups = [] + fp = getPathGroups() + if not os.path.exists(fp): + return + json_ = json.load(codecs.open(fp, "r", "UTF-8")) + for entry in json_: + _groups.append( + GroupTables( + entry["name"], entry["members"], entry["usableIn"] + ) + ) + +def saveGroups(entries=None): + if not entries: entries = getGroups() + entries = [ + { + "name": entry.name, + "members": entry.members, + "usableIn": entry.usableIn + } + for entry in entries + ] + with codecs.open(getPathGroups(), "w", "UTF-8") as outfile: + json.dump(entries, outfile, ensure_ascii=False, indent=2) + +def getGroups(plain=True): + if plain: return _groups if _groups else [] + groups = getGroups() + i = [group for group in groups if group.usableIn in ['i', 'io']] + o = [group for group in groups if group.usableIn in ['o', 'io']] + return i, o + +def getAllGroups(usableIn): + usableInIndex = USABLE_LIST.index(usableIn) + return [None] +tablesToGroups(getPreferredTables()[usableInIndex], usableIn=usableIn) + getGroups(0)[usableInIndex] + +def getGroup( + usableIn, + position=POSITION_CURRENT, + choices=None +): + global _currentGroup + if position not in POSITIONS or usableIn not in USABLE_LIST: return None + usableInIndex = USABLE_LIST.index(usableIn) + currentGroup = _currentGroup[usableInIndex] + if not choices: choices = getAllGroups(usableIn) + if currentGroup not in choices: + currentGroup = choices[0] + curPos = choices.index(currentGroup) + newPos = curPos + if position == POSITION_PREVIOUS: newPos = curPos - 1 + elif position == POSITION_NEXT: newPos = curPos + 1 + return choices[newPos % len(choices)] + +def setTableOrGroup(usableIn, e, choices=None): + global _currentGroup + if not usableIn in USABLE_LIST: return False + usableInIndex = USABLE_LIST.index(usableIn) + choices = getAllGroups(usableIn) + if not e in choices: return False + _currentGroup[usableInIndex] = e + return True + +def tablesToGroups(tables, usableIn): + groups = [] + for table in tables: + groups.append(GroupTables( + ", ".join(fileName2displayName([table])), + [table], + usableIn + )) + return groups + +def groupEnabled(): + return bool(_groups) + +_groups = None +_currentGroup = [None, None] + + +class BrailleTablesDlg(gui.settingsDialogs.SettingsPanel): + + # Translators: title of a dialog. + title = _("Braille tables") + + def makeSettings(self, settingsSizer): + listPreferredTablesIndexes = getPreferredTablesIndexes() + currentTableLabel = _("Use the current input table") + sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) + bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) + + tables = [f"{table.displayName}, {table.fileName}" for table in listTables() if table.input] + label = _("Preferred &input tables") + self.inputTables = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=tables) + self.inputTables.CheckedItems = listPreferredTablesIndexes[0] + self.inputTables.Select(0) + + tables = [f"{table.displayName}, {table.fileName}" for table in listTables() if table.output] + label = _("Preferred &output tables") + self.outputTables = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=tables) + self.outputTables.CheckedItems = listPreferredTablesIndexes[1] + self.outputTables.Select(0) + + label = _("Input braille table to use for keyboard shortcuts") + try: + selectedItem = 0 if config.conf["brailleExtender"]["tables"]["shortcuts"] == '?' else listTablesFileName( + listUncontractedInputTables + ).index(config.conf["brailleExtender"]["tables"]["shortcuts"]) + 1 + except ValueError: + selectedItem = 0 + self.inputTableShortcuts = sHelper.addLabeledControl(label, wx.Choice, choices=[currentTableLabel] + listTablesDisplayName(listUncontractedInputTables)) + self.inputTableShortcuts.SetSelection(selectedItem) + + self.tablesGroupBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Groups of tables"), wx.DefaultPosition) + self.tablesGroupBtn.Bind(wx.EVT_BUTTON, self.onTablesGroupsBtn) + + self.customBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("Alternative and &custom braille tables"), wx.DefaultPosition) + self.customBrailleTablesBtn.Bind(wx.EVT_BUTTON, self.onCustomBrailleTablesBtn) + + # Translators: label of a dialog. + self.tabSpace = sHelper.addItem(wx.CheckBox(self, label=_("Display &tab signs as spaces"))) + self.tabSpace.SetValue(config.conf["brailleExtender"]["tabSpace"]) + self.tabSpace.Bind(wx.EVT_CHECKBOX, self.onTabSpace) + + # Translators: label of a dialog. + self.tabSize = sHelper.addLabeledControl(_("Number of &space for a tab sign")+" "+_("for the currrent braille display"), gui.nvdaControls.SelectOnFocusSpinCtrl, min=1, max=42, initial=int(config.conf["brailleExtender"]["tabSize_%s" % configBE.curBD])) + sHelper.addItem(bHelper1) + self.onTabSpace() + + def onTabSpace(self, evt=None): + if self.tabSpace.IsChecked(): self.tabSize.Enable() + else: self.tabSize.Disable() + + def onTablesGroupsBtn(self, evt): + tablesGroupsDlg = TablesGroupsDlg(self, multiInstanceAllowed=True) + tablesGroupsDlg.ShowModal() + + def onCustomBrailleTablesBtn(self, evt): + customBrailleTablesDlg = CustomBrailleTablesDlg(self, multiInstanceAllowed=True) + customBrailleTablesDlg.ShowModal() + + def postInit(self): self.tables.SetFocus() + + def isValid(self): + if self.tabSize.Value > 42: + gui.messageBox( + _("Tab size is invalid"), + _("Error"), + wx.OK|wx.ICON_ERROR, + self + ) + self.tabSize.SetFocus() + return False + return super().isValid() + + def onSave(self): + inputTables = '|'.join(getTablesFilenameByID( + self.inputTables.CheckedItems, + listInputTables() + )) + outputTables = '|'.join( + getTablesFilenameByID( + self.outputTables.CheckedItems, + listOutputTables() + ) + ) + tablesShortcuts = getTablesFilenameByID( + [self.inputTableShortcuts.GetSelection()-1], + listUncontractedInputTables + )[0] if self.inputTableShortcuts.GetSelection() > 0 else '?' + config.conf["brailleExtender"]["tables"]["preferredInput"] = inputTables + config.conf["brailleExtender"]["tables"]["preferredOutput"] = outputTables + config.conf["brailleExtender"]["tables"]["shortcuts"] = tablesShortcuts + config.conf["brailleExtender"]["tabSpace"] = self.tabSpace.IsChecked() + config.conf["brailleExtender"][f"tabSize_{configBE.curBD}"] = self.tabSize.Value + + def postSave(self): + configBE.initializePreferredTables() + + +class TablesGroupsDlg(gui.settingsDialogs.SettingsDialog): + + # Translators: title of a dialog. + title = f"{addonName} - %s" % _("Groups of tables") + + def makeSettings(self, settingsSizer): + self.tmpGroups = getGroups() + self.tmpGroups.sort(key=lambda e: e.name) + sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) + groupsLabelText = _("List of table groups") + self.groupsList = sHelper.addLabeledControl(groupsLabelText, wx.ListCtrl, style=wx.LC_REPORT|wx.LC_SINGLE_SEL,size=(550,350)) + self.groupsList.InsertColumn(0, _("Name"), width=150) + self.groupsList.InsertColumn(1, _("Members"), width=150) + self.groupsList.InsertColumn(2, _("Usable in"), width=150) + self.onSetEntries() + + bHelper = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) + bHelper.addButton( + parent=self, + # Translators: The label for a button in groups of tables dialog to add new entries. + label=_("&Add") + ).Bind(wx.EVT_BUTTON, self.onAddClick) + + bHelper.addButton( + parent=self, + # Translators: The label for a button in groups of tables dialog to edit existing entries. + label=_("&Edit") + ).Bind(wx.EVT_BUTTON, self.onEditClick) + + bHelper.addButton( + parent=self, + # Translators: The label for a button in groups of tables dialog to remove existing entries. + label=_("Re&move") + ).Bind(wx.EVT_BUTTON, self.onRemoveClick) + + sHelper.addItem(bHelper) + bHelper = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) + bHelper.addButton( + parent=self, + # Translators: The label for a button in groups of tables dialog to open groups of tables file in an editor. + label=_("&Open the groups of tables file in an editor") + ).Bind(wx.EVT_BUTTON, self.onOpenFileClick) + bHelper.addButton( + parent=self, + # Translators: The label for a button in groups of tables dialog to reload groups of tables. + label=_("&Reload the groups of tables") + ).Bind(wx.EVT_BUTTON, self.onReloadClick) + sHelper.addItem(bHelper) + + def onSetEntries(self, evt=None): + self.groupsList.DeleteAllItems() + for group in self.tmpGroups: + self.groupsList.Append(( + group.name, + ", ".join(fileName2displayName(group.members)), + translateUsableIn(group.usableIn) + )) + + def onAddClick(self, event): + entryDialog = GroupEntryDlg(self, title=_("Add group entry")) + if entryDialog.ShowModal() == wx.ID_OK: + entry = entryDialog.groupEntry + self.tmpGroups.append(entry) + self.groupsList.Append( + (entry.name, ", ".join(fileName2displayName(entry.members)), translateUsableIn(entry.usableIn)) + ) + index = self.groupsList.GetFirstSelected() + while index >= 0: + self.groupsList.Select(index, on=0) + index = self.groupsList.GetNextSelected(index) + addedIndex = self.groupsList.GetItemCount() - 1 + self.groupsList.Select(addedIndex) + self.groupsList.Focus(addedIndex) + self.groupsList.SetFocus() + entryDialog.Destroy() + + def onEditClick(self, event): + if self.groupsList.GetSelectedItemCount() != 1: + return + editIndex = self.groupsList.GetFirstSelected() + entryDialog = GroupEntryDlg(self) + entryDialog.name.SetValue(self.tmpGroups[editIndex].name) + entryDialog.members.CheckedItems = listTablesIndexes(self.tmpGroups[editIndex].members, listUncontractedInputTables) + entryDialog.refreshOrders() + selectedItem = 0 + try: + selectedItem = list(entryDialog.orderPermutations.keys()).index(tuple(listTablesIndexes(self.tmpGroups[editIndex].members, listUncontractedTables()))) + entryDialog.order.SetSelection(selectedItem) + except ValueError: pass + entryDialog.usableIn.CheckedItems = translateUsableInIndexes(self.tmpGroups[editIndex].usableIn) + if entryDialog.ShowModal() == wx.ID_OK: + entry = entryDialog.groupEntry + self.tmpGroups[editIndex] = entry + self.groupsList.SetItem(editIndex, 0, entry.name) + self.groupsList.SetItem(editIndex, 1, ", ".join(fileName2displayName(entry.members))) + self.groupsList.SetItem(editIndex, 2, translateUsableIn(entry.usableIn)) + self.groupsList.SetFocus() + entryDialog.Destroy() + + def onRemoveClick(self, event): + index = self.groupsList.GetFirstSelected() + while index >= 0: + self.groupsList.DeleteItem(index) + del self.tmpGroups[index] + index = self.groupsList.GetNextSelected(index) + self.onSetEntries() + self.groupsList.SetFocus() + + + def onOpenFileClick(self,evt): + path = getPathGroups() + if not os.path.exists(path): return + try: os.startfile(path) + except OSError: os.popen(f"notepad \"{path}\"") + + def onReloadClick(self,evt): + self.tmpGroups = getGroups() + self.onSetEntries() + + def onOk(self, evt): + saveGroups(self.tmpGroups) + setDict(self.tmpGroups) + super().onOk(evt) + + +class GroupEntryDlg(wx.Dialog): + + orderPermutations = {} + + def __init__(self, parent=None, title=_("Edit Dictionary Entry")): + super().__init__(parent, title=title) + mainSizer = wx.BoxSizer(wx.VERTICAL) + sHelper = gui.guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL) + self.name = sHelper.addLabeledControl(_("Group name"), wx.TextCtrl) + label = _(f"Group members") + self.members = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=listTablesDisplayName(listUncontractedTables())) + self.members.SetSelection(0) + self.members.Bind(wx.EVT_CHECKLISTBOX, lambda s: self.refreshOrders()) + label = _("Usable in") + self.order = sHelper.addLabeledControl(_("Order of the tables"), wx.Choice, choices=[]) + self.refreshOrders() + choices = [_("input"), _("output")] + self.usableIn = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=choices) + self.usableIn.SetSelection(0) + sHelper.addDialogDismissButtons(self.CreateButtonSizer(wx.OK | wx.CANCEL)) + mainSizer.Add(sHelper.sizer, border=20, flag=wx.ALL) + mainSizer.Fit(self) + self.SetSizer(mainSizer) + self.Bind(wx.EVT_BUTTON, self.onOk, id=wx.ID_OK) + self.name.SetFocus() + + def refreshOrders(self, evt=None): + tables = listUncontractedTables() + self.orderPermutations = {e: fileName2displayName(getTablesFilenameByID(e, tables)) for e in permutations(self.members.CheckedItems) if e} + self.order.SetItems([", ".join(e) for e in self.orderPermutations.values()]) + self.order.SetSelection(0) + + def onOk(self, evt): + name = self.name.Value + if not self.orderPermutations: return + members = getTablesFilenameByID(list(self.orderPermutations.keys())[self.order.GetSelection()], listUncontractedTables()) + matches = ['i', 'o'] + usableIn = ''.join([matches[e] for e in self.usableIn.CheckedItems]) + if not name: + gui.messageBox( + _("Please specify a group name"), + _("Error"), + wx.OK|wx.ICON_ERROR, + self + ) + return self.name.SetFocus() + if len(members) < 2: + gui.messageBox( + _("Please select at least 2 tables"), + _("Error"), + wx.OK|wx.ICON_ERROR, + self + ) + return self.members.SetFocus() + self.groupEntry = GroupTables(name, members, usableIn) + evt.Skip() + +class CustomBrailleTablesDlg(gui.settingsDialogs.SettingsDialog): + + # Translators: title of a dialog. + title = f"{addonName} - %s" % _("Custom braille tables") + providedTablesPath = "%s/res/json" % baseDir + userTablesPath = "%s/json" % configDir + + def makeSettings(self, settingsSizer): + self.providedTables = self.getBrailleTablesFromJSON(self.providedTablesPath) + self.userTables = self.getBrailleTablesFromJSON(self.userTablesPath) + sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) + bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) + self.inTable = sHelper.addItem(wx.CheckBox(self, label=_("Use a custom table as input table"))) + self.outTable = sHelper.addItem(wx.CheckBox(self, label=_("Use a custom table as output table"))) + self.addBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Add a braille table"), wx.DefaultPosition) + self.addBrailleTablesBtn.Bind(wx.EVT_BUTTON, self.onAddBrailleTablesBtn) + sHelper.addItem(bHelper1) + + @staticmethod + def getBrailleTablesFromJSON(path): + if not os.path.exists(path): + path = "%s/%s" % (baseDir, path) + if not os.path.exists(path): return {} + f = open(path, "r") + return json.load(f) + + def onAddBrailleTablesBtn(self, evt): + addBrailleTablesDlg = AddBrailleTablesDlg(self, multiInstanceAllowed=True) + addBrailleTablesDlg.ShowModal() + + def postInit(self): self.inTable.SetFocus() + + def onOk(self, event): + super(CustomBrailleTablesDlg, self).onOk(evt) + + +class AddBrailleTablesDlg(gui.settingsDialogs.SettingsDialog): + # Translators: title of a dialog. + title = "Braille Extender - %s" % _("Add a braille table") + tbl = [] + + def makeSettings(self, settingsSizer): + sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) + bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) + self.name = sHelper.addLabeledControl(_("Display name"), wx.TextCtrl) + self.description = sHelper.addLabeledControl(_("Description"), wx.TextCtrl, style = wx.TE_MULTILINE|wx.TE_PROCESS_ENTER, size = (360, 90), pos=(-1,-1)) + self.path = sHelper.addLabeledControl(_("Path"), wx.TextCtrl) + self.browseBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Browse"), wx.DefaultPosition) + self.browseBtn.Bind(wx.EVT_BUTTON, self.onBrowseBtn) + sHelper.addItem(bHelper1) + self.isContracted = sHelper.addItem(wx.CheckBox(self, label=_("Contracted (grade 2) braille table"))) + # Translators: label of a dialog. + self.inputOrOutput = sHelper.addLabeledControl(_("Available for"), wx.Choice, choices=[_("Input and output"), _("Input only"), _("Output only")]) + self.inputOrOutput.SetSelection(0) + + def postInit(self): self.name.SetFocus() + + def onBrowseBtn(self, event): + dlg = wx.FileDialog(None, _("Choose a table file"), "%PROGRAMFILES%", "", "%s (*.ctb, *.cti, *.utb, *.uti)|*.ctb;*.cti;*.utb;*.uti" % _("Liblouis table files"), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + if dlg.ShowModal() != wx.ID_OK: + dlg.Destroy() + return self.path.SetFocus() + self.path.SetValue(dlg.GetDirectory() + '\\' + dlg.GetFilename()) + dlg.Destroy() + self.path.SetFocus() + + def onOk(self, event): + path = self.path.GetValue().strip().encode("UTF-8") + displayName = self.name.GetValue().strip() + if not displayName: + gui.messageBox(_("Please specify a display name."), _("Invalid display name"), wx.OK|wx.ICON_ERROR) + self.name.SetFocus() + return + if not os.path.exists(path.decode("UTF-8").encode("mbcs")): + gui.messageBox(_("The specified path is not valid (%s).") % path.decode("UTF-8"), _("Invalid path"), wx.OK|wx.ICON_ERROR) + self.path.SetFocus() + return + switch_possibleValues = ["both", "input", "output"] + v = "%s|%s|%s|%s" % ( + switch_possibleValues[self.inputOrOutput.GetSelection()], + self.isContracted.IsChecked(), path.decode("UTF-8"), displayName + ) + k = hashlib.md5(path).hexdigest()[:15] + config.conf["brailleExtender"]["brailleTables"][k] = v + super(AddBrailleTablesDlg, self).onOk(evt) + + @staticmethod + def getAvailableBrailleTables(): + out = [] + brailleTablesDir = configBE.TABLES_DIR + ls = glob.glob(brailleTablesDir+'\\*.ctb')+glob.glob(brailleTablesDir+'\\*.cti')+glob.glob(brailleTablesDir+'\\*.utb') + for i, e in enumerate(ls): + e = str(e.split('\\')[-1]) + if e in configBE.tablesFN or e.lower() in configBE.tablesFN: del ls[i] + else: out.append(e.lower()) + out = sorted(out) + return out + + diff --git a/addon/globalPlugins/brailleExtender/configBE.py b/addon/globalPlugins/brailleExtender/configBE.py index 60780d03..1bffd741 100644 --- a/addon/globalPlugins/brailleExtender/configBE.py +++ b/addon/globalPlugins/brailleExtender/configBE.py @@ -15,6 +15,7 @@ import configobj import inputCore import languageHandler +from . import brailleTablesExt from .common import * from .oneHandMode import DOT_BY_DOT, ONE_SIDE, BOTH_SIDES @@ -73,21 +74,12 @@ noMessageTimeout = True if 'noMessageTimeout' in config.conf["braille"] else False outputTables = inputTables = None -preTable = [] -postTable = [] +preTables = [] +postTables = [] if not os.path.exists(profilesDir): log.error('Profiles\' path not found') else: log.debug('Profiles\' path (%s) found' % profilesDir) -try: - import brailleTables - tables = brailleTables.listTables() - tablesFN = [t[0] for t in brailleTables.listTables()] - tablesUFN = [t[0] for t in brailleTables.listTables() if not t.contracted and t.output] - tablesTR = [t[1] for t in brailleTables.listTables()] - noUnicodeTable = False -except BaseException: - noUnicodeTable = True -def getValidBrailleDisplayPrefered(): +def getValidBrailleDisplayPreferred(): l = braille.getDisplayList() l.append(("last", _("last known"))) return l @@ -139,9 +131,6 @@ def getConfspec(): "stopSpeechUnknown": "boolean(default=True)", "speakRoutingTo": "boolean(default=True)", "routingReviewModeWithCursorKeys": "boolean(default=False)", - "inputTableShortcuts": 'string(default="?")', - "inputTables": 'string(default="%s")' % config.conf["braille"]["inputTable"] + ", unicode-braille.utb", - "outputTables": "string(default=%s)" % config.conf["braille"]["translationTable"], "tabSpace": "boolean(default=False)", f"tabSize_{curBD}": "integer(min=1, default=2, max=42)", "undefinedCharsRepr": { @@ -157,7 +146,6 @@ def getConfspec(): "lang": "string(default=Windows)", "table": "string(default=current)" }, - "postTable": 'string(default="None")', "viewSaved": "string(default=%s)" % NOVIEWSAVED, "reviewModeTerminal": "boolean(default=True)", "features": { @@ -211,7 +199,6 @@ def getConfspec(): }, "quickLaunches": {}, "roleLabels": {}, - "brailleTables": {}, "advancedInputMode": { "stopAfterOneChar": "boolean(default=True)", "escapeSignUnicodeValue": "string(default=⠼)", @@ -220,21 +207,14 @@ def getConfspec(): "enabled": "boolean(default=False)", "inputMethod": f"option({DOT_BY_DOT}, {BOTH_SIDES}, {ONE_SIDE}, default={ONE_SIDE})", }, + "tables": { + "groups": {}, + "shortcuts": 'string(default="?")', + "preferredInput": f'string(default="{config.conf["braille"]["inputTable"]}|unicode-braille.utb")', + "preferredOutput": f'string(default="{config.conf["braille"]["translationTable"]}")', + }, } -def loadPreferedTables(): - global inputTables, outputTables - listInputTables = [table[0] for table in brailleTables.listTables() if table.input] - listOutputTables = [table[0] for table in brailleTables.listTables() if table.output] - inputTables = config.conf["brailleExtender"]["inputTables"] - outputTables = config.conf["brailleExtender"]["outputTables"] - if not isinstance(inputTables, list): - inputTables = inputTables.replace(', ', ',').split(',') - if not isinstance(outputTables, list): - outputTables = outputTables.replace(', ', ',').split(',') - inputTables = [t for t in inputTables if t in listInputTables] - outputTables = [t for t in outputTables if t in listOutputTables] - def getLabelFromID(idCategory, idLabel): if idCategory == 0: return braille.roleLabels[int(idLabel)] elif idCategory == 1: return braille.landmarkLabels[idLabel] @@ -303,12 +283,16 @@ def loadConf(): limitCellsRight = int(config.conf["brailleExtender"]["rightMarginCells_%s" % curBD]) if (backupDisplaySize-limitCellsRight <= backupDisplaySize and limitCellsRight > 0): braille.handler.displaySize = backupDisplaySize-limitCellsRight - if not noUnicodeTable: loadPreferedTables() - if config.conf["brailleExtender"]["inputTableShortcuts"] not in tablesUFN: config.conf["brailleExtender"]["inputTableShortcuts"] = '?' + if config.conf["brailleExtender"]["tables"]["shortcuts"] not in brailleTablesExt.listTablesFileName(brailleTablesExt.listUncontractedTables()): config.conf["brailleExtender"]["tables"]["shortcuts"] = '?' if config.conf["brailleExtender"]["features"]["roleLabels"]: loadRoleLabels(config.conf["brailleExtender"]["roleLabels"].copy()) + initializePreferredTables() return True +def initializePreferredTables(): + global inputTables, outputTables + inputTables, outputTables = brailleTablesExt.getPreferredTables() + def loadGestures(): if gesturesFileExists: if os.path.exists(os.path.join(profilesDir, "_BrowseMode", config.conf["braille"]["inputTable"] + ".ini")): GLng = config.conf["braille"]["inputTable"] @@ -359,11 +343,6 @@ def initGestures(): iniGestures["globalCommands.GlobalCommands"][g])).replace('br(' + curBD + '):', '')] = g return gesturesFileExists, iniGestures -def isContractedTable(table): - if not table in tablesFN: return False - tablePos = tablesFN.index(table) - if brailleTables.listTables()[tablePos].contracted: return True - return False def getKeyboardLayout(): if (config.conf["brailleExtender"]["keyboardLayout_%s" % curBD] is not None @@ -371,8 +350,6 @@ def getKeyboardLayout(): return iniProfile['keyboardLayouts'].keys().index(config.conf["brailleExtender"]["keyboardLayout_%s" % curBD]) else: return 0 -def getCustomBrailleTables(): - return [config.conf["brailleExtender"]["brailleTables"][k].split('|', 3) for k in config.conf["brailleExtender"]["brailleTables"]] def getTabSize(): size = config.conf["brailleExtender"]["tabSize_%s" % curBD] diff --git a/addon/globalPlugins/brailleExtender/dictionaries.py b/addon/globalPlugins/brailleExtender/dictionaries.py index e8b8df1b..1156b48a 100644 --- a/addon/globalPlugins/brailleExtender/dictionaries.py +++ b/addon/globalPlugins/brailleExtender/dictionaries.py @@ -18,7 +18,9 @@ from collections import namedtuple from . import configBE from .common import * +from . import brailleTablesExt from . import huc +from logHandler import log TableDictEntry = namedtuple("TableDictEntry", ("opcode", "textPattern", "braillePattern", "direction", "comment")) OPCODE_SIGN = "sign" @@ -44,27 +46,40 @@ } DIRECTION_LABELS_ORDERING = (DIRECTION_BOTH, DIRECTION_FORWARD, DIRECTION_BACKWARD) -dictTables = [] -invalidDictTables = set() +inputTables = [] +outputTables = [] +invalidTables = set() def checkTable(path): - global invalidDictTables - try: - louis.checkTable([path]) - return True - except RuntimeError: invalidDictTables.add(path) - return False - -def getValidPathsDict(): + global invalidTables + tablesString = b",".join([x.encode("mbcs") if isinstance(x, str) else bytes(x) for x in [path]]) + if not louis.liblouis.lou_checkTable(tablesString): + log.error("Can't compile: tables %s" % path) + invalidTables.add(path) + return False + return True + +def getValidPathsDict(usableIn): types = ["tmp", "table", "default"] - paths = [getPathDict(type_) for type_ in types] + paths = [getPathDict(type_, usableIn) for type_ in types] valid = lambda path: os.path.exists(path) and os.path.isfile(path) and checkTable(path) return [path for path in paths if valid(path)] -def getPathDict(type_): - if type_ == "table": path = os.path.join(configDir, "brailleDicts", config.conf["braille"]["translationTable"]) +def getPathDict(type_, usableIn): + groupEnabled = brailleTablesExt.groupEnabled() + g = brailleTablesExt.getGroup(usableIn=usableIn) + table = os.path.join(configDir, "brailleDicts", config.conf["braille"]["inputTable"]) if usableIn == brailleTablesExt.USABLE_INPUT else config.conf["braille"]["translationTable"] + if type_ == "table": + if groupEnabled and g and g.members: + if len(g.members) == 1: path = os.path.join(configDir, "brailleDicts", g.members[0]) + else: path = '' + else: path = os.path.join(configDir, "brailleDicts", table) elif type_ == "tmp": path = os.path.join(configDir, "brailleDicts", "tmp") - else: path = os.path.join(configDir, "brailleDicts", "default") + else: + if groupEnabled and g and g.members: + if len(g.members) == 1: path = os.path.join(configDir, "brailleDicts", "default") + else: path = '' + else: path = os.path.join(configDir, "brailleDicts", "default") return "%s.cti" % path def getDictionary(type_): @@ -95,18 +110,19 @@ def saveDict(type_, dict_): return True def setDictTables(): - global dictTables - dictTables = getValidPathsDict() - invalidDictTables.clear() + global inputTables, outTable + inputTables = getValidPathsDict(brailleTablesExt.USABLE_INPUT) + outputTables = getValidPathsDict(brailleTablesExt.USABLE_OUTPUT) + invalidTables.clear() def notifyInvalidTables(): - if invalidDictTables: + if invalidTables: dicts = { getPathDict("default"): "default", getPathDict("table"): "table", getPathDict("tmp"): "tmp" } - msg = _("One or more errors are present in dictionaries tables. Concerned dictionaries: %s. As a result, these dictionaries are not loaded.") % ", ".join([dicts[path] for path in invalidDictTables if path in dicts]) + msg = _("One or more errors are present in dictionaries tables. Concerned dictionaries: %s. As a result, these dictionaries are not loaded.") % ", ".join([dicts[path] for path in invalidTables if path in dicts]) wx.CallAfter(gui.messageBox, msg, _("Braille Extender"), wx.OK|wx.ICON_ERROR) def removeTmpDict(): @@ -292,7 +308,7 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry"), textPattern='' if specifyDict: # Translators: This is a label for an edit field in add dictionary entry dialog. dictText = _("Dictionary") - outTable = configBE.tablesTR[configBE.tablesFN.index(config.conf["braille"]["translationTable"])] + outTable = brailleTablesExt.fileName2displayName(config.conf["braille"]["translationTable"]) dictChoices = [_("Global"), _("Table")+(" (%s)" % outTable), _("Temporary")] self.dictRadioBox = sHelper.addItem(wx.RadioBox(self, label=dictText, choices=dictChoices)) self.dictRadioBox.SetSelection(1) @@ -338,7 +354,7 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry"), textPattern='' def onSeeEntriesClick(self, evt): - outTable = configBE.tablesTR[configBE.tablesFN.index(config.conf["braille"]["translationTable"])] + outTable = brailleTablesExt.fileName2displayName(config.conf["braille"]["translationTable"]) label = [_("Global dictionary"), _("Table dictionary")+(" (%s)" % outTable), _("Temporary dictionary")][self.dictRadioBox.GetSelection()] type_ = self.getType_() self.Destroy() diff --git a/addon/globalPlugins/brailleExtender/settings.py b/addon/globalPlugins/brailleExtender/settings.py index 99b38a4a..95e2feae 100644 --- a/addon/globalPlugins/brailleExtender/settings.py +++ b/addon/globalPlugins/brailleExtender/settings.py @@ -23,6 +23,7 @@ import ui addonHandler.initTranslation() +from . import brailleTablesExt from . import configBE from . import utils from .advancedInputMode import SettingsDlg as AdvancedInputModeDlg @@ -39,8 +40,8 @@ class GeneralDlg(gui.settingsDialogs.SettingsPanel): # Translators: title of a dialog. title = _("General") - bds_k = [k for k, v in configBE.getValidBrailleDisplayPrefered()] - bds_v = [v for k, v in configBE.getValidBrailleDisplayPrefered()] + bds_k = [k for k, v in configBE.getValidBrailleDisplayPreferred()] + bds_v = [v for k, v in configBE.getValidBrailleDisplayPreferred()] def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) @@ -325,253 +326,6 @@ def onSave(self): if config.conf["brailleExtender"]["features"]["roleLabels"]: configBE.loadRoleLabels(config.conf["brailleExtender"]["roleLabels"].copy()) -class BrailleTablesDlg(gui.settingsDialogs.SettingsPanel): - - # Translators: title of a dialog. - title = _("Braille tables") - - def makeSettings(self, settingsSizer): - self.oTables = set(configBE.outputTables) - self.iTables = set(configBE.inputTables) - lt = [_("Use the current input table")] - for table in configBE.tables: - if table.output and not table.contracted: lt.append(table[1]) - if config.conf["brailleExtender"]["inputTableShortcuts"] in configBE.tablesUFN: - iSht = configBE.tablesUFN.index(config.conf["brailleExtender"]["inputTableShortcuts"]) + 1 - else: iSht = 0 - sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) - bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) - - self.tables = sHelper.addLabeledControl(_("Prefered braille tables")+" (%s)" % _("press F1 for help"), wx.Choice, choices=self.getTablesWithSwitches()) - self.tables.SetSelection(0) - self.tables.Bind(wx.EVT_CHAR, self.onTables) - - self.inputTableShortcuts = sHelper.addLabeledControl(_("Input braille table for keyboard shortcut keys"), wx.Choice, choices=lt) - self.inputTableShortcuts.SetSelection(iSht) - lt = [_('None')] - for table in configBE.tables: - if table.output: lt.append(table[1]) - self.postTable = sHelper.addLabeledControl(_("Secondary output table to use"), wx.Choice, choices=lt) - self.postTable.SetSelection(configBE.tablesFN.index(config.conf["brailleExtender"]["postTable"]) if config.conf["brailleExtender"]["postTable"] in configBE.tablesFN else 0) - - # Translators: label of a dialog. - self.tabSpace = sHelper.addItem(wx.CheckBox(self, label=_("Display &tab signs as spaces"))) - self.tabSpace.SetValue(config.conf["brailleExtender"]["tabSpace"]) - - # Translators: label of a dialog. - self.tabSize = sHelper.addLabeledControl(_("Number of &space for a tab sign")+" "+_("for the currrent braille display"), gui.nvdaControls.SelectOnFocusSpinCtrl, min=1, max=42, initial=int(config.conf["brailleExtender"]["tabSize_%s" % configBE.curBD])) - self.customBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("Alternative and &custom braille tables"), wx.DefaultPosition) - self.customBrailleTablesBtn.Bind(wx.EVT_BUTTON, self.onCustomBrailleTablesBtn) - sHelper.addItem(bHelper1) - - def postInit(self): self.tables.SetFocus() - - def onSave(self): - config.conf["brailleExtender"]["outputTables"] = ','.join(self.oTables) - config.conf["brailleExtender"]["inputTables"] = ','.join(self.iTables) - config.conf["brailleExtender"]["inputTableShortcuts"] = configBE.tablesUFN[self.inputTableShortcuts.GetSelection()-1] if self.inputTableShortcuts.GetSelection()>0 else '?' - postTableID = self.postTable.GetSelection() - postTable = "None" if postTableID == 0 else configBE.tablesFN[postTableID] - config.conf["brailleExtender"]["postTable"] = postTable - if self.tabSpace.IsChecked() and config.conf["brailleExtender"]["tabSpace"] != self.tabSpace.IsChecked(): - restartRequired = True - else: restartRequired = False - config.conf["brailleExtender"]["tabSpace"] = self.tabSpace.IsChecked() - config.conf["brailleExtender"]["tabSize_%s" % configBE.curBD] = self.tabSize.Value - if restartRequired: - res = gui.messageBox( - _("NVDA must be restarted for some new options to take effect. Do you want restart now?"), - _("Braille Extender"), - style=wx.YES_NO|wx.ICON_INFORMATION - ) - if res == wx.YES: core.restart() - - def getTablesWithSwitches(self): - out = [] - for i, tbl in enumerate(configBE.tablesTR): - out.append("%s%s: %s" % (tbl, punctuationSeparator, self.getInSwitchesText(configBE.tablesFN[i]))) - return out - - def getCurrentSelection(self): - idx = self.tables.GetSelection() - tbl = configBE.tablesFN[self.tables.GetSelection()] - return idx, tbl - - def setCurrentSelection(self, tbl, newLoc): - if newLoc == "io": - self.iTables.add(tbl) - self.oTables.add(tbl) - elif newLoc == "i": - self.iTables.add(tbl) - self.oTables.discard(tbl) - elif newLoc == "o": - self.oTables.add(tbl) - self.iTables.discard(tbl) - elif newLoc == "n": - self.iTables.discard(tbl) - self.oTables.discard(tbl) - - def inSwitches(self, tbl): - inp = tbl in self.iTables - out = tbl in self.oTables - return [inp, out] - - def getInSwitchesText(self, tbl): - inS = self.inSwitches(tbl) - if all(inS): inSt = _("input and output") - elif not any(inS): inSt = _("none") - elif inS[0]: inSt = _("input only") - elif inS[1]: inSt = _("output only") - return inSt - - def changeSwitch(self, tbl, direction=1, loop=True): - dirs = ['n', 'i', 'o', "io"] - iCurDir = 0 - inS = self.inSwitches(tbl) - if all(inS): iCurDir = dirs.index("io") - elif not any(inS): iCurDir = dirs.index('n') - elif inS[0]: iCurDir = dirs.index('i') - elif inS[1]: iCurDir = dirs.index('o') - - if len(dirs)-1 == iCurDir and direction == 1 and loop: newDir = dirs[0] - elif iCurDir == 0 and direction == 0 and loop: newDir = dirs[-1] - elif iCurDir < len(dirs)-1 and direction == 1: newDir = dirs[iCurDir+1] - elif iCurDir > 0 and iCurDir < len(dirs) and direction == 0: newDir = dirs[iCurDir-1] - else: return - self.setCurrentSelection(tbl, newDir) - - def onCustomBrailleTablesBtn(self, evt): - customBrailleTablesDlg = CustomBrailleTablesDlg(self, multiInstanceAllowed=True) - customBrailleTablesDlg.ShowModal() - - def onTables(self, evt): - keycode = evt.GetKeyCode() - if keycode in [ord(','), ord(';')]: - idx, tbl = self.getCurrentSelection() - if keycode == ord(','): - queueHandler.queueFunction(queueHandler.eventQueue, ui.message, "%s" % tbl) - else: - ui.browseableMessage('\n'.join([ - _("Table name: %s") % configBE.tablesTR[idx], - _("File name: %s") % tbl, - _("In switches: %s") % self.getInSwitchesText(tbl) - ]), _("About this table"), False) - if keycode == wx.WXK_F1: - ui.browseableMessage( - _("In this combo box, all tables are present. Press space bar, left or right arrow keys to include (or not) the selected table in switches")+".\n"+ - _("You can also press 'comma' key to get the file name of the selected table and 'semicolon' key to view miscellaneous infos on the selected table")+".", - _("Contextual help"), False) - if keycode in [wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_SPACE]: - idx, tbl = self.getCurrentSelection() - if keycode == wx.WXK_LEFT: self.changeSwitch(tbl, 0, False) - elif keycode == wx.WXK_RIGHT: self.changeSwitch(tbl, 1, False) - elif keycode == wx.WXK_SPACE: self.changeSwitch(tbl, 1, True) - newSwitch = self.getInSwitchesText(tbl) - self.tables.SetString(self.tables.GetSelection(), "%s%s: %s" % (configBE.tablesTR[idx], punctuationSeparator, newSwitch)) - queueHandler.queueFunction(queueHandler.eventQueue, ui.message, "%s" % newSwitch) - utils.refreshBD() - else: evt.Skip() - - -class CustomBrailleTablesDlg(gui.settingsDialogs.SettingsDialog): - - # Translators: title of a dialog. - title = "Braille Extender - %s" % _("Custom braille tables") - providedTablesPath = "%s/res/brailleTables.json" % configBE.baseDir - userTablesPath = "%s/brailleTables.json" % configBE.configDir - - def makeSettings(self, settingsSizer): - self.providedTables = self.getBrailleTablesFromJSON(self.providedTablesPath) - self.userTables = self.getBrailleTablesFromJSON(self.userTablesPath) - wx.CallAfter(notImplemented) - sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) - bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) - self.inTable = sHelper.addItem(wx.CheckBox(self, label=_("Use a custom table as input table"))) - self.outTable = sHelper.addItem(wx.CheckBox(self, label=_("Use a custom table as output table"))) - self.addBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Add a braille table"), wx.DefaultPosition) - self.addBrailleTablesBtn.Bind(wx.EVT_BUTTON, self.onAddBrailleTablesBtn) - sHelper.addItem(bHelper1) - - @staticmethod - def getBrailleTablesFromJSON(path): - if not os.path.exists(path): - path = "%s/%s" % (configBE.baseDir, path) - if not os.path.exists(path): return {} - f = open(path, "r") - return json.load(f) - - def onAddBrailleTablesBtn(self, evt): - addBrailleTablesDlg = AddBrailleTablesDlg(self, multiInstanceAllowed=True) - addBrailleTablesDlg.ShowModal() - - def postInit(self): self.inTable.SetFocus() - - def onOk(self, event): - super(CustomBrailleTablesDlg, self).onOk(evt) - - -class AddBrailleTablesDlg(gui.settingsDialogs.SettingsDialog): - # Translators: title of a dialog. - title = "Braille Extender - %s" % _("Add a braille table") - tbl = [] - - def makeSettings(self, settingsSizer): - sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) - bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) - self.name = sHelper.addLabeledControl(_("Display name"), wx.TextCtrl) - self.description = sHelper.addLabeledControl(_("Description"), wx.TextCtrl, style = wx.TE_MULTILINE|wx.TE_PROCESS_ENTER, size = (360, 90), pos=(-1,-1)) - self.path = sHelper.addLabeledControl(_("Path"), wx.TextCtrl) - self.browseBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Browse"), wx.DefaultPosition) - self.browseBtn.Bind(wx.EVT_BUTTON, self.onBrowseBtn) - sHelper.addItem(bHelper1) - self.isContracted = sHelper.addItem(wx.CheckBox(self, label=_("Contracted (grade 2) braille table"))) - # Translators: label of a dialog. - self.inputOrOutput = sHelper.addLabeledControl(_("Available for"), wx.Choice, choices=[_("Input and output"), _("Input only"), _("Output only")]) - self.inputOrOutput.SetSelection(0) - - def postInit(self): self.name.SetFocus() - - def onBrowseBtn(self, event): - dlg = wx.FileDialog(None, _("Choose a table file"), "%PROGRAMFILES%", "", "%s (*.ctb, *.cti, *.utb, *.uti)|*.ctb;*.cti;*.utb;*.uti" % _("Liblouis table files"), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - if dlg.ShowModal() != wx.ID_OK: - dlg.Destroy() - return self.path.SetFocus() - self.path.SetValue(dlg.GetDirectory() + '\\' + dlg.GetFilename()) - dlg.Destroy() - self.path.SetFocus() - - def onOk(self, event): - path = self.path.GetValue().strip().encode("UTF-8") - displayName = self.name.GetValue().strip() - if not displayName: - gui.messageBox(_("Please specify a display name."), _("Invalid display name"), wx.OK|wx.ICON_ERROR) - self.name.SetFocus() - return - if not os.path.exists(path.decode("UTF-8").encode("mbcs")): - gui.messageBox(_("The specified path is not valid (%s).") % path.decode("UTF-8"), _("Invalid path"), wx.OK|wx.ICON_ERROR) - self.path.SetFocus() - return - switch_possibleValues = ["both", "input", "output"] - v = "%s|%s|%s|%s" % ( - switch_possibleValues[self.inputOrOutput.GetSelection()], - self.isContracted.IsChecked(), path.decode("UTF-8"), displayName - ) - k = hashlib.md5(path).hexdigest()[:15] - config.conf["brailleExtender"]["brailleTables"][k] = v - super(AddBrailleTablesDlg, self).onOk(evt) - - @staticmethod - def getAvailableBrailleTables(): - out = [] - brailleTablesDir = configBE.brailleTables.TABLES_DIR - ls = glob.glob(brailleTablesDir+'\\*.ctb')+glob.glob(brailleTablesDir+'\\*.cti')+glob.glob(brailleTablesDir+'\\*.utb') - for i, e in enumerate(ls): - e = str(e.split('\\')[-1]) - if e in configBE.tablesFN or e.lower() in configBE.tablesFN: del ls[i] - else: out.append(e.lower()) - out = sorted(out) - return out - class QuickLaunchesDlg(gui.settingsDialogs.SettingsDialog): @@ -894,7 +648,7 @@ class AddonSettingsDialog(gui.settingsDialogs.MultiCategorySettingsDialog): categoryClasses=[ GeneralDlg, AttribraDlg, - BrailleTablesDlg, + brailleTablesExt.BrailleTablesDlg, UndefinedCharsDlg, AdvancedInputModeDlg, OneHandModeDlg, diff --git a/addon/globalPlugins/brailleExtender/undefinedChars.py b/addon/globalPlugins/brailleExtender/undefinedChars.py index 6f6a9936..8b2f818d 100644 --- a/addon/globalPlugins/brailleExtender/undefinedChars.py +++ b/addon/globalPlugins/brailleExtender/undefinedChars.py @@ -11,13 +11,13 @@ import addonHandler import brailleInput -import brailleTables +from . import brailleTablesExt import characterProcessing import config import gui import louis -from . import configBE, huc +from . import huc from .common import * from .utils import getCurrentBrailleTables, getTextInBraille from . import brailleRegionHelper @@ -316,17 +316,12 @@ def makeSettings(self, settingsSizer): _("&Language"), wx.Choice, choices=values ) self.undefinedCharLang.SetSelection(undefinedCharLangID) - values = [_("Use the current output table")] + [ - table.displayName for table in configBE.tables if table.output - ] - keys = ["current"] + [ - table.fileName for table in configBE.tables if table.output - ] + values = [_("Use the current output table")] + brailleTablesExt.listTablesDisplayName(brailleTablesExt.listOutputTables()) + keys = ["current"] + brailleTablesExt.listTablesFileName(brailleTablesExt.listOutputTables()) undefinedCharTable = config.conf["brailleExtender"]["undefinedCharsRepr"][ "table" ] - if undefinedCharTable not in configBE.tablesFN + ["current"]: - undefinedCharTable = "current" + if undefinedCharTable not in keys: undefinedCharTable = "current" undefinedCharTableID = keys.index(undefinedCharTable) self.undefinedCharTable = sHelper.addLabeledControl( _("Braille &table"), wx.Choice, choices=values @@ -418,9 +413,7 @@ def onSave(self): 0 ] undefinedCharTable = self.undefinedCharTable.GetSelection() - keys = ["current"] + [ - table.fileName for table in configBE.tables if table.output - ] + keys = ["current"] + brailleTablesExt.listTablesFileName(brailleTablesExt.listOutputTables()) config.conf["brailleExtender"]["undefinedCharsRepr"]["table"] = keys[ undefinedCharTable ] diff --git a/addon/globalPlugins/brailleExtender/utils.py b/addon/globalPlugins/brailleExtender/utils.py index 5568206c..e4572070 100644 --- a/addon/globalPlugins/brailleExtender/utils.py +++ b/addon/globalPlugins/brailleExtender/utils.py @@ -25,6 +25,7 @@ import treeInterceptorHandler import unicodedata from .common import * +from . import brailleTablesExt from . import huc from . import dictionaries @@ -179,8 +180,7 @@ def bkToChar(dots, inTable=-1): if inTable == -1: inTable = config.conf["braille"]["inputTable"] char = chr(dots | 0x8000) text = louis.backTranslate( - [osp.join(r"louis\tables", inTable), - "braille-patterns.cti"], + [osp.join(r"louis\tables", inTable), "braille-patterns.cti"], char, mode=louis.dotsIO) chars = text[0] if len(chars) == 1 and chars.isupper(): @@ -202,11 +202,14 @@ def currentCharDesc(ch='', display=True): if not ch: return ui.message(_("Not a character")) c = ord(ch) if c: - try: descChar = unicodedata.name(ch) - except ValueError: descChar = _("unknown") + charDescCurLang = getSpeechSymbols(ch) + try: charDesc = unicodedata.name(ch) + except ValueError: charDesc = _("N/A") HUCrepr = " (%s, %s)" % (huc.translate(ch, False), huc.translate(ch, True)) brch = getTextInBraille(ch) - s = "%c%s: %s; %s; %s; %s; %s [%s]\n%s (%s)" % (ch, HUCrepr, hex(c), c, oct(c), bin(c), descChar, unicodedata.category(ch), brch, huc.unicodeBrailleToDescription(brch)) + brchDesc = huc.unicodeBrailleToDescription(brch) + charCategory = unicodedata.category(ch) + s = f"{ch}{HUCrepr}: {hex(c)}, {c}, {oct(c)}, {bin(c)}, {charDescCurLang} / {charDesc} [{charCategory}]. {brch} {brchDesc}" if not display: return s if scriptHandler.getLastScriptRepeatCount() == 0: ui.message(s) elif scriptHandler.getLastScriptRepeatCount() == 1: @@ -257,9 +260,7 @@ def getTextInBraille(t=None, table=[]): if not t: t = getTextSelection() if not t.strip(): return '' if not table or "current" in table: - currentTable = os.path.join(brailleTables.TABLES_DIR, config.conf["braille"]["translationTable"]) - if "current" in table: table[table.index("current")] = currentTable - else: table.append(currentTable) + table = getCurrentBrailleTables() nt = [] res = '' t = t.split("\n") @@ -473,11 +474,18 @@ def getCurrentBrailleTables(input_=False, brf=False): else: tables = [] app = appModuleHandler.getAppModuleForNVDAObject(api.getNavigatorObject()) - if brailleInput.handler._table.fileName == config.conf["braille"]["translationTable"] and app and app.appName != "nvda": tables += dictionaries.dictTables - if input_: mainTable = os.path.join(brailleTables.TABLES_DIR, brailleInput.handler._table.fileName) - else: mainTable = os.path.join(brailleTables.TABLES_DIR, config.conf["braille"]["translationTable"]) - tables += [ - mainTable, + if brailleInput.handler._table.fileName == config.conf["braille"]["translationTable"] and app and app.appName != "nvda": tables += dictionaries.inputTables if input_ else dictionaries.outputTables + if input_: + mainTable = os.path.join(brailleTables.TABLES_DIR, brailleInput.handler._table.fileName) + group = brailleTablesExt.getGroup(usableIn='i') + else: + mainTable = os.path.join(brailleTables.TABLES_DIR, config.conf["braille"]["translationTable"]) + group = brailleTablesExt.getGroup(usableIn='o') + if group: + group = group.members + group = [f if '\\' in f else osp.join(r"louis\tables", f) for f in group] + tbl = group or [mainTable] + tables += tbl + [ os.path.join(brailleTables.TABLES_DIR, "braille-patterns.cti") ] return tables From d48a04296d066ce51405a4c4fa802567e0c66d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Mon, 1 Jun 2020 13:52:38 +0200 Subject: [PATCH 02/11] Optimizes an import --- addon/globalPlugins/brailleExtender/brailleTablesExt.py | 2 +- addon/globalPlugins/brailleExtender/settings.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/brailleTablesExt.py index 83723cf9..5e672219 100644 --- a/addon/globalPlugins/brailleExtender/brailleTablesExt.py +++ b/addon/globalPlugins/brailleExtender/brailleTablesExt.py @@ -195,7 +195,7 @@ def groupEnabled(): _currentGroup = [None, None] -class BrailleTablesDlg(gui.settingsDialogs.SettingsPanel): +class SettingsDlg(gui.settingsDialogs.SettingsPanel): # Translators: title of a dialog. title = _("Braille tables") diff --git a/addon/globalPlugins/brailleExtender/settings.py b/addon/globalPlugins/brailleExtender/settings.py index 1d06dce1..4c9d861f 100644 --- a/addon/globalPlugins/brailleExtender/settings.py +++ b/addon/globalPlugins/brailleExtender/settings.py @@ -23,7 +23,7 @@ import ui addonHandler.initTranslation() -from . import brailleTablesExt +from .brailleTablesExt import SettingsDlg as BrailleTablesDlg from . import configBE from . import utils from .advancedInputMode import SettingsDlg as AdvancedInputModeDlg @@ -651,7 +651,7 @@ class AddonSettingsDialog(gui.settingsDialogs.MultiCategorySettingsDialog): categoryClasses=[ GeneralDlg, AttribraDlg, - brailleTablesExt.BrailleTablesDlg, + BrailleTablesDlg, UndefinedCharsDlg, AdvancedInputModeDlg, OneHandModeDlg, From 273712e7bd8e608fa095fd27730d654e6ca44f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Mon, 22 Jun 2020 13:21:21 +0200 Subject: [PATCH 03/11] Fixes #61 --- addon/globalPlugins/brailleExtender/dictionaries.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/globalPlugins/brailleExtender/dictionaries.py b/addon/globalPlugins/brailleExtender/dictionaries.py index 1156b48a..a4521622 100644 --- a/addon/globalPlugins/brailleExtender/dictionaries.py +++ b/addon/globalPlugins/brailleExtender/dictionaries.py @@ -65,7 +65,7 @@ def getValidPathsDict(usableIn): valid = lambda path: os.path.exists(path) and os.path.isfile(path) and checkTable(path) return [path for path in paths if valid(path)] -def getPathDict(type_, usableIn): +def getPathDict(type_, usableIn="io"): groupEnabled = brailleTablesExt.groupEnabled() g = brailleTablesExt.getGroup(usableIn=usableIn) table = os.path.join(configDir, "brailleDicts", config.conf["braille"]["inputTable"]) if usableIn == brailleTablesExt.USABLE_INPUT else config.conf["braille"]["translationTable"] @@ -80,7 +80,7 @@ def getPathDict(type_, usableIn): if len(g.members) == 1: path = os.path.join(configDir, "brailleDicts", "default") else: path = '' else: path = os.path.join(configDir, "brailleDicts", "default") - return "%s.cti" % path + return f"{path}.cti" def getDictionary(type_): path = getPathDict(type_) From 0dc239895edea9dab6158ae32913019454ec9c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Fri, 17 Jul 2020 11:16:03 +0200 Subject: [PATCH 04/11] fixes a grammatical error: groups of tables -> table groups See https://github.com/Andre9642/BrailleExtender/issues/75#issuecomment-659660029 --- .../brailleExtender/brailleTablesExt.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/brailleTablesExt.py index 5e672219..cb8b2482 100644 --- a/addon/globalPlugins/brailleExtender/brailleTablesExt.py +++ b/addon/globalPlugins/brailleExtender/brailleTablesExt.py @@ -228,8 +228,8 @@ def makeSettings(self, settingsSizer): self.inputTableShortcuts = sHelper.addLabeledControl(label, wx.Choice, choices=[currentTableLabel] + listTablesDisplayName(listUncontractedInputTables)) self.inputTableShortcuts.SetSelection(selectedItem) - self.tablesGroupBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Groups of tables"), wx.DefaultPosition) - self.tablesGroupBtn.Bind(wx.EVT_BUTTON, self.onTablesGroupsBtn) + self.tablesGroupBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("Table &groups"), wx.DefaultPosition) + self.tablesGroupBtn.Bind(wx.EVT_BUTTON, self.onTableGroupsBtn) self.customBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("Alternative and &custom braille tables"), wx.DefaultPosition) self.customBrailleTablesBtn.Bind(wx.EVT_BUTTON, self.onCustomBrailleTablesBtn) @@ -248,9 +248,9 @@ def onTabSpace(self, evt=None): if self.tabSpace.IsChecked(): self.tabSize.Enable() else: self.tabSize.Disable() - def onTablesGroupsBtn(self, evt): - tablesGroupsDlg = TablesGroupsDlg(self, multiInstanceAllowed=True) - tablesGroupsDlg.ShowModal() + def onTableGroupsBtn(self, evt): + tableGroupsDlg = TableGroupsDlg(self, multiInstanceAllowed=True) + tableGroupsDlg.ShowModal() def onCustomBrailleTablesBtn(self, evt): customBrailleTablesDlg = CustomBrailleTablesDlg(self, multiInstanceAllowed=True) @@ -295,10 +295,10 @@ def postSave(self): configBE.initializePreferredTables() -class TablesGroupsDlg(gui.settingsDialogs.SettingsDialog): +class TableGroupsDlg(gui.settingsDialogs.SettingsDialog): # Translators: title of a dialog. - title = f"{addonName} - %s" % _("Groups of tables") + title = f"{addonName} - %s" % _("table groups") def makeSettings(self, settingsSizer): self.tmpGroups = getGroups() @@ -314,19 +314,19 @@ def makeSettings(self, settingsSizer): bHelper = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) bHelper.addButton( parent=self, - # Translators: The label for a button in groups of tables dialog to add new entries. + # Translators: The label for a button in table groups dialog to add new entries. label=_("&Add") ).Bind(wx.EVT_BUTTON, self.onAddClick) bHelper.addButton( parent=self, - # Translators: The label for a button in groups of tables dialog to edit existing entries. + # Translators: The label for a button in table groups dialog to edit existing entries. label=_("&Edit") ).Bind(wx.EVT_BUTTON, self.onEditClick) bHelper.addButton( parent=self, - # Translators: The label for a button in groups of tables dialog to remove existing entries. + # Translators: The label for a button in table groups dialog to remove existing entries. label=_("Re&move") ).Bind(wx.EVT_BUTTON, self.onRemoveClick) @@ -334,13 +334,13 @@ def makeSettings(self, settingsSizer): bHelper = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) bHelper.addButton( parent=self, - # Translators: The label for a button in groups of tables dialog to open groups of tables file in an editor. - label=_("&Open the groups of tables file in an editor") + # Translators: The label for a button in table groups dialog to open table groups file in an editor. + label=_("&Open the table groups file in an editor") ).Bind(wx.EVT_BUTTON, self.onOpenFileClick) bHelper.addButton( parent=self, - # Translators: The label for a button in groups of tables dialog to reload groups of tables. - label=_("&Reload the groups of tables") + # Translators: The label for a button in table groups dialog to reload table groups. + label=_("&Reload table groups") ).Bind(wx.EVT_BUTTON, self.onReloadClick) sHelper.addItem(bHelper) From 0a0dbd6c46751d03c7d1daeb0993d9eed54af6df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Sun, 26 Jul 2020 15:35:03 +0200 Subject: [PATCH 05/11] Format code, optimize 'import's --- .../brailleExtender/brailleTablesExt.py | 279 +++++++++++------ .../brailleExtender/dictionaries.py | 280 +++++++++++------- 2 files changed, 373 insertions(+), 186 deletions(-) diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/brailleTablesExt.py index cb8b2482..5096ed89 100644 --- a/addon/globalPlugins/brailleExtender/brailleTablesExt.py +++ b/addon/globalPlugins/brailleExtender/brailleTablesExt.py @@ -5,6 +5,7 @@ import codecs import json +import os import gui import wx @@ -17,7 +18,7 @@ from brailleTables import listTables from logHandler import log from . import configBE -from .common import * +from .common import addonName, baseDir, configDir addonHandler.initTranslation() @@ -32,35 +33,64 @@ GroupTables = namedtuple("GroupTables", ("name", "members", "usableIn")) -listContractedTables = lambda tables=None: [table for table in (tables or listTables()) if table.contracted] -listUncontractedTables = lambda tables=None: [table for table in (tables or listTables()) if not table.contracted] -listInputTables = lambda tables=None: [table for table in (tables or listTables()) if table.input] + +def listContractedTables(tables=None): return [table for table in ( + tables or listTables()) if table.contracted] + + +def listUncontractedTables(tables=None): return [table for table in ( + tables or listTables()) if not table.contracted] + + +def listInputTables(tables=None): return [ + table for table in (tables or listTables()) if table.input] + + listUncontractedInputTables = listInputTables(listUncontractedTables()) -listOutputTables = lambda tables=None: [table for table in (tables or listTables()) if table.output] -listTablesFileName = lambda tables=None: [table.fileName for table in (tables or listTables())] -listTablesDisplayName = lambda tables=None: [table.displayName for table in (tables or listTables())] + + +def listOutputTables(tables=None): return [ + table for table in (tables or listTables()) if table.output] + + +def listTablesFileName(tables=None): return [ + table.fileName for table in (tables or listTables())] + + +def listTablesDisplayName(tables=None): return [ + table.displayName for table in (tables or listTables())] + def fileName2displayName(l): allTablesFileName = listTablesFileName() o = [] for e in l: - if e in allTablesFileName: o.append(allTablesFileName.index(e)) + if e in allTablesFileName: + o.append(allTablesFileName.index(e)) return [listTables()[e].displayName for e in o] + def listTablesIndexes(l, tables): - if not tables: tables = listTables() + if not tables: + tables = listTables() tables = listTablesFileName(tables) return [tables.index(e) for e in l if e in tables] + def getPreferredTables() -> Tuple[List[str]]: allInputTablesFileName = listTablesFileName(listInputTables()) allOutputTablesFileName = listTablesFileName(listOutputTables()) - preferredInputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredInput"].split('|') - preferredOutputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredOutput"].split('|') - inputTables = [fn for fn in preferredInputTablesFileName if fn in allInputTablesFileName] - outputTables = [fn for fn in preferredOutputTablesFileName if fn in allOutputTablesFileName] + preferredInputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredInput"].split( + '|') + preferredOutputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredOutput"].split( + '|') + inputTables = [ + fn for fn in preferredInputTablesFileName if fn in allInputTablesFileName] + outputTables = [ + fn for fn in preferredOutputTablesFileName if fn in allOutputTablesFileName] return inputTables, outputTables + def getPreferredTablesIndexes() -> List[int]: preferredInputTables, preferredOutputTables = getPreferredTables() inputTables = listTablesFileName(listInputTables()) @@ -69,29 +99,39 @@ def getPreferredTablesIndexes() -> List[int]: for a, b in [(preferredInputTables, inputTables), (preferredOutputTables, outputTables)]: o_ = [] for e in a: - if e in b: o_.append(b.index(e)) + if e in b: + o_.append(b.index(e)) o.append(o_) return o + def getCustomBrailleTables(): return [config.conf["brailleExtender"]["brailleTables"][k].split('|', 3) for k in config.conf["brailleExtender"]["brailleTables"]] + def isContractedTable(fileName): return fileName in listTablesFileName(listContractedTables()) + + def getTable(fileName, tables=None): - if not tables: tables = listTables() + if not tables: + tables = listTables() for table in tables: - if table.fileName == fileName: return table + if table.fileName == fileName: + return table return None + def getTablesFilenameByID(l: List[int], tables=None) -> List[int]: tablesFileName = [table.fileName for table in (tables or listTables())] o = [] size = len(tablesFileName) for i in l: - if i < size: o.append(tablesFileName[i]) + if i < size: + o.append(tablesFileName[i]) return o + def translateUsableIn(s): labels = { 'i': _("input"), @@ -100,19 +140,25 @@ def translateUsableIn(s): } return labels[s] if s in labels.keys() else _("None") + def translateUsableInIndexes(usableIn): o = [] - if 'i' in usableIn: o.append(0) - if 'o' in usableIn: o.append(1) + if 'i' in usableIn: + o.append(0) + if 'o' in usableIn: + o.append(1) return o + def setDict(newGroups): global _groups _groups = newGroups + def getPathGroups(): return f"{configDir}/groups-tables.json" + def initializeGroups(): global _groups _groups = [] @@ -127,8 +173,10 @@ def initializeGroups(): ) ) + def saveGroups(entries=None): - if not entries: entries = getGroups() + if not entries: + entries = getGroups() entries = [ { "name": entry.name, @@ -140,16 +188,20 @@ def saveGroups(entries=None): with codecs.open(getPathGroups(), "w", "UTF-8") as outfile: json.dump(entries, outfile, ensure_ascii=False, indent=2) + def getGroups(plain=True): - if plain: return _groups if _groups else [] + if plain: + return _groups if _groups else [] groups = getGroups() i = [group for group in groups if group.usableIn in ['i', 'io']] o = [group for group in groups if group.usableIn in ['o', 'io']] return i, o + def getAllGroups(usableIn): usableInIndex = USABLE_LIST.index(usableIn) - return [None] +tablesToGroups(getPreferredTables()[usableInIndex], usableIn=usableIn) + getGroups(0)[usableInIndex] + return [None] + tablesToGroups(getPreferredTables()[usableInIndex], usableIn=usableIn) + getGroups(0)[usableInIndex] + def getGroup( usableIn, @@ -157,27 +209,35 @@ def getGroup( choices=None ): global _currentGroup - if position not in POSITIONS or usableIn not in USABLE_LIST: return None + if position not in POSITIONS or usableIn not in USABLE_LIST: + return None usableInIndex = USABLE_LIST.index(usableIn) currentGroup = _currentGroup[usableInIndex] - if not choices: choices = getAllGroups(usableIn) + if not choices: + choices = getAllGroups(usableIn) if currentGroup not in choices: currentGroup = choices[0] curPos = choices.index(currentGroup) newPos = curPos - if position == POSITION_PREVIOUS: newPos = curPos - 1 - elif position == POSITION_NEXT: newPos = curPos + 1 + if position == POSITION_PREVIOUS: + newPos = curPos - 1 + elif position == POSITION_NEXT: + newPos = curPos + 1 return choices[newPos % len(choices)] + def setTableOrGroup(usableIn, e, choices=None): global _currentGroup - if not usableIn in USABLE_LIST: return False + if not usableIn in USABLE_LIST: + return False usableInIndex = USABLE_LIST.index(usableIn) choices = getAllGroups(usableIn) - if not e in choices: return False + if not e in choices: + return False _currentGroup[usableInIndex] = e return True + def tablesToGroups(tables, usableIn): groups = [] for table in tables: @@ -188,9 +248,11 @@ def tablesToGroups(tables, usableIn): )) return groups + def groupEnabled(): return bool(_groups) + _groups = None _currentGroup = [None, None] @@ -206,15 +268,19 @@ def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) - tables = [f"{table.displayName}, {table.fileName}" for table in listTables() if table.input] + tables = [ + f"{table.displayName}, {table.fileName}" for table in listTables() if table.input] label = _("Preferred &input tables") - self.inputTables = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=tables) + self.inputTables = sHelper.addLabeledControl( + label, gui.nvdaControls.CustomCheckListBox, choices=tables) self.inputTables.CheckedItems = listPreferredTablesIndexes[0] self.inputTables.Select(0) - tables = [f"{table.displayName}, {table.fileName}" for table in listTables() if table.output] + tables = [ + f"{table.displayName}, {table.fileName}" for table in listTables() if table.output] label = _("Preferred &output tables") - self.outputTables = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=tables) + self.outputTables = sHelper.addLabeledControl( + label, gui.nvdaControls.CustomCheckListBox, choices=tables) self.outputTables.CheckedItems = listPreferredTablesIndexes[1] self.outputTables.Select(0) @@ -225,35 +291,44 @@ def makeSettings(self, settingsSizer): ).index(config.conf["brailleExtender"]["tables"]["shortcuts"]) + 1 except ValueError: selectedItem = 0 - self.inputTableShortcuts = sHelper.addLabeledControl(label, wx.Choice, choices=[currentTableLabel] + listTablesDisplayName(listUncontractedInputTables)) + self.inputTableShortcuts = sHelper.addLabeledControl(label, wx.Choice, choices=[ + currentTableLabel] + listTablesDisplayName(listUncontractedInputTables)) self.inputTableShortcuts.SetSelection(selectedItem) - self.tablesGroupBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("Table &groups"), wx.DefaultPosition) + self.tablesGroupBtn = bHelper1.addButton( + self, wx.NewId(), "%s..." % _("Table &groups"), wx.DefaultPosition) self.tablesGroupBtn.Bind(wx.EVT_BUTTON, self.onTableGroupsBtn) - self.customBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("Alternative and &custom braille tables"), wx.DefaultPosition) - self.customBrailleTablesBtn.Bind(wx.EVT_BUTTON, self.onCustomBrailleTablesBtn) + self.customBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _( + "Alternative and &custom braille tables"), wx.DefaultPosition) + self.customBrailleTablesBtn.Bind( + wx.EVT_BUTTON, self.onCustomBrailleTablesBtn) # Translators: label of a dialog. - self.tabSpace = sHelper.addItem(wx.CheckBox(self, label=_("Display &tab signs as spaces"))) + self.tabSpace = sHelper.addItem(wx.CheckBox( + self, label=_("Display &tab signs as spaces"))) self.tabSpace.SetValue(config.conf["brailleExtender"]["tabSpace"]) self.tabSpace.Bind(wx.EVT_CHECKBOX, self.onTabSpace) # Translators: label of a dialog. - self.tabSize = sHelper.addLabeledControl(_("Number of &space for a tab sign")+" "+_("for the currrent braille display"), gui.nvdaControls.SelectOnFocusSpinCtrl, min=1, max=42, initial=int(config.conf["brailleExtender"]["tabSize_%s" % configBE.curBD])) + self.tabSize = sHelper.addLabeledControl(_("Number of &space for a tab sign")+" "+_("for the currrent braille display"), + gui.nvdaControls.SelectOnFocusSpinCtrl, min=1, max=42, initial=int(config.conf["brailleExtender"]["tabSize_%s" % configBE.curBD])) sHelper.addItem(bHelper1) self.onTabSpace() def onTabSpace(self, evt=None): - if self.tabSpace.IsChecked(): self.tabSize.Enable() - else: self.tabSize.Disable() + if self.tabSpace.IsChecked(): + self.tabSize.Enable() + else: + self.tabSize.Disable() def onTableGroupsBtn(self, evt): tableGroupsDlg = TableGroupsDlg(self, multiInstanceAllowed=True) tableGroupsDlg.ShowModal() def onCustomBrailleTablesBtn(self, evt): - customBrailleTablesDlg = CustomBrailleTablesDlg(self, multiInstanceAllowed=True) + customBrailleTablesDlg = CustomBrailleTablesDlg( + self, multiInstanceAllowed=True) customBrailleTablesDlg.ShowModal() def postInit(self): self.tables.SetFocus() @@ -263,7 +338,7 @@ def isValid(self): gui.messageBox( _("Tab size is invalid"), _("Error"), - wx.OK|wx.ICON_ERROR, + wx.OK | wx.ICON_ERROR, self ) self.tabSize.SetFocus() @@ -305,7 +380,8 @@ def makeSettings(self, settingsSizer): self.tmpGroups.sort(key=lambda e: e.name) sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) groupsLabelText = _("List of table groups") - self.groupsList = sHelper.addLabeledControl(groupsLabelText, wx.ListCtrl, style=wx.LC_REPORT|wx.LC_SINGLE_SEL,size=(550,350)) + self.groupsList = sHelper.addLabeledControl( + groupsLabelText, wx.ListCtrl, style=wx.LC_REPORT | wx.LC_SINGLE_SEL, size=(550, 350)) self.groupsList.InsertColumn(0, _("Name"), width=150) self.groupsList.InsertColumn(1, _("Members"), width=150) self.groupsList.InsertColumn(2, _("Usable in"), width=150) @@ -359,7 +435,8 @@ def onAddClick(self, event): entry = entryDialog.groupEntry self.tmpGroups.append(entry) self.groupsList.Append( - (entry.name, ", ".join(fileName2displayName(entry.members)), translateUsableIn(entry.usableIn)) + (entry.name, ", ".join(fileName2displayName(entry.members)), + translateUsableIn(entry.usableIn)) ) index = self.groupsList.GetFirstSelected() while index >= 0: @@ -377,20 +454,26 @@ def onEditClick(self, event): editIndex = self.groupsList.GetFirstSelected() entryDialog = GroupEntryDlg(self) entryDialog.name.SetValue(self.tmpGroups[editIndex].name) - entryDialog.members.CheckedItems = listTablesIndexes(self.tmpGroups[editIndex].members, listUncontractedInputTables) + entryDialog.members.CheckedItems = listTablesIndexes( + self.tmpGroups[editIndex].members, listUncontractedInputTables) entryDialog.refreshOrders() selectedItem = 0 try: - selectedItem = list(entryDialog.orderPermutations.keys()).index(tuple(listTablesIndexes(self.tmpGroups[editIndex].members, listUncontractedTables()))) + selectedItem = list(entryDialog.orderPermutations.keys()).index(tuple( + listTablesIndexes(self.tmpGroups[editIndex].members, listUncontractedTables()))) entryDialog.order.SetSelection(selectedItem) - except ValueError: pass - entryDialog.usableIn.CheckedItems = translateUsableInIndexes(self.tmpGroups[editIndex].usableIn) + except ValueError: + pass + entryDialog.usableIn.CheckedItems = translateUsableInIndexes( + self.tmpGroups[editIndex].usableIn) if entryDialog.ShowModal() == wx.ID_OK: entry = entryDialog.groupEntry self.tmpGroups[editIndex] = entry self.groupsList.SetItem(editIndex, 0, entry.name) - self.groupsList.SetItem(editIndex, 1, ", ".join(fileName2displayName(entry.members))) - self.groupsList.SetItem(editIndex, 2, translateUsableIn(entry.usableIn)) + self.groupsList.SetItem(editIndex, 1, ", ".join( + fileName2displayName(entry.members))) + self.groupsList.SetItem( + editIndex, 2, translateUsableIn(entry.usableIn)) self.groupsList.SetFocus() entryDialog.Destroy() @@ -403,14 +486,16 @@ def onRemoveClick(self, event): self.onSetEntries() self.groupsList.SetFocus() - - def onOpenFileClick(self,evt): + def onOpenFileClick(self, evt): path = getPathGroups() - if not os.path.exists(path): return - try: os.startfile(path) - except OSError: os.popen(f"notepad \"{path}\"") + if not os.path.exists(path): + return + try: + os.startfile(path) + except OSError: + os.popen(f"notepad \"{path}\"") - def onReloadClick(self,evt): + def onReloadClick(self, evt): self.tmpGroups = getGroups() self.onSetEntries() @@ -430,16 +515,20 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry")): sHelper = gui.guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL) self.name = sHelper.addLabeledControl(_("Group name"), wx.TextCtrl) label = _(f"Group members") - self.members = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=listTablesDisplayName(listUncontractedTables())) + self.members = sHelper.addLabeledControl( + label, gui.nvdaControls.CustomCheckListBox, choices=listTablesDisplayName(listUncontractedTables())) self.members.SetSelection(0) self.members.Bind(wx.EVT_CHECKLISTBOX, lambda s: self.refreshOrders()) label = _("Usable in") - self.order = sHelper.addLabeledControl(_("Order of the tables"), wx.Choice, choices=[]) + self.order = sHelper.addLabeledControl( + _("Order of the tables"), wx.Choice, choices=[]) self.refreshOrders() choices = [_("input"), _("output")] - self.usableIn = sHelper.addLabeledControl(label, gui.nvdaControls.CustomCheckListBox, choices=choices) + self.usableIn = sHelper.addLabeledControl( + label, gui.nvdaControls.CustomCheckListBox, choices=choices) self.usableIn.SetSelection(0) - sHelper.addDialogDismissButtons(self.CreateButtonSizer(wx.OK | wx.CANCEL)) + sHelper.addDialogDismissButtons( + self.CreateButtonSizer(wx.OK | wx.CANCEL)) mainSizer.Add(sHelper.sizer, border=20, flag=wx.ALL) mainSizer.Fit(self) self.SetSizer(mainSizer) @@ -448,21 +537,25 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry")): def refreshOrders(self, evt=None): tables = listUncontractedTables() - self.orderPermutations = {e: fileName2displayName(getTablesFilenameByID(e, tables)) for e in permutations(self.members.CheckedItems) if e} - self.order.SetItems([", ".join(e) for e in self.orderPermutations.values()]) + self.orderPermutations = {e: fileName2displayName(getTablesFilenameByID( + e, tables)) for e in permutations(self.members.CheckedItems) if e} + self.order.SetItems([", ".join(e) + for e in self.orderPermutations.values()]) self.order.SetSelection(0) def onOk(self, evt): name = self.name.Value - if not self.orderPermutations: return - members = getTablesFilenameByID(list(self.orderPermutations.keys())[self.order.GetSelection()], listUncontractedTables()) + if not self.orderPermutations: + return + members = getTablesFilenameByID(list(self.orderPermutations.keys())[ + self.order.GetSelection()], listUncontractedTables()) matches = ['i', 'o'] usableIn = ''.join([matches[e] for e in self.usableIn.CheckedItems]) if not name: gui.messageBox( _("Please specify a group name"), _("Error"), - wx.OK|wx.ICON_ERROR, + wx.OK | wx.ICON_ERROR, self ) return self.name.SetFocus() @@ -470,13 +563,14 @@ def onOk(self, evt): gui.messageBox( _("Please select at least 2 tables"), _("Error"), - wx.OK|wx.ICON_ERROR, + wx.OK | wx.ICON_ERROR, self ) return self.members.SetFocus() self.groupEntry = GroupTables(name, members, usableIn) evt.Skip() + class CustomBrailleTablesDlg(gui.settingsDialogs.SettingsDialog): # Translators: title of a dialog. @@ -485,26 +579,33 @@ class CustomBrailleTablesDlg(gui.settingsDialogs.SettingsDialog): userTablesPath = "%s/json" % configDir def makeSettings(self, settingsSizer): - self.providedTables = self.getBrailleTablesFromJSON(self.providedTablesPath) + self.providedTables = self.getBrailleTablesFromJSON( + self.providedTablesPath) self.userTables = self.getBrailleTablesFromJSON(self.userTablesPath) sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) - self.inTable = sHelper.addItem(wx.CheckBox(self, label=_("Use a custom table as input table"))) - self.outTable = sHelper.addItem(wx.CheckBox(self, label=_("Use a custom table as output table"))) - self.addBrailleTablesBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Add a braille table"), wx.DefaultPosition) - self.addBrailleTablesBtn.Bind(wx.EVT_BUTTON, self.onAddBrailleTablesBtn) + self.inTable = sHelper.addItem(wx.CheckBox( + self, label=_("Use a custom table as input table"))) + self.outTable = sHelper.addItem(wx.CheckBox( + self, label=_("Use a custom table as output table"))) + self.addBrailleTablesBtn = bHelper1.addButton( + self, wx.NewId(), "%s..." % _("&Add a braille table"), wx.DefaultPosition) + self.addBrailleTablesBtn.Bind( + wx.EVT_BUTTON, self.onAddBrailleTablesBtn) sHelper.addItem(bHelper1) @staticmethod def getBrailleTablesFromJSON(path): if not os.path.exists(path): path = "%s/%s" % (baseDir, path) - if not os.path.exists(path): return {} + if not os.path.exists(path): + return {} f = open(path, "r") return json.load(f) def onAddBrailleTablesBtn(self, evt): - addBrailleTablesDlg = AddBrailleTablesDlg(self, multiInstanceAllowed=True) + addBrailleTablesDlg = AddBrailleTablesDlg( + self, multiInstanceAllowed=True) addBrailleTablesDlg.ShowModal() def postInit(self): self.inTable.SetFocus() @@ -522,20 +623,25 @@ def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) self.name = sHelper.addLabeledControl(_("Display name"), wx.TextCtrl) - self.description = sHelper.addLabeledControl(_("Description"), wx.TextCtrl, style = wx.TE_MULTILINE|wx.TE_PROCESS_ENTER, size = (360, 90), pos=(-1,-1)) + self.description = sHelper.addLabeledControl( + _("Description"), wx.TextCtrl, style=wx.TE_MULTILINE | wx.TE_PROCESS_ENTER, size=(360, 90), pos=(-1, -1)) self.path = sHelper.addLabeledControl(_("Path"), wx.TextCtrl) - self.browseBtn = bHelper1.addButton(self, wx.NewId(), "%s..." % _("&Browse"), wx.DefaultPosition) + self.browseBtn = bHelper1.addButton( + self, wx.NewId(), "%s..." % _("&Browse"), wx.DefaultPosition) self.browseBtn.Bind(wx.EVT_BUTTON, self.onBrowseBtn) sHelper.addItem(bHelper1) - self.isContracted = sHelper.addItem(wx.CheckBox(self, label=_("Contracted (grade 2) braille table"))) + self.isContracted = sHelper.addItem(wx.CheckBox( + self, label=_("Contracted (grade 2) braille table"))) # Translators: label of a dialog. - self.inputOrOutput = sHelper.addLabeledControl(_("Available for"), wx.Choice, choices=[_("Input and output"), _("Input only"), _("Output only")]) + self.inputOrOutput = sHelper.addLabeledControl(_("Available for"), wx.Choice, choices=[ + _("Input and output"), _("Input only"), _("Output only")]) self.inputOrOutput.SetSelection(0) def postInit(self): self.name.SetFocus() def onBrowseBtn(self, event): - dlg = wx.FileDialog(None, _("Choose a table file"), "%PROGRAMFILES%", "", "%s (*.ctb, *.cti, *.utb, *.uti)|*.ctb;*.cti;*.utb;*.uti" % _("Liblouis table files"), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) + dlg = wx.FileDialog(None, _("Choose a table file"), "%PROGRAMFILES%", "", "%s (*.ctb, *.cti, *.utb, *.uti)|*.ctb;*.cti;*.utb;*.uti" % + _("Liblouis table files"), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) if dlg.ShowModal() != wx.ID_OK: dlg.Destroy() return self.path.SetFocus() @@ -547,11 +653,13 @@ def onOk(self, event): path = self.path.GetValue().strip().encode("UTF-8") displayName = self.name.GetValue().strip() if not displayName: - gui.messageBox(_("Please specify a display name."), _("Invalid display name"), wx.OK|wx.ICON_ERROR) + gui.messageBox(_("Please specify a display name."), _( + "Invalid display name"), wx.OK | wx.ICON_ERROR) self.name.SetFocus() return if not os.path.exists(path.decode("UTF-8").encode("mbcs")): - gui.messageBox(_("The specified path is not valid (%s).") % path.decode("UTF-8"), _("Invalid path"), wx.OK|wx.ICON_ERROR) + gui.messageBox(_("The specified path is not valid (%s).") % path.decode( + "UTF-8"), _("Invalid path"), wx.OK | wx.ICON_ERROR) self.path.SetFocus() return switch_possibleValues = ["both", "input", "output"] @@ -567,12 +675,13 @@ def onOk(self, event): def getAvailableBrailleTables(): out = [] brailleTablesDir = configBE.TABLES_DIR - ls = glob.glob(brailleTablesDir+'\\*.ctb')+glob.glob(brailleTablesDir+'\\*.cti')+glob.glob(brailleTablesDir+'\\*.utb') + ls = glob.glob(brailleTablesDir+'\\*.ctb')+glob.glob(brailleTablesDir + + '\\*.cti')+glob.glob(brailleTablesDir+'\\*.utb') for i, e in enumerate(ls): e = str(e.split('\\')[-1]) - if e in configBE.tablesFN or e.lower() in configBE.tablesFN: del ls[i] - else: out.append(e.lower()) + if e in configBE.tablesFN or e.lower() in configBE.tablesFN: + del ls[i] + else: + out.append(e.lower()) out = sorted(out) return out - - diff --git a/addon/globalPlugins/brailleExtender/dictionaries.py b/addon/globalPlugins/brailleExtender/dictionaries.py index 4cbf937a..6e189e29 100644 --- a/addon/globalPlugins/brailleExtender/dictionaries.py +++ b/addon/globalPlugins/brailleExtender/dictionaries.py @@ -3,6 +3,15 @@ # Part of BrailleExtender addon for NVDA # Copyright 2016-2020 André-Abush CLAUSE, released under GPL. +from logHandler import log +from . import huc +from . import brailleTablesExt +from .common import * +from . import configBE +from collections import namedtuple +import louis +import config +import braille import gui import wx import os.path @@ -11,18 +20,10 @@ import addonHandler addonHandler.initTranslation() -import braille -import config -import louis -from collections import namedtuple -from . import configBE -from .common import * -from . import brailleTablesExt -from . import huc -from logHandler import log -TableDictEntry = namedtuple("TableDictEntry", ("opcode", "textPattern", "braillePattern", "direction", "comment")) +TableDictEntry = namedtuple( + "TableDictEntry", ("opcode", "textPattern", "braillePattern", "direction", "comment")) OPCODE_SIGN = "sign" OPCODE_MATH = "math" OPCODE_REPLACE = "replace" @@ -44,77 +45,103 @@ DIRECTION_BACKWARD: _("Backward (input only)"), DIRECTION_FORWARD: _("Forward (output only)") } -DIRECTION_LABELS_ORDERING = (DIRECTION_BOTH, DIRECTION_FORWARD, DIRECTION_BACKWARD) +DIRECTION_LABELS_ORDERING = ( + DIRECTION_BOTH, DIRECTION_FORWARD, DIRECTION_BACKWARD) inputTables = [] outputTables = [] invalidTables = set() + def checkTable(path): global invalidTables - tablesString = b",".join([x.encode("mbcs") if isinstance(x, str) else bytes(x) for x in [path]]) + tablesString = b",".join( + [x.encode("mbcs") if isinstance(x, str) else bytes(x) for x in [path]]) if not louis.liblouis.lou_checkTable(tablesString): log.error("Can't compile: tables %s" % path) invalidTables.add(path) return False return True + def getValidPathsDict(usableIn): types = ["tmp", "table", "default"] paths = [getPathDict(type_, usableIn) for type_ in types] - valid = lambda path: os.path.exists(path) and os.path.isfile(path) and checkTable(path) + def valid(path): return os.path.exists( + path) and os.path.isfile(path) and checkTable(path) return [path for path in paths if valid(path)] + def getPathDict(type_, usableIn="io"): groupEnabled = brailleTablesExt.groupEnabled() g = brailleTablesExt.getGroup(usableIn=usableIn) - table = os.path.join(configDir, "brailleDicts", config.conf["braille"]["inputTable"]) if usableIn == brailleTablesExt.USABLE_INPUT else config.conf["braille"]["translationTable"] + table = os.path.join(configDir, "brailleDicts", config.conf["braille"]["inputTable"] + ) if usableIn == brailleTablesExt.USABLE_INPUT else config.conf["braille"]["translationTable"] if type_ == "table": if groupEnabled and g and g.members: - if len(g.members) == 1: path = os.path.join(configDir, "brailleDicts", g.members[0]) - else: path = '' - else: path = os.path.join(configDir, "brailleDicts", table) - elif type_ == "tmp": path = os.path.join(configDir, "brailleDicts", "tmp") + if len(g.members) == 1: + path = os.path.join(configDir, "brailleDicts", g.members[0]) + else: + path = '' + else: + path = os.path.join(configDir, "brailleDicts", table) + elif type_ == "tmp": + path = os.path.join(configDir, "brailleDicts", "tmp") else: if groupEnabled and g and g.members: - if len(g.members) == 1: path = os.path.join(configDir, "brailleDicts", "default") - else: path = '' - else: path = os.path.join(configDir, "brailleDicts", "default") + if len(g.members) == 1: + path = os.path.join(configDir, "brailleDicts", "default") + else: + path = '' + else: + path = os.path.join(configDir, "brailleDicts", "default") return f"{path}.cti" + def getDictionary(type_): path = getPathDict(type_) - if not os.path.exists(path): return False, [] + if not os.path.exists(path): + return False, [] out = [] with open(path, "rb") as f: for line in f: line = line.decode("UTF-8") - line = line.replace(" ", " ").replace(" ", " ").replace(" ", " ").strip().split(" ", 4) - if line[0].lower().strip() not in [DIRECTION_BACKWARD, DIRECTION_FORWARD]: line.insert(0, DIRECTION_BOTH) + line = line.replace(" ", " ").replace( + " ", " ").replace(" ", " ").strip().split(" ", 4) + if line[0].lower().strip() not in [DIRECTION_BACKWARD, DIRECTION_FORWARD]: + line.insert(0, DIRECTION_BOTH) if len(line) < 4: - if line[1] == "replace" and len(line) == 3: line.append("") - else: continue - if len(line) == 4: line.append("") - out.append(TableDictEntry(line[1], line[2], line[3], line[0], ' '.join(line[4:]).replace(" ", " "))) + if line[1] == "replace" and len(line) == 3: + line.append("") + else: + continue + if len(line) == 4: + line.append("") + out.append(TableDictEntry( + line[1], line[2], line[3], line[0], ' '.join(line[4:]).replace(" ", " "))) return True, out + def saveDict(type_, dict_): path = getPathDict(type_) f = open(path, "wb") for entry in dict_: direction = entry.direction if entry.direction != "both" else '' - line = ("%s %s %s %s %s" % (direction, entry.opcode, entry.textPattern, entry.braillePattern, entry.comment)).strip()+"\n" + line = ("%s %s %s %s %s" % (direction, entry.opcode, entry.textPattern, + entry.braillePattern, entry.comment)).strip()+"\n" f.write(line.encode("UTF-8")) f.write('\n'.encode("UTF-8")) f.close() return True + def setDictTables(): global inputTables, outTable inputTables = getValidPathsDict(brailleTablesExt.USABLE_INPUT) outputTables = getValidPathsDict(brailleTablesExt.USABLE_OUTPUT) invalidTables.clear() + def notifyInvalidTables(): if invalidTables: dicts = { @@ -122,16 +149,22 @@ def notifyInvalidTables(): getPathDict("table"): "table", getPathDict("tmp"): "tmp" } - msg = _("One or more errors are present in dictionary tables: %s. As a result, these dictionaries were not loaded.") % ", ".join([dicts[path] for path in invalidTables if path in dicts]) - wx.CallAfter(gui.messageBox, msg, _("Braille Extender"), wx.OK|wx.ICON_ERROR) + msg = _("One or more errors are present in dictionary tables: %s. As a result, these dictionaries were not loaded.") % ", ".join( + [dicts[path] for path in invalidTables if path in dicts]) + wx.CallAfter(gui.messageBox, msg, _( + "Braille Extender"), wx.OK | wx.ICON_ERROR) + def removeTmpDict(): path = getPathDict("tmp") - if os.path.exists(path): os.remove(path) + if os.path.exists(path): + os.remove(path) + setDictTables() notifyInvalidTables() + class DictionaryDlg(gui.settingsDialogs.SettingsDialog): def __init__(self, parent, title, type_): @@ -144,17 +177,18 @@ def makeSettings(self, settingsSizer): sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) # Translators: The label for the combo box of dictionary entries in table dictionary dialog. entriesLabelText = _("Dictionary &entries") - self.dictList = sHelper.addLabeledControl(entriesLabelText, wx.ListCtrl, style=wx.LC_REPORT|wx.LC_SINGLE_SEL,size=(550,350)) + self.dictList = sHelper.addLabeledControl( + entriesLabelText, wx.ListCtrl, style=wx.LC_REPORT | wx.LC_SINGLE_SEL, size=(550, 350)) # Translators: The label for a column in dictionary entries list used to identify comments for the entry. self.dictList.InsertColumn(0, _("Comment"), width=150) # Translators: The label for a column in dictionary entries list used to identify original character. - self.dictList.InsertColumn(1, _("Pattern"),width=150) + self.dictList.InsertColumn(1, _("Pattern"), width=150) # Translators: The label for a column in dictionary entries list and in a list of symbols from symbol pronunciation dialog used to identify replacement for a pattern or a symbol - self.dictList.InsertColumn(2, _("Representation"),width=150) + self.dictList.InsertColumn(2, _("Representation"), width=150) # Translators: The label for a column in dictionary entries list used to identify whether the entry is a sign, math, replace - self.dictList.InsertColumn(4, _("Opcode"),width=50) + self.dictList.InsertColumn(4, _("Opcode"), width=50) # Translators: The label for a column in dictionary entries list used to identify whether the entry is a sign, math, replace - self.dictList.InsertColumn(5, _("Direction"),width=50) + self.dictList.InsertColumn(5, _("Direction"), width=50) self.onSetEntries() bHelper = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) bHelper.addButton( @@ -192,33 +226,40 @@ def makeSettings(self, settingsSizer): def onSetEntries(self, evt=None): self.dictList.DeleteAllItems() for entry in self.tmpDict: - direction = DIRECTION_LABELS[entry[3]] if len(entry) >= 4 and entry[3] in DIRECTION_LABELS else "both" - self.dictList.Append(( - entry.comment, - self.getReprTextPattern(entry.textPattern), - self.getReprBraillePattern(entry.braillePattern), - entry.opcode, - direction - )) + direction = DIRECTION_LABELS[entry[3]] if len( + entry) >= 4 and entry[3] in DIRECTION_LABELS else "both" + self.dictList.Append(( + entry.comment, + self.getReprTextPattern(entry.textPattern), + self.getReprBraillePattern(entry.braillePattern), + entry.opcode, + direction + )) self.dictList.SetFocus() def onOpenFileClick(self, evt): dictPath = getPathDict(self.type_) - if not os.path.exists(dictPath): return - try: os.startfile(dictPath) - except OSError: os.popen("notepad \"%s\"" % dictPath) + if not os.path.exists(dictPath): + return + try: + os.startfile(dictPath) + except OSError: + os.popen("notepad \"%s\"" % dictPath) def onReloadDictClick(self, evt): - self.tmpDict = getDictionary(self.type_ )[1] + self.tmpDict = getDictionary(self.type_)[1] self.onSetEntries() @staticmethod def getReprTextPattern(textPattern, equiv=True): if re.match(r"^\\x[0-9a-f]+$", textPattern, re.IGNORECASE): textPattern = textPattern.lower() - textPattern = chr(int(''.join([c for c in textPattern if c in "abcdef1234567890"]), 16)) - if equiv and len(textPattern) == 1: return "%s (%s, %s)" % (textPattern, hex(ord(textPattern)).replace("0x", r"\x"), unicodedata.name(textPattern).lower()) - textPattern = textPattern.replace(r"\s", " ").replace(r"\t", " ").replace(r"\ ", r"\s").replace(r"\ ", r"\t") + textPattern = chr( + int(''.join([c for c in textPattern if c in "abcdef1234567890"]), 16)) + if equiv and len(textPattern) == 1: + return "%s (%s, %s)" % (textPattern, hex(ord(textPattern)).replace("0x", r"\x"), unicodedata.name(textPattern).lower()) + textPattern = textPattern.replace(r"\s", " ").replace( + r"\t", " ").replace(r"\ ", r"\s").replace(r"\ ", r"\t") return textPattern @staticmethod @@ -229,12 +270,13 @@ def getReprBraillePattern(braillePattern, equiv=True): return braillePattern def onAddClick(self, evt): - entryDialog = DictionaryEntryDlg(self,title=_("Add Dictionary Entry")) + entryDialog = DictionaryEntryDlg(self, title=_("Add Dictionary Entry")) if entryDialog.ShowModal() == wx.ID_OK: entry = entryDialog.dictEntry self.tmpDict.append(entry) - direction = DIRECTION_LABELS[entry[3]] if len(entry)>=4 and entry[3] in DIRECTION_LABELS else "both" - comment = entry[4] if len(entry)==5 else '' + direction = DIRECTION_LABELS[entry[3]] if len( + entry) >= 4 and entry[3] in DIRECTION_LABELS else "both" + comment = entry[4] if len(entry) == 5 else '' self.dictList.Append(( comment, self.getReprTextPattern(entry.textPattern), @@ -244,8 +286,8 @@ def onAddClick(self, evt): )) index = self.dictList.GetFirstSelected() while index >= 0: - self.dictList.Select(index,on=0) - index=self.dictList.GetNextSelected(index) + self.dictList.Select(index, on=0) + index = self.dictList.GetNextSelected(index) addedIndex = self.dictList.GetItemCount()-1 self.dictList.Select(addedIndex) self.dictList.Focus(addedIndex) @@ -253,29 +295,35 @@ def onAddClick(self, evt): entryDialog.Destroy() def onEditClick(self, evt): - if self.dictList.GetSelectedItemCount() != 1: return + if self.dictList.GetSelectedItemCount() != 1: + return editIndex = self.dictList.GetFirstSelected() entryDialog = DictionaryEntryDlg(self) - entryDialog.textPatternTextCtrl.SetValue(self.getReprTextPattern(self.tmpDict[editIndex].textPattern, False)) - entryDialog.braillePatternTextCtrl.SetValue(self.getReprBraillePattern(self.tmpDict[editIndex].braillePattern, False)) + entryDialog.textPatternTextCtrl.SetValue( + self.getReprTextPattern(self.tmpDict[editIndex].textPattern, False)) + entryDialog.braillePatternTextCtrl.SetValue( + self.getReprBraillePattern(self.tmpDict[editIndex].braillePattern, False)) entryDialog.commentTextCtrl.SetValue(self.tmpDict[editIndex].comment) entryDialog.setOpcode(self.tmpDict[editIndex].opcode) entryDialog.setDirection(self.tmpDict[editIndex].direction) if entryDialog.ShowModal() == wx.ID_OK: self.tmpDict[editIndex] = entryDialog.dictEntry entry = entryDialog.dictEntry - direction = DIRECTION_LABELS[entry.direction] if len(entry) >= 4 and entry.direction in DIRECTION_LABELS else "both" + direction = DIRECTION_LABELS[entry.direction] if len( + entry) >= 4 and entry.direction in DIRECTION_LABELS else "both" self.dictList.SetItem(editIndex, 0, entry.comment) - self.dictList.SetItem(editIndex, 1, self.getReprTextPattern(entry.textPattern)) - self.dictList.SetItem(editIndex, 2, self.getReprBraillePattern(entry.braillePattern)) + self.dictList.SetItem( + editIndex, 1, self.getReprTextPattern(entry.textPattern)) + self.dictList.SetItem( + editIndex, 2, self.getReprBraillePattern(entry.braillePattern)) self.dictList.SetItem(editIndex, 3, entry.opcode) self.dictList.SetItem(editIndex, 4, direction) self.dictList.SetFocus() entryDialog.Destroy() - def onRemoveClick(self,evt): + def onRemoveClick(self, evt): index = self.dictList.GetFirstSelected() - while index>=0: + while index >= 0: self.dictList.DeleteItem(index) del self.tmpDict[index] index = self.dictList.GetNextSelected(index) @@ -285,8 +333,10 @@ def onApply(self, evt): res = saveDict(self.type_, self.tmpDict) setDictTables() braille.handler.setDisplayByName(braille.handler.display.name) - if res: super(DictionaryDlg, self).onApply(evt) - else: notImplemented("Error during writing file, more info in log.") + if res: + super(DictionaryDlg, self).onApply(evt) + else: + notImplemented("Error during writing file, more info in log.") notifyInvalidTables() self.dictList.SetFocus() @@ -295,22 +345,28 @@ def onOk(self, evt): setDictTables() braille.handler.setDisplayByName(braille.handler.display.name) notifyInvalidTables() - if res: super(DictionaryDlg, self).onOk(evt) - else: notImplemented("Error during writing file, more info in log.") + if res: + super(DictionaryDlg, self).onOk(evt) + else: + notImplemented("Error during writing file, more info in log.") notifyInvalidTables() + class DictionaryEntryDlg(wx.Dialog): # Translators: This is the label for the edit dictionary entry dialog. def __init__(self, parent=None, title=_("Edit Dictionary Entry"), textPattern='', specifyDict=False): super(DictionaryEntryDlg, self).__init__(parent, title=title) - mainSizer=wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.VERTICAL) sHelper = gui.guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL) if specifyDict: # Translators: This is a label for an edit field in add dictionary entry dialog. dictText = _("Dictionary") - outTable = brailleTablesExt.fileName2displayName(config.conf["braille"]["translationTable"]) - dictChoices = [_("Global"), _("Table ({})").format(outTable), _("Temporary")] - self.dictRadioBox = sHelper.addItem(wx.RadioBox(self, label=dictText, choices=dictChoices)) + outTable = brailleTablesExt.fileName2displayName( + config.conf["braille"]["translationTable"]) + dictChoices = [_("Global"), _( + "Table ({})").format(outTable), _("Temporary")] + self.dictRadioBox = sHelper.addItem(wx.RadioBox( + self, label=dictText, choices=dictChoices)) self.dictRadioBox.SetSelection(1) bHelper = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) bHelper.addButton( @@ -321,53 +377,64 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry"), textPattern='' # Translators: This is a label for an edit field in add dictionary entry dialog. patternLabelText = _("&Text pattern/sign") - self.textPatternTextCtrl = sHelper.addLabeledControl(patternLabelText, wx.TextCtrl) - if textPattern: self.textPatternTextCtrl.SetValue(textPattern) + self.textPatternTextCtrl = sHelper.addLabeledControl( + patternLabelText, wx.TextCtrl) + if textPattern: + self.textPatternTextCtrl.SetValue(textPattern) # Translators: This is a label for an edit field in add dictionary entry dialog and in punctuation/symbol pronunciation dialog. braillePatternLabelText = _("&Braille representation") - self.braillePatternTextCtrl = sHelper.addLabeledControl(braillePatternLabelText, wx.TextCtrl) + self.braillePatternTextCtrl = sHelper.addLabeledControl( + braillePatternLabelText, wx.TextCtrl) # Translators: This is a label for an edit field in add dictionary entry dialog. commentLabelText = _("&Comment") - self.commentTextCtrl=sHelper.addLabeledControl(commentLabelText, wx.TextCtrl) + self.commentTextCtrl = sHelper.addLabeledControl( + commentLabelText, wx.TextCtrl) # Translators: This is a label for a set of radio buttons in add dictionary entry dialog. opcodeText = _("&Opcode") opcodeChoices = [OPCODE_LABELS[i] for i in OPCODE_LABELS_ORDERING] - self.opcodeRadioBox = sHelper.addItem(wx.RadioBox(self, label=opcodeText, choices=opcodeChoices)) + self.opcodeRadioBox = sHelper.addItem(wx.RadioBox( + self, label=opcodeText, choices=opcodeChoices)) # Translators: This is a label for a set of radio buttons in add dictionary entry dialog. directionText = _("&Direction") - directionChoices = [DIRECTION_LABELS[i] for i in DIRECTION_LABELS_ORDERING] - self.directionRadioBox = sHelper.addItem(wx.RadioBox(self, label=directionText, choices=directionChoices)) + directionChoices = [DIRECTION_LABELS[i] + for i in DIRECTION_LABELS_ORDERING] + self.directionRadioBox = sHelper.addItem(wx.RadioBox( + self, label=directionText, choices=directionChoices)) - sHelper.addDialogDismissButtons(self.CreateButtonSizer(wx.OK|wx.CANCEL)) + sHelper.addDialogDismissButtons( + self.CreateButtonSizer(wx.OK | wx.CANCEL)) - mainSizer.Add(sHelper.sizer,border=20,flag=wx.ALL) + mainSizer.Add(sHelper.sizer, border=20, flag=wx.ALL) mainSizer.Fit(self) self.SetSizer(mainSizer) self.setOpcode(OPCODE_SIGN) toFocus = self.dictRadioBox if specifyDict else self.textPatternTextCtrl toFocus.SetFocus() - self.Bind(wx.EVT_BUTTON,self.onOk,id=wx.ID_OK) - + self.Bind(wx.EVT_BUTTON, self.onOk, id=wx.ID_OK) def onSeeEntriesClick(self, evt): - outTable = brailleTablesExt.fileName2displayName(config.conf["braille"]["translationTable"]) - label = [_("Global dictionary"), _("Table dictionary ({})").format(outTable), _("Temporary dictionary")][self.dictRadioBox.GetSelection()] + outTable = brailleTablesExt.fileName2displayName( + config.conf["braille"]["translationTable"]) + label = [_("Global dictionary"), _("Table dictionary ({})").format( + outTable), _("Temporary dictionary")][self.dictRadioBox.GetSelection()] type_ = self.getType_() self.Destroy() gui.mainFrame._popupSettingsDialog(DictionaryDlg, label, type_) def getOpcode(self): opcodeRadioValue = self.opcodeRadioBox.GetSelection() - if opcodeRadioValue == wx.NOT_FOUND: return OPCODE_SIGN + if opcodeRadioValue == wx.NOT_FOUND: + return OPCODE_SIGN return OPCODE_LABELS_ORDERING[opcodeRadioValue] def getDirection(self): directionRadioValue = self.directionRadioBox.GetSelection() - if directionRadioValue == wx.NOT_FOUND: return DIRECTION_BOTH + if directionRadioValue == wx.NOT_FOUND: + return DIRECTION_BOTH return DIRECTION_LABELS_ORDERING[directionRadioValue] def getType_(self): @@ -380,27 +447,36 @@ def onOk(self, evt): opcode = self.getOpcode() if not textPattern: msg = _("Text pattern/sign field is empty.") - gui.messageBox(msg, _("Braille Extender"), wx.OK|wx.ICON_ERROR) + gui.messageBox(msg, _("Braille Extender"), wx.OK | wx.ICON_ERROR) return self.textPatternTextCtrl.SetFocus() if opcode != OPCODE_REPLACE: egBRLRepr = "12345678, 5-123456, 0-138." egTextPattern = r"α, ∪, \x2019." if len(textPattern) > 1 and not re.match(r"^\\x[0-9a-f]+$", textPattern): - msg = _("Invalid value for 'text pattern/sign' field. You must specify a character with this opcode. E.g.: %s") % egTextPattern - gui.messageBox(msg, _("Braille Extender"), wx.OK|wx.ICON_ERROR) + msg = _( + "Invalid value for 'text pattern/sign' field. You must specify a character with this opcode. E.g.: %s") % egTextPattern + gui.messageBox(msg, _("Braille Extender"), + wx.OK | wx.ICON_ERROR) return self.textPatternTextCtrl.SetFocus() if not braillePattern: - msg = _("'Braille representation' field is empty. You must specify something with this opcode. E.g.: %s") % egBRLRepr - gui.messageBox(msg, _("Braille Extender"), wx.OK|wx.ICON_ERROR) + msg = _( + "'Braille representation' field is empty. You must specify something with this opcode. E.g.: %s") % egBRLRepr + gui.messageBox(msg, _("Braille Extender"), + wx.OK | wx.ICON_ERROR) return self.braillePatternTextCtrl.SetFocus() - if not re.match("^[0-8\-]+$", braillePattern): - msg = _("Invalid value for 'braille representation' field. You must enter dot patterns with this opcode. E.g.: %s") % egBRLRepr - gui.messageBox(msg, _("Braille Extender"), wx.OK|wx.ICON_ERROR) + if not re.match("^[0-8\-]+$", braillePattern): + msg = _( + "Invalid value for 'braille representation' field. You must enter dot patterns with this opcode. E.g.: %s") % egBRLRepr + gui.messageBox(msg, _("Braille Extender"), + wx.OK | wx.ICON_ERROR) return self.braillePatternTextCtrl.SetFocus() - else: textPattern = textPattern.lower().replace("\\", r"\\") + else: + textPattern = textPattern.lower().replace("\\", r"\\") textPattern = textPattern.replace(" ", r"\t").replace(" ", r"\s") - braillePattern = braillePattern.replace("\\", r"\\").replace(" ", r"\t").replace(" ", r"\s") - newEntry = TableDictEntry(opcode, textPattern, braillePattern, self.getDirection(), self.commentTextCtrl.GetValue()) + braillePattern = braillePattern.replace( + "\\", r"\\").replace(" ", r"\t").replace(" ", r"\s") + newEntry = TableDictEntry(opcode, textPattern, braillePattern, self.getDirection( + ), self.commentTextCtrl.GetValue()) save = True if hasattr(self, "dictRadioBox") else False if save: type_ = self.getType_() @@ -411,11 +487,13 @@ def onOk(self, evt): setDictTables() braille.handler.setDisplayByName(braille.handler.display.name) notifyInvalidTables() - else: self.dictEntry = newEntry + else: + self.dictEntry = newEntry evt.Skip() def setOpcode(self, opcode): self.opcodeRadioBox.SetSelection(OPCODE_LABELS_ORDERING.index(opcode)) def setDirection(self, direction): - self.directionRadioBox.SetSelection(DIRECTION_LABELS_ORDERING.index(direction)) + self.directionRadioBox.SetSelection( + DIRECTION_LABELS_ORDERING.index(direction)) From 9c684ce343a629a3fa1fb412fdd23021cd56f717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Sun, 26 Jul 2020 23:04:45 +0200 Subject: [PATCH 06/11] Add 2 'SetFocus()'s --- addon/globalPlugins/brailleExtender/brailleTablesExt.py | 3 +++ addon/globalPlugins/brailleExtender/dictionaries.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/brailleTablesExt.py index 5096ed89..e570d343 100644 --- a/addon/globalPlugins/brailleExtender/brailleTablesExt.py +++ b/addon/globalPlugins/brailleExtender/brailleTablesExt.py @@ -420,6 +420,9 @@ def makeSettings(self, settingsSizer): ).Bind(wx.EVT_BUTTON, self.onReloadClick) sHelper.addItem(bHelper) + def postInit(self): + self.groupsList.SetFocus() + def onSetEntries(self, evt=None): self.groupsList.DeleteAllItems() for group in self.tmpGroups: diff --git a/addon/globalPlugins/brailleExtender/dictionaries.py b/addon/globalPlugins/brailleExtender/dictionaries.py index 6e189e29..ed150097 100644 --- a/addon/globalPlugins/brailleExtender/dictionaries.py +++ b/addon/globalPlugins/brailleExtender/dictionaries.py @@ -223,6 +223,9 @@ def makeSettings(self, settingsSizer): ).Bind(wx.EVT_BUTTON, self.onReloadDictClick) sHelper.addItem(bHelper) + def postInit(self): + self.dictList.SetFocus() + def onSetEntries(self, evt=None): self.dictList.DeleteAllItems() for entry in self.tmpDict: From b3322c1062a84304849ff7c80aa7366ccba9ece9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Sun, 26 Jul 2020 23:10:47 +0200 Subject: [PATCH 07/11] Optimize 'import's --- addon/globalPlugins/brailleExtender/brailleTablesExt.py | 1 - addon/globalPlugins/brailleExtender/dictionaries.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/brailleTablesExt.py index e570d343..2e214415 100644 --- a/addon/globalPlugins/brailleExtender/brailleTablesExt.py +++ b/addon/globalPlugins/brailleExtender/brailleTablesExt.py @@ -10,7 +10,6 @@ import wx import addonHandler -import brailleTables import config from collections import namedtuple from itertools import permutations diff --git a/addon/globalPlugins/brailleExtender/dictionaries.py b/addon/globalPlugins/brailleExtender/dictionaries.py index ed150097..a88027d2 100644 --- a/addon/globalPlugins/brailleExtender/dictionaries.py +++ b/addon/globalPlugins/brailleExtender/dictionaries.py @@ -6,8 +6,7 @@ from logHandler import log from . import huc from . import brailleTablesExt -from .common import * -from . import configBE +from .common import configDir from collections import namedtuple import louis import config From cd1ee8d7f63e3611c38e6a12c07706d106c13f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Thu, 24 Sep 2020 09:04:41 +0200 Subject: [PATCH 08/11] Small rewrites (to be continued) --- .../brailleExtender/brailleTablesExt.py | 98 ++++++++++--------- .../globalPlugins/brailleExtender/configBE.py | 7 -- 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/brailleTablesExt.py index 714e45e3..faed3700 100644 --- a/addon/globalPlugins/brailleExtender/brailleTablesExt.py +++ b/addon/globalPlugins/brailleExtender/brailleTablesExt.py @@ -25,38 +25,52 @@ POSITION_NEXT = "n" POSITIONS = [POSITION_CURRENT, POSITION_PREVIOUS, POSITION_NEXT] -USABLE_INPUT = 'i' -USABLE_OUTPUT = 'o' -USABLE_LIST = [USABLE_INPUT, USABLE_OUTPUT] +USABLE_INPUT = 0 +USABLE_OUTPUT = 1 +USABLE_BOTH = 2 +USABLE_LIST = [USABLE_INPUT, USABLE_OUTPUT, USABLE_BOTH] -GroupTables = namedtuple("GroupTables", ("name", "members", "usableIn")) +USABLE_LIST_LABELS = { + USABLE_INPUT: _("input only"), + USABLE_OUTPUT: _("output only"), + USABLE_BOTH: _("input and output") +} +GroupTables = namedtuple("GroupTables", ( + "name", "members", "usableIn")) +conf = config.conf["brailleExtender"]["tables"] -def listContractedTables(tables=None): return [table for table in ( - tables or listTables()) if table.contracted] +def listContractedTables(tables=None): + return [table for table in ( + tables or listTables()) if table.contracted] -def listUncontractedTables(tables=None): return [table for table in ( - tables or listTables()) if not table.contracted] +def listUncontractedTables(tables=None): + return [table for table in ( + tables or listTables()) if not table.contracted] -def listInputTables(tables=None): return [ - table for table in (tables or listTables()) if table.input] +def listInputTables(tables=None): + return [ + table for table in (tables or listTables()) if table.input] listUncontractedInputTables = listInputTables(listUncontractedTables()) -def listOutputTables(tables=None): return [ - table for table in (tables or listTables()) if table.output] +def listOutputTables(tables=None): + return [ + table for table in (tables or listTables()) if table.output] -def listTablesFileName(tables=None): return [ - table.fileName for table in (tables or listTables())] +def listTablesFileName(tables=None): + return [ + table.fileName for table in (tables or listTables())] -def listTablesDisplayName(tables=None): return [ - table.displayName for table in (tables or listTables())] +def listTablesDisplayName(tables=None): + return [ + table.displayName for table in (tables or listTables())] def fileName2displayName(l): @@ -78,9 +92,9 @@ def listTablesIndexes(l, tables): def getPreferredTables() -> Tuple[List[str]]: allInputTablesFileName = listTablesFileName(listInputTables()) allOutputTablesFileName = listTablesFileName(listOutputTables()) - preferredInputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredInput"].split( + preferredInputTablesFileName = conf["preferredInput"].split( '|') - preferredOutputTablesFileName = config.conf["brailleExtender"]["tables"]["preferredOutput"].split( + preferredOutputTablesFileName = conf["preferredOutput"].split( '|') inputTables = [ fn for fn in preferredInputTablesFileName if fn in allInputTablesFileName] @@ -131,30 +145,17 @@ def getTablesFilenameByID(l: List[int], tables=None) -> List[int]: def translateUsableIn(s): - labels = { - 'i': _("input"), - 'o': _("output"), - 'io': _("input and output") - } + labels = USABLE_LIST_LABELS return labels[s] if s in labels.keys() else _("None") -def translateUsableInIndexes(usableIn): - o = [] - if 'i' in usableIn: - o.append(0) - if 'o' in usableIn: - o.append(1) - return o - - def setDict(newGroups): global _groups _groups = newGroups def getPathGroups(): - return f"{configDir}/groups-tables.json" + return f"{configDir}/table-groups.json" def initializeGroups(): @@ -179,7 +180,7 @@ def saveGroups(entries=None): { "name": entry.name, "members": entry.members, - "usableIn": entry.usableIn + "usableIn": entry.usableIn, } for entry in entries ] @@ -284,9 +285,9 @@ def makeSettings(self, settingsSizer): label = _("Input braille table to use for keyboard shortcuts") try: - selectedItem = 0 if config.conf["brailleExtender"]["tables"]["shortcuts"] == '?' else listTablesFileName( + selectedItem = 0 if conf["shortcuts"] == '?' else listTablesFileName( listUncontractedInputTables - ).index(config.conf["brailleExtender"]["tables"]["shortcuts"]) + 1 + ).index(conf["shortcuts"]) + 1 except ValueError: selectedItem = 0 self.inputTableShortcuts = sHelper.addLabeledControl(label, wx.Choice, choices=[ @@ -358,14 +359,14 @@ def onSave(self): [self.inputTableShortcuts.GetSelection()-1], listUncontractedInputTables )[0] if self.inputTableShortcuts.GetSelection() > 0 else '?' - config.conf["brailleExtender"]["tables"]["preferredInput"] = inputTables - config.conf["brailleExtender"]["tables"]["preferredOutput"] = outputTables - config.conf["brailleExtender"]["tables"]["shortcuts"] = tablesShortcuts + conf["preferredInput"] = inputTables + conf["preferredOutput"] = outputTables + conf["shortcuts"] = tablesShortcuts config.conf["brailleExtender"]["tabSpace"] = self.tabSpace.IsChecked() config.conf["brailleExtender"][f"tabSize_{configBE.curBD}"] = self.tabSize.Value def postSave(self): - configBE.initializePreferredTables() + pass #initializePreferredTables() class TableGroupsDlg(gui.settingsDialogs.SettingsDialog): @@ -514,20 +515,21 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry")): super().__init__(parent, title=title) mainSizer = wx.BoxSizer(wx.VERTICAL) sHelper = gui.guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL) - self.name = sHelper.addLabeledControl(_("Group name"), wx.TextCtrl) - label = _(f"Group members") + self.name = sHelper.addLabeledControl(_("Group &name"), wx.TextCtrl) + label = _("Group &members") self.members = sHelper.addLabeledControl( label, gui.nvdaControls.CustomCheckListBox, choices=listTablesDisplayName(listUncontractedTables())) self.members.SetSelection(0) self.members.Bind(wx.EVT_CHECKLISTBOX, lambda s: self.refreshOrders()) - label = _("Usable in") + label = _("Table &order") self.order = sHelper.addLabeledControl( - _("Order of the tables"), wx.Choice, choices=[]) + label, wx.Choice, choices=[]) self.refreshOrders() - choices = [_("input"), _("output")] - self.usableIn = sHelper.addLabeledControl( - label, gui.nvdaControls.CustomCheckListBox, choices=choices) - self.usableIn.SetSelection(0) + label = _("&Usable in") + choices = list(USABLE_LIST_LABELS.values()) + self.usableIn = sHelper.addItem(wx.RadioBox(self, + label=label, choices=choices)) + self.usableIn.SetSelection(1) sHelper.addDialogDismissButtons( self.CreateButtonSizer(wx.OK | wx.CANCEL)) mainSizer.Add(sHelper.sizer, border=20, flag=wx.ALL) diff --git a/addon/globalPlugins/brailleExtender/configBE.py b/addon/globalPlugins/brailleExtender/configBE.py index c645f638..f61a1249 100644 --- a/addon/globalPlugins/brailleExtender/configBE.py +++ b/addon/globalPlugins/brailleExtender/configBE.py @@ -12,7 +12,6 @@ import config import configobj import inputCore -from . import brailleTablesExt from .common import * from .oneHandMode import DOT_BY_DOT, ONE_SIDE, BOTH_SIDES @@ -276,16 +275,10 @@ def loadConf(): limitCellsRight = int(config.conf["brailleExtender"]["rightMarginCells_%s" % curBD]) if (backupDisplaySize-limitCellsRight <= backupDisplaySize and limitCellsRight > 0): braille.handler.displaySize = backupDisplaySize-limitCellsRight - if config.conf["brailleExtender"]["tables"]["shortcuts"] not in brailleTablesExt.listTablesFileName(brailleTablesExt.listUncontractedTables()): config.conf["brailleExtender"]["tables"]["shortcuts"] = '?' if config.conf["brailleExtender"]["features"]["roleLabels"]: loadRoleLabels(config.conf["brailleExtender"]["roleLabels"].copy()) - initializePreferredTables() return True -def initializePreferredTables(): - global inputTables, outputTables - inputTables, outputTables = brailleTablesExt.getPreferredTables() - def loadGestures(): if gesturesFileExists: if os.path.exists(os.path.join(profilesDir, "_BrowseMode", config.conf["braille"]["inputTable"] + ".ini")): GLng = config.conf["braille"]["inputTable"] From 348a6f7d3935f03514f55af53de0b5750ccce8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Sat, 24 Oct 2020 17:05:11 +0200 Subject: [PATCH 09/11] WIP: Code refactoring --- .../globalPlugins/brailleExtender/__init__.py | 74 +++--- .../globalPlugins/brailleExtender/patches.py | 1 - .../globalPlugins/brailleExtender/settings.py | 4 +- .../{dictionaries.py => tabledictionaries.py} | 22 +- .../{brailleTablesExt.py => tablegroups.py} | 249 ++++++------------ .../brailleExtender/tablehelper.py | 63 +++++ .../brailleExtender/undefinedChars.py | 8 +- addon/globalPlugins/brailleExtender/utils.py | 14 +- 8 files changed, 201 insertions(+), 234 deletions(-) rename addon/globalPlugins/brailleExtender/{dictionaries.py => tabledictionaries.py} (96%) rename addon/globalPlugins/brailleExtender/{brailleTablesExt.py => tablegroups.py} (72%) create mode 100644 addon/globalPlugins/brailleExtender/tablehelper.py diff --git a/addon/globalPlugins/brailleExtender/__init__.py b/addon/globalPlugins/brailleExtender/__init__.py index dc1f6f8d..bc3d252a 100644 --- a/addon/globalPlugins/brailleExtender/__init__.py +++ b/addon/globalPlugins/brailleExtender/__init__.py @@ -46,8 +46,8 @@ from . import utils from .updateCheck import * from . import advancedInputMode -from . import brailleTablesExt -from . import dictionaries +from . import tabledictionaries +from . import tablegroups from . import huc from . import patches from . import settings @@ -204,7 +204,7 @@ def __init__(self): if config.conf["brailleExtender"]["reverseScrollBtns"]: self.reverseScrollBtns() self.createMenu() advancedInputMode.initialize() - brailleTablesExt.initializeGroups() + tablegroups.initializeGroups() log.info(f"{addonName} {addonVersion} loaded ({round(time.time()-startTime, 2)}s)") def event_gainFocus(self, obj, nextHandler): @@ -262,13 +262,13 @@ def createMenu(self): lambda event: wx.CallAfter(gui.mainFrame._popupSettingsDialog, settings.AddonSettingsDialog), item ) - dictionariesMenu = wx.Menu() - self.submenu.AppendSubMenu(dictionariesMenu, _("Table &dictionaries"), _("'Braille dictionaries' menu")) - item = dictionariesMenu.Append(wx.ID_ANY, _("&Global dictionary"), _("A dialog where you can set global dictionary by adding dictionary entries to the list.")) + tabledictionariesMenu = wx.Menu() + self.submenu.AppendSubMenu(tabledictionariesMenu, _("Table &dictionaries"), _("'Braille dictionaries' menu")) + item = tabledictionariesMenu.Append(wx.ID_ANY, _("&Global dictionary"), _("A dialog where you can set global dictionary by adding dictionary entries to the list.")) gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onDefaultDictionary, item) - item = dictionariesMenu.Append(wx.ID_ANY, _("&Table dictionary"), _("A dialog where you can set table-specific dictionary by adding dictionary entries to the list.")) + item = tabledictionariesMenu.Append(wx.ID_ANY, _("&Table dictionary"), _("A dialog where you can set table-specific dictionary by adding dictionary entries to the list.")) gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onTableDictionary, item) - item = dictionariesMenu.Append(wx.ID_ANY, _("Te&mporary dictionary"), _("A dialog where you can set temporary dictionary by adding dictionary entries to the list.")) + item = tabledictionariesMenu.Append(wx.ID_ANY, _("Te&mporary dictionary"), _("A dialog where you can set temporary dictionary by adding dictionary entries to the list.")) gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, self.onTemporaryDictionary, item) item = self.submenu.Append(wx.ID_ANY, _("Advanced &input mode dictionary..."), _("Advanced input mode configuration")) @@ -296,8 +296,8 @@ def createMenu(self): self.submenu_item = gui.mainFrame.sysTrayIcon.menu.InsertMenu(2, wx.ID_ANY, "%s (%s)" % (_("&Braille Extender"), addonVersion), self.submenu) def reloadBrailleTables(self): - dictionaries.setDictTables() - dictionaries.notifyInvalidTables() + tabledictionaries.setDictTables() + tabledictionaries.notifyInvalidTables() if config.conf["brailleExtender"]["tabSpace"]: liblouisDef = r"always \t " + ("0-" * configBE.getTabSize()).strip('-') patches.louis.compileString(patches.getCurrentBrailleTables(), bytes(liblouisDef, "ASCII")) @@ -305,16 +305,16 @@ def reloadBrailleTables(self): @staticmethod def onDefaultDictionary(evt): - gui.mainFrame._popupSettingsDialog(dictionaries.DictionaryDlg, _("Global dictionary"), "default") + gui.mainFrame._popupSettingsDialog(tabledictionaries.DictionaryDlg, _("Global dictionary"), "default") @staticmethod def onTableDictionary(evt): - outTable = brailleTablesExt.listTablesDisplayName()[brailleTablesExt.listTablesFileName().index(config.conf["braille"]["translationTable"])] - gui.mainFrame._popupSettingsDialog(dictionaries.DictionaryDlg, _("Table dictionary ({})").format(outTable), "table") + outTable = tablegroups.listTablesDisplayName()[tablegroups.listTablesFileName().index(config.conf["braille"]["translationTable"])] + gui.mainFrame._popupSettingsDialog(tabledictionaries.DictionaryDlg, _("Table dictionary ({})").format(outTable), "table") @staticmethod def onTemporaryDictionary(evt): - gui.mainFrame._popupSettingsDialog(dictionaries.DictionaryDlg, _("Temporary dictionary"), "tmp") + gui.mainFrame._popupSettingsDialog(tabledictionaries.DictionaryDlg, _("Temporary dictionary"), "tmp") def restorReviewCursorTethering(self): if not self.switchedMode: return @@ -618,7 +618,7 @@ def script_reportExtraInfos(self, gesture): def script_getTableOverview(self, gesture): inTable = brailleInput.handler.table.displayName - ouTable = brailleTablesExt.listTablesDisplayName()[brailleTablesExt.listTablesFileName().index(config.conf["braille"]["translationTable"])] + ouTable = tablegroups.listTablesDisplayName()[tablegroups.listTablesFileName().index(config.conf["braille"]["translationTable"])] t = (_(" Input table")+": %s\n"+_("Output table")+": %s\n\n") % (inTable+' (%s)' % (brailleInput.handler.table.fileName), ouTable+' (%s)' % (config.conf["braille"]["translationTable"])) t += utils.getTableOverview() ui.browseableMessage("
%s
" % t, _("Table overview (%s)" % brailleInput.handler.table.displayName), True) @@ -831,19 +831,19 @@ def script_decreaseDelayAutoScroll(self, gesture): script_decreaseDelayAutoScroll.__doc__ = _("Decreases braille autoscroll delay") def script_switchInputBrailleTable(self, gesture): - usableIn = brailleTablesExt.USABLE_INPUT - choices = brailleTablesExt.getPreferredTables()[0] + brailleTablesExt.getGroups(0)[0] + usageIn = tablegroups.USAGE_INPUT + choices = tablegroups.getPreferredTables()[0] + tablegroups.getGroups(0)[0] if len(choices) < 2: return ui.message(_("Please fill at least two tables and/or groups of tables for this feature first")) - newGroup = brailleTablesExt.getGroup( - position=brailleTablesExt.POSITION_NEXT, - usableIn=usableIn + newGroup = tablegroups.getGroup( + position=tablegroups.POSITION_NEXT, + usageIn=usageIn ) - res = brailleTablesExt.setTableOrGroup( - usableIn=usableIn, + res = tablegroups.setTableOrGroup( + usageIn=usageIn, e=newGroup ) - table = brailleTablesExt.getTable(newGroup.members[0] if newGroup else config.conf["braille"]["inputTable"]) + table = tablegroups.get_table_by_file_name(newGroup.members[0] if newGroup else config.conf["braille"]["inputTable"]) if table: brailleInput.handler._table = table if not res: raise RuntimeError("error") self.reloadBrailleTables() @@ -854,23 +854,23 @@ def script_switchInputBrailleTable(self, gesture): script_switchInputBrailleTable.__doc__ = _("Switch between your favorite input braille tables including groups") def script_switchOutputBrailleTable(self, gesture): - usableIn = brailleTablesExt.USABLE_OUTPUT - choices = brailleTablesExt.getPreferredTables()[1] + brailleTablesExt.getGroups(0)[1] + usageIn = tablegroups.USAGE_OUTPUT + choices = tablegroups.getPreferredTables()[1] + tablegroups.getGroups(0)[1] if len(choices) < 2: return ui.message(_("Please fill at least two tables and/or groups of tables for this feature first")) - newGroup = brailleTablesExt.getGroup( - position=brailleTablesExt.POSITION_NEXT, - usableIn=usableIn + newGroup = tablegroups.getGroup( + position=tablegroups.POSITION_NEXT, + usageIn=usageIn ) - res = brailleTablesExt.setTableOrGroup( - usableIn=usableIn, + res = tablegroups.setTableOrGroup( + usageIn=usageIn, e=newGroup ) if not res: raise RuntimeError("error") self.reloadBrailleTables() utils.refreshBD() dictionaries.setDictTables() - desc = (newGroup.name + (" (%s)" % _("group") if len(newGroup.members) > 1 else '') if newGroup else (_("Default") + " (%s)" % brailleTablesExt.fileName2displayName([config.conf["braille"]["translationTable"]])[0])) + desc = (newGroup.name + (" (%s)" % _("group") if len(newGroup.members) > 1 else '') if newGroup else (_("Default") + " (%s)" % tablegroups.fileName2displayName([config.conf["braille"]["translationTable"]])[0])) ui.message(_("Output: %s") % desc) script_switchOutputBrailleTable.__doc__ = _("Switch between your favorite output braille tables including groups") @@ -878,13 +878,13 @@ def script_switchOutputBrailleTable(self, gesture): def script_currentBrailleTable(self, gesture): inTable = None ouTable = None - if brailleTablesExt.groupEnabled(): - i = brailleTablesExt.getGroup(brailleTablesExt.USABLE_INPUT) - o = brailleTablesExt.getGroup(brailleTablesExt.USABLE_OUTPUT) + if tablegroups.groupEnabled(): + i = tablegroups.getGroup(tablegroups.USAGE_INPUT) + o = tablegroups.getGroup(tablegroups.USAGE_OUTPUT) if i: inTable = i.name if o: ouTable = o.name if not inTable: inTable = brailleInput.handler.table.displayName - if not ouTable: ouTable = brailleTablesExt.listTablesDisplayName()[brailleTablesExt.listTablesFileName().index(config.conf["braille"]["translationTable"])] + if not ouTable: ouTable = tablegroups.listTablesDisplayName()[tablegroups.listTablesFileName().index(config.conf["braille"]["translationTable"])] if ouTable == inTable: braille.handler.message(_("I⣿O:{I}").format(I=inTable, O=ouTable)) speech.speakMessage(_("Input and output: {I}.").format(I=inTable, O=ouTable)) @@ -1268,7 +1268,7 @@ def script_autoTest(self, gesture): def script_addDictionaryEntry(self, gesture): curChar = utils.getCurrentChar() - gui.mainFrame._popupSettingsDialog(dictionaries.DictionaryEntryDlg, title=_("Add dictionary entry or see a dictionary"), textPattern=curChar, specifyDict=True) + gui.mainFrame._popupSettingsDialog(tabledictionaries.DictionaryEntryDlg, title=_("Add dictionary entry or see a dictionary"), textPattern=curChar, specifyDict=True) script_addDictionaryEntry.__doc__ = _("Adds an entry in braille dictionary") def script_toggle_blank_line_scroll(self, gesture): @@ -1318,7 +1318,7 @@ def terminate(self): self.autoScrollTimer.Stop() config.conf["braille"]["showCursor"] = self.backupShowCursor if self.autoTestPlayed: self.autoTestTimer.Stop() - dictionaries.removeTmpDict() + tabledictionaries.removeTmpDict() advancedInputMode.terminate() super().terminate() diff --git a/addon/globalPlugins/brailleExtender/patches.py b/addon/globalPlugins/brailleExtender/patches.py index a0ba3c86..bff49f36 100644 --- a/addon/globalPlugins/brailleExtender/patches.py +++ b/addon/globalPlugins/brailleExtender/patches.py @@ -37,7 +37,6 @@ from . import advancedInputMode from . import brailleRegionHelper from . import configBE -from . import dictionaries from . import huc from . import undefinedChars from .oneHandMode import process as processOneHandMode diff --git a/addon/globalPlugins/brailleExtender/settings.py b/addon/globalPlugins/brailleExtender/settings.py index 67f93fbc..e60a9c31 100644 --- a/addon/globalPlugins/brailleExtender/settings.py +++ b/addon/globalPlugins/brailleExtender/settings.py @@ -20,7 +20,7 @@ import ui addonHandler.initTranslation() -from .brailleTablesExt import SettingsDlg as BrailleTablesDlg +from .tablegroups import SettingsDlg as BrailleTablesDlg from . import configBE from . import utils from .advancedInputMode import SettingsDlg as AdvancedInputModeDlg @@ -481,7 +481,7 @@ class AddonSettingsDialog(gui.settingsDialogs.MultiCategorySettingsDialog): categoryClasses=[ GeneralDlg, AttribraDlg, - BrailleTablesDlg, + #BrailleTablesDlg, UndefinedCharsDlg, AdvancedInputModeDlg, OneHandModeDlg, diff --git a/addon/globalPlugins/brailleExtender/dictionaries.py b/addon/globalPlugins/brailleExtender/tabledictionaries.py similarity index 96% rename from addon/globalPlugins/brailleExtender/dictionaries.py rename to addon/globalPlugins/brailleExtender/tabledictionaries.py index 12c79acd..c20b9b84 100644 --- a/addon/globalPlugins/brailleExtender/dictionaries.py +++ b/addon/globalPlugins/brailleExtender/tabledictionaries.py @@ -4,7 +4,7 @@ from logHandler import log from . import huc -from . import brailleTablesExt +from . import tablegroups from .common import configDir from collections import namedtuple import louis @@ -62,19 +62,19 @@ def checkTable(path): return True -def getValidPathsDict(usableIn): +def getValidPathsDict(usageIn): types = ["tmp", "table", "default"] - paths = [getPathDict(type_, usableIn) for type_ in types] + paths = [getPathDict(type_, usageIn) for type_ in types] def valid(path): return os.path.exists( path) and os.path.isfile(path) and checkTable(path) return [path for path in paths if valid(path)] -def getPathDict(type_, usableIn="io"): - groupEnabled = brailleTablesExt.groupEnabled() - g = brailleTablesExt.getGroup(usableIn=usableIn) +def getPathDict(type_, usageIn="io"): + groupEnabled = tablegroups.groupEnabled() + g = tablegroups.getGroup(usageIn=usageIn) table = os.path.join(configDir, "brailleDicts", config.conf["braille"]["inputTable"] - ) if usableIn == brailleTablesExt.USABLE_INPUT else config.conf["braille"]["translationTable"] + ) if usageIn == tablegroups.USAGE_INPUT else config.conf["braille"]["translationTable"] if type_ == "table": if groupEnabled and g and g.members: if len(g.members) == 1: @@ -135,8 +135,8 @@ def saveDict(type_, dict_): def setDictTables(): global inputTables, outTable - inputTables = getValidPathsDict(brailleTablesExt.USABLE_INPUT) - outputTables = getValidPathsDict(brailleTablesExt.USABLE_OUTPUT) + inputTables = getValidPathsDict(tablegroups.USAGE_INPUT) + outputTables = getValidPathsDict(tablegroups.USAGE_OUTPUT) invalidTables.clear() @@ -362,7 +362,7 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry"), textPattern='' if specifyDict: # Translators: This is a label for an edit field in add dictionary entry dialog. dictText = _("Dictionary") - outTable = brailleTablesExt.fileName2displayName( + outTable = tablegroups.fileName2displayName( config.conf["braille"]["translationTable"]) dictChoices = [_("Global"), _( "Table ({})").format(outTable), _("Temporary")] @@ -418,7 +418,7 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry"), textPattern='' self.Bind(wx.EVT_BUTTON, self.onOk, id=wx.ID_OK) def onSeeEntriesClick(self, evt): - outTable = brailleTablesExt.fileName2displayName( + outTable = tablegroups.fileName2displayName( config.conf["braille"]["translationTable"]) label = [_("Global dictionary"), _("Table dictionary ({})").format( outTable), _("Temporary dictionary")][self.dictRadioBox.GetSelection()] diff --git a/addon/globalPlugins/brailleExtender/brailleTablesExt.py b/addon/globalPlugins/brailleExtender/tablegroups.py similarity index 72% rename from addon/globalPlugins/brailleExtender/brailleTablesExt.py rename to addon/globalPlugins/brailleExtender/tablegroups.py index faed3700..b0bf4344 100644 --- a/addon/globalPlugins/brailleExtender/brailleTablesExt.py +++ b/addon/globalPlugins/brailleExtender/tablegroups.py @@ -10,13 +10,12 @@ import addonHandler import config -from collections import namedtuple from itertools import permutations from typing import Optional, List, Tuple from brailleTables import listTables from logHandler import log from . import configBE -from .common import addonName, baseDir, configDir +from .common import baseDir, configDir addonHandler.initTranslation() @@ -25,127 +24,25 @@ POSITION_NEXT = "n" POSITIONS = [POSITION_CURRENT, POSITION_PREVIOUS, POSITION_NEXT] -USABLE_INPUT = 0 -USABLE_OUTPUT = 1 -USABLE_BOTH = 2 -USABLE_LIST = [USABLE_INPUT, USABLE_OUTPUT, USABLE_BOTH] +USAGE_INPUT = 0 +USAGE_OUTPUT = 1 +USAGE_BOTH = 2 +USAGES = [USAGE_INPUT, USAGE_OUTPUT, USAGE_BOTH] -USABLE_LIST_LABELS = { - USABLE_INPUT: _("input only"), - USABLE_OUTPUT: _("output only"), - USABLE_BOTH: _("input and output") +USAGE_LABELS = { + USAGE_INPUT: _("input only"), + USAGE_OUTPUT: _("output only"), + USAGE_BOTH: _("input and output") } -GroupTables = namedtuple("GroupTables", ( - "name", "members", "usableIn")) -conf = config.conf["brailleExtender"]["tables"] +class GroupTable: + name = None + members: list = [] + usageIn = None -def listContractedTables(tables=None): - return [table for table in ( - tables or listTables()) if table.contracted] - -def listUncontractedTables(tables=None): - return [table for table in ( - tables or listTables()) if not table.contracted] - - -def listInputTables(tables=None): - return [ - table for table in (tables or listTables()) if table.input] - - -listUncontractedInputTables = listInputTables(listUncontractedTables()) - - -def listOutputTables(tables=None): - return [ - table for table in (tables or listTables()) if table.output] - - -def listTablesFileName(tables=None): - return [ - table.fileName for table in (tables or listTables())] - - -def listTablesDisplayName(tables=None): - return [ - table.displayName for table in (tables or listTables())] - - -def fileName2displayName(l): - allTablesFileName = listTablesFileName() - o = [] - for e in l: - if e in allTablesFileName: - o.append(allTablesFileName.index(e)) - return [listTables()[e].displayName for e in o] - - -def listTablesIndexes(l, tables): - if not tables: - tables = listTables() - tables = listTablesFileName(tables) - return [tables.index(e) for e in l if e in tables] - - -def getPreferredTables() -> Tuple[List[str]]: - allInputTablesFileName = listTablesFileName(listInputTables()) - allOutputTablesFileName = listTablesFileName(listOutputTables()) - preferredInputTablesFileName = conf["preferredInput"].split( - '|') - preferredOutputTablesFileName = conf["preferredOutput"].split( - '|') - inputTables = [ - fn for fn in preferredInputTablesFileName if fn in allInputTablesFileName] - outputTables = [ - fn for fn in preferredOutputTablesFileName if fn in allOutputTablesFileName] - return inputTables, outputTables - - -def getPreferredTablesIndexes() -> List[int]: - preferredInputTables, preferredOutputTables = getPreferredTables() - inputTables = listTablesFileName(listInputTables()) - outputTables = listTablesFileName(listOutputTables()) - o = [] - for a, b in [(preferredInputTables, inputTables), (preferredOutputTables, outputTables)]: - o_ = [] - for e in a: - if e in b: - o_.append(b.index(e)) - o.append(o_) - return o - - -def getCustomBrailleTables(): - return [config.conf["brailleExtender"]["brailleTables"][k].split('|', 3) for k in config.conf["brailleExtender"]["brailleTables"]] - - -def isContractedTable(fileName): - return fileName in listTablesFileName(listContractedTables()) - - -def getTable(fileName, tables=None): - if not tables: - tables = listTables() - for table in tables: - if table.fileName == fileName: - return table - return None - - -def getTablesFilenameByID(l: List[int], tables=None) -> List[int]: - tablesFileName = [table.fileName for table in (tables or listTables())] - o = [] - size = len(tablesFileName) - for i in l: - if i < size: - o.append(tablesFileName[i]) - return o - - -def translateUsableIn(s): - labels = USABLE_LIST_LABELS +def translateUsageIn(s): + labels = USAGE_LABELS return labels[s] if s in labels.keys() else _("None") @@ -168,7 +65,7 @@ def initializeGroups(): for entry in json_: _groups.append( GroupTables( - entry["name"], entry["members"], entry["usableIn"] + entry["name"], entry["members"], entry["usageIn"] ) ) @@ -180,7 +77,7 @@ def saveGroups(entries=None): { "name": entry.name, "members": entry.members, - "usableIn": entry.usableIn, + "usageIn": entry.usageIn, } for entry in entries ] @@ -192,28 +89,29 @@ def getGroups(plain=True): if plain: return _groups if _groups else [] groups = getGroups() - i = [group for group in groups if group.usableIn in ['i', 'io']] - o = [group for group in groups if group.usableIn in ['o', 'io']] + i = [group for group in groups if group.usageIn in [USAGE_INPUT, USAGE_BOTH]] + o = [group for group in groups if group.usageIn in [USAGE_OUTPUT, USAGE_BOTH]] return i, o -def getAllGroups(usableIn): - usableInIndex = USABLE_LIST.index(usableIn) - return [None] + tablesToGroups(getPreferredTables()[usableInIndex], usableIn=usableIn) + getGroups(0)[usableInIndex] +def getAllGroups(usageIn): + return [None] + usageInIndex = USAGES.index(usageIn) + return [None] + tablesToGroups(getPreferredTables()[usageInIndex], usageIn=usageIn) + getGroups(0)[usageInIndex] def getGroup( - usableIn, + usageIn, position=POSITION_CURRENT, choices=None ): global _currentGroup - if position not in POSITIONS or usableIn not in USABLE_LIST: + if position not in POSITIONS or usageIn not in USAGES: return None - usableInIndex = USABLE_LIST.index(usableIn) - currentGroup = _currentGroup[usableInIndex] + usageInIndex = USAGES.index(usageIn) + currentGroup = _currentGroup[usageInIndex] if not choices: - choices = getAllGroups(usableIn) + choices = getAllGroups(usageIn) if currentGroup not in choices: currentGroup = choices[0] curPos = choices.index(currentGroup) @@ -225,25 +123,25 @@ def getGroup( return choices[newPos % len(choices)] -def setTableOrGroup(usableIn, e, choices=None): +def setTableOrGroup(usageIn, e, choices=None): global _currentGroup - if not usableIn in USABLE_LIST: + if not usageIn in USAGES: return False - usableInIndex = USABLE_LIST.index(usableIn) - choices = getAllGroups(usableIn) + usageInIndex = USAGES.index(usageIn) + choices = getAllGroups(usageIn) if not e in choices: return False - _currentGroup[usableInIndex] = e + _currentGroup[usageInIndex] = e return True -def tablesToGroups(tables, usableIn): +def tablesToGroups(tables, usageIn): groups = [] for table in tables: groups.append(GroupTables( - ", ".join(fileName2displayName([table])), + ", ".join(get_file_name_by_display_name([table])), [table], - usableIn + usageIn )) return groups @@ -286,12 +184,14 @@ def makeSettings(self, settingsSizer): label = _("Input braille table to use for keyboard shortcuts") try: selectedItem = 0 if conf["shortcuts"] == '?' else listTablesFileName( - listUncontractedInputTables + get_tables(input=True, contracted=False) ).index(conf["shortcuts"]) + 1 except ValueError: selectedItem = 0 self.inputTableShortcuts = sHelper.addLabeledControl(label, wx.Choice, choices=[ - currentTableLabel] + listTablesDisplayName(listUncontractedInputTables)) + currentTableLabel] + get_display_names( + get_tables(contracted=False, input=True) + )) self.inputTableShortcuts.SetSelection(selectedItem) self.tablesGroupBtn = bHelper1.addButton( @@ -345,19 +245,19 @@ def isValid(self): return super().isValid() def onSave(self): - inputTables = '|'.join(getTablesFilenameByID( + inputTables = '|'.join(get_tables_file_name_by_id( self.inputTables.CheckedItems, - listInputTables() + get_tables(input=True) )) outputTables = '|'.join( - getTablesFilenameByID( + get_tables_file_name_by_id( self.outputTables.CheckedItems, - listOutputTables() + get_tables(output=True) ) ) - tablesShortcuts = getTablesFilenameByID( + tablesShortcuts = get_tables_file_name_by_id( [self.inputTableShortcuts.GetSelection()-1], - listUncontractedInputTables + get_tables(contracted=False, input=True) )[0] if self.inputTableShortcuts.GetSelection() > 0 else '?' conf["preferredInput"] = inputTables conf["preferredOutput"] = outputTables @@ -372,7 +272,7 @@ def postSave(self): class TableGroupsDlg(gui.settingsDialogs.SettingsDialog): # Translators: title of a dialog. - title = f"{addonName} - %s" % _("table groups") + title = _("Table groups") def makeSettings(self, settingsSizer): self.tmpGroups = getGroups() @@ -427,8 +327,8 @@ def onSetEntries(self, evt=None): for group in self.tmpGroups: self.groupsList.Append(( group.name, - ", ".join(fileName2displayName(group.members)), - translateUsableIn(group.usableIn) + ", ".join(FileName2displayName(group.members)), + translateUsageIn(group.usageIn) )) def onAddClick(self, event): @@ -437,8 +337,8 @@ def onAddClick(self, event): entry = entryDialog.groupEntry self.tmpGroups.append(entry) self.groupsList.Append( - (entry.name, ", ".join(fileName2displayName(entry.members)), - translateUsableIn(entry.usableIn)) + (entry.name, ", ".join(FileName2displayName(entry.members)), + translateUsageIn(entry.usageIn)) ) index = self.groupsList.GetFirstSelected() while index >= 0: @@ -457,25 +357,25 @@ def onEditClick(self, event): entryDialog = GroupEntryDlg(self) entryDialog.name.SetValue(self.tmpGroups[editIndex].name) entryDialog.members.CheckedItems = listTablesIndexes( - self.tmpGroups[editIndex].members, listUncontractedInputTables) + self.tmpGroups[editIndex].members, get_tables(contracted=False, input=True)) entryDialog.refreshOrders() selectedItem = 0 try: selectedItem = list(entryDialog.orderPermutations.keys()).index(tuple( - listTablesIndexes(self.tmpGroups[editIndex].members, listUncontractedTables()))) + listTablesIndexes(self.tmpGroups[editIndex].members, get_tables(contracted=False)))) entryDialog.order.SetSelection(selectedItem) except ValueError: pass - entryDialog.usableIn.CheckedItems = translateUsableInIndexes( - self.tmpGroups[editIndex].usableIn) + entryDialog.usageIn.CheckedItems = translateUsageInIndexes( + self.tmpGroups[editIndex].usageIn) if entryDialog.ShowModal() == wx.ID_OK: entry = entryDialog.groupEntry self.tmpGroups[editIndex] = entry self.groupsList.SetItem(editIndex, 0, entry.name) self.groupsList.SetItem(editIndex, 1, ", ".join( - fileName2displayName(entry.members))) + FileName2displayName(entry.members))) self.groupsList.SetItem( - editIndex, 2, translateUsableIn(entry.usableIn)) + editIndex, 2, translateUsageIn(entry.usageIn)) self.groupsList.SetFocus() entryDialog.Destroy() @@ -515,21 +415,23 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry")): super().__init__(parent, title=title) mainSizer = wx.BoxSizer(wx.VERTICAL) sHelper = gui.guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL) - self.name = sHelper.addLabeledControl(_("Group &name"), wx.TextCtrl) + self.name = sHelper.addLabeledControl(_("Group &name:"), wx.TextCtrl) label = _("Group &members") self.members = sHelper.addLabeledControl( - label, gui.nvdaControls.CustomCheckListBox, choices=listTablesDisplayName(listUncontractedTables())) + label, gui.nvdaControls.CustomCheckListBox, choices=get_display_names( + get_tables(contracted=False) + )) self.members.SetSelection(0) self.members.Bind(wx.EVT_CHECKLISTBOX, lambda s: self.refreshOrders()) - label = _("Table &order") + label = _("Table &order:") self.order = sHelper.addLabeledControl( label, wx.Choice, choices=[]) self.refreshOrders() - label = _("&Usable in") - choices = list(USABLE_LIST_LABELS.values()) - self.usableIn = sHelper.addItem(wx.RadioBox(self, + label = _("&Usable in:") + choices = list(USAGE_LABELS.values()) + self.usageIn = sHelper.addItem(wx.RadioBox(self, label=label, choices=choices)) - self.usableIn.SetSelection(1) + self.usageIn.SetSelection(1) sHelper.addDialogDismissButtons( self.CreateButtonSizer(wx.OK | wx.CANCEL)) mainSizer.Add(sHelper.sizer, border=20, flag=wx.ALL) @@ -539,9 +441,8 @@ def __init__(self, parent=None, title=_("Edit Dictionary Entry")): self.name.SetFocus() def refreshOrders(self, evt=None): - tables = listUncontractedTables() - self.orderPermutations = {e: fileName2displayName(getTablesFilenameByID( - e, tables)) for e in permutations(self.members.CheckedItems) if e} + tables = get_tables(contracted=False) + self.orderPermutations = {e: FileName2displayName(get_tables_file_name_by_id(e, tables)) for e in permutations(self.members.CheckedItems) if e} self.order.SetItems([", ".join(e) for e in self.orderPermutations.values()]) self.order.SetSelection(0) @@ -550,10 +451,10 @@ def onOk(self, evt): name = self.name.Value if not self.orderPermutations: return - members = getTablesFilenameByID(list(self.orderPermutations.keys())[ - self.order.GetSelection()], listUncontractedTables()) - matches = ['i', 'o'] - usableIn = ''.join([matches[e] for e in self.usableIn.CheckedItems]) + members = get_tables_file_name_by_id(list(self.orderPermutations.keys())[ + self.order.GetSelection()], get_tables(contracted=False)) + matches = USAGE_LABELS.keys() + usageIn = ''.join([matches[e] for e in self.usageIn.CheckedItems]) if not name: gui.messageBox( _("Please specify a group name"), @@ -570,14 +471,14 @@ def onOk(self, evt): self ) return self.members.SetFocus() - self.groupEntry = GroupTables(name, members, usableIn) + self.groupEntry = GroupTables(name, members, usageIn) evt.Skip() class CustomBrailleTablesDlg(gui.settingsDialogs.SettingsDialog): # Translators: title of a dialog. - title = f"{addonName} - %s" % _("Custom braille tables") + title = _("Custom braille tables") providedTablesPath = "%s/res/json" % baseDir userTablesPath = "%s/json" % configDir @@ -648,7 +549,7 @@ def onBrowseBtn(self, event): if dlg.ShowModal() != wx.ID_OK: dlg.Destroy() return self.path.SetFocus() - self.path.SetValue(dlg.GetDirectory() + '\\' + dlg.GetFilename()) + self.path.SetValue(dlg.GetDirectory() + '\\' + dlg.GetFileName()) dlg.Destroy() self.path.SetFocus() diff --git a/addon/globalPlugins/brailleExtender/tablehelper.py b/addon/globalPlugins/brailleExtender/tablehelper.py new file mode 100644 index 00000000..0f924e8a --- /dev/null +++ b/addon/globalPlugins/brailleExtender/tablehelper.py @@ -0,0 +1,63 @@ +# tablehelper.py +# Part of BrailleExtender addon for NVDA +# Copyright 2016-2020 André-Abush CLAUSE, released under GPL. +from brailleTables import listTables +from typing import List + +def get_tables(tables=None, contracted=None, output=None, input=None): + if not tables: + tables = listTables() + if isinstance(contracted, bool): + tables = filter(lambda e: e.contracted == contracted, tables) + if isinstance(input, bool): + tables = filter(lambda e: e.input == input, tables) + if isinstance(output, bool): + tables = filter(lambda e: e.output == output, tables) + return list(tables) + + +def get_file_names(tables=None): + if not tables: + tables = listTables() + return [table.fileName for table in tables] + + +def get_file_names_by_display_names(l): + file_names = get_file_names() + o = [] + for e in l: + if e in file_names: + o.append(file_names.index(e)) + return [listTables()[e].displayName for e in o] + + +def get_display_names(tables=None): + if not tables: + tables = listTables() + return [table.displayName for table in tables] + + +def get_indexes(l, tables): + if not tables: + tables = listTables() + tables = get_file_names(tables) + return [tables.index(e) for e in l if e in tables] + + +def get_table_by_file_name(FileName, tables=None): + if not tables: + tables = listTables() + for table in tables: + if table.fileName == FileName: + return table + return None + + +def get_tables_file_name_by_id(l: List[int], tables=None) -> List[int]: + file_names = get_file_names(tables or listTables()) + o = [] + size = len(file_names) + for i in l: + if i < size: + o.append(file_names[i]) + return o diff --git a/addon/globalPlugins/brailleExtender/undefinedChars.py b/addon/globalPlugins/brailleExtender/undefinedChars.py index 5f9d7951..000c6561 100644 --- a/addon/globalPlugins/brailleExtender/undefinedChars.py +++ b/addon/globalPlugins/brailleExtender/undefinedChars.py @@ -6,7 +6,7 @@ import wx import addonHandler -from . import brailleTablesExt +from . import tablehelper import characterProcessing import config import gui @@ -309,8 +309,8 @@ def makeSettings(self, settingsSizer): _("&Language"), wx.Choice, choices=values ) self.undefinedCharLang.SetSelection(undefinedCharLangID) - values = [_("Use the current output table")] + brailleTablesExt.listTablesDisplayName(brailleTablesExt.listOutputTables()) - keys = ["current"] + brailleTablesExt.listTablesFileName(brailleTablesExt.listOutputTables()) + values = [_("Use the current output table")] + tablehelper.get_display_names(tablehelper.get_tables(output=True)) + keys = ["current"] + tablehelper.get_file_names(tablehelper.get_tables(output=True)) undefinedCharTable = config.conf["brailleExtender"]["undefinedCharsRepr"][ "table" ] @@ -404,7 +404,7 @@ def onSave(self): 0 ] undefinedCharTable = self.undefinedCharTable.GetSelection() - keys = ["current"] + brailleTablesExt.listTablesFileName(brailleTablesExt.listOutputTables()) + keys = ["current"] + tablehelper.get_file_names(tablehelper.get_tables(output=True)) config.conf["brailleExtender"]["undefinedCharsRepr"]["table"] = keys[ undefinedCharTable ] diff --git a/addon/globalPlugins/brailleExtender/utils.py b/addon/globalPlugins/brailleExtender/utils.py index ebc6fd1c..c42126e8 100644 --- a/addon/globalPlugins/brailleExtender/utils.py +++ b/addon/globalPlugins/brailleExtender/utils.py @@ -22,12 +22,13 @@ addonHandler.initTranslation() import treeInterceptorHandler import unicodedata -from . import brailleTablesExt +from . import tablegroups from .configBE import CHOICE_braille,CHOICE_speech , CHOICE_speechAndBraille from .common import INSERT_AFTER, INSERT_BEFORE, REPLACE_TEXT, baseDir from . import huc -from . import dictionaries +from . import tabledictionaries from . import volume_helper +from logHandler import log get_mute = volume_helper.get_mute get_volume_level = volume_helper.get_volume_level @@ -143,6 +144,9 @@ def getTextInBraille(t=None, table=[]): if not t.strip(): return '' if not table or "current" in table: table = getCurrentBrailleTables() + for i, e in enumerate(table): + if '\\' not in e and '/' not in e: + table[i] = "%s\\%s" % (brailleTables.TABLES_DIR, e) nt = [] res = '' t = t.split("\n") @@ -332,13 +336,13 @@ def getCurrentBrailleTables(input_=False, brf=False): else: tables = [] app = appModuleHandler.getAppModuleForNVDAObject(api.getNavigatorObject()) - if brailleInput.handler._table.fileName == config.conf["braille"]["translationTable"] and app and app.appName != "nvda": tables += dictionaries.inputTables if input_ else dictionaries.outputTables + if brailleInput.handler._table.fileName == config.conf["braille"]["translationTable"] and app and app.appName != "nvda": tables += tabledictionaries.inputTables if input_ else tabledictionaries.outputTables if input_: mainTable = os.path.join(brailleTables.TABLES_DIR, brailleInput.handler._table.fileName) - group = brailleTablesExt.getGroup(usableIn='i') + group = tablegroups.getGroup(usageIn=tablegroups.USAGE_OUTPUT) else: mainTable = os.path.join(brailleTables.TABLES_DIR, config.conf["braille"]["translationTable"]) - group = brailleTablesExt.getGroup(usableIn='o') + group = tablegroups.getGroup(usageIn=tablegroups.USAGE_OUTPUT) if group: group = group.members group = [f if '\\' in f else os.path.join(r"louis\tables", f) for f in group] From d19f24afaad254248d12ef6688d56a52e5e94bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Sat, 7 Nov 2020 14:39:08 +0100 Subject: [PATCH 10/11] Restore 'braille tables' settings --- addon/globalPlugins/brailleExtender/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/globalPlugins/brailleExtender/settings.py b/addon/globalPlugins/brailleExtender/settings.py index c989c3c2..5e5507b0 100644 --- a/addon/globalPlugins/brailleExtender/settings.py +++ b/addon/globalPlugins/brailleExtender/settings.py @@ -483,7 +483,7 @@ class AddonSettingsDialog(gui.settingsDialogs.MultiCategorySettingsDialog): categoryClasses=[ GeneralDlg, AttribraDlg, - #BrailleTablesDlg, + BrailleTablesDlg, UndefinedCharsDlg, AdvancedInputModeDlg, OneHandModeDlg, From 26166c81ca1acbdd286a0a459936ffaf4b1f9392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9-Abush=20Clause?= Date: Sun, 13 Nov 2022 13:09:40 +0100 Subject: [PATCH 11/11] Various enhancements --- .../globalPlugins/brailleExtender/__init__.py | 65 +++-- .../globalPlugins/brailleExtender/addoncfg.py | 5 +- .../brailleExtender/tabledictionaries.py | 4 - .../brailleExtender/tablegroups.py | 237 +++++++++++++----- .../brailleExtender/tablehelper.py | 42 +++- .../brailleExtender/undefinedchars.py | 3 +- addon/globalPlugins/brailleExtender/utils.py | 34 ++- 7 files changed, 280 insertions(+), 110 deletions(-) diff --git a/addon/globalPlugins/brailleExtender/__init__.py b/addon/globalPlugins/brailleExtender/__init__.py index 2844d6d7..f57bcea1 100644 --- a/addon/globalPlugins/brailleExtender/__init__.py +++ b/addon/globalPlugins/brailleExtender/__init__.py @@ -46,6 +46,7 @@ from . import undefinedchars from . import updatecheck from . import utils +from .tablehelper import get_table_by_file_name from .common import (addonName, addonURL, addonVersion, punctuationSeparator, RC_NORMAL, RC_EMULATE_ARROWS_BEEP, RC_EMULATE_ARROWS_SILENT) @@ -232,7 +233,7 @@ def event_gainFocus(self, obj, nextHandler): self.switchedMode = True elif self.switchedMode and obj.role != utils.get_control_type("ROLE_TERMINAL"): self.restorReviewCursorTethering() - if "tabSize_%s" % addoncfg.curBD not in config.conf["brailleExtender"].copy().keys(): self.onReload(None, 1) + if "tabSize_%s" % addoncfg.curBD not in config.conf["brailleExtender"]["tables"].copy().keys(): self.onReload(None, 1) if self.hourDatePlayed: self.script_hourDate(None) if self.autoTestPlayed: self.script_autoTest(None) if braille.handler is not None and addoncfg.curBD != braille.handler.display.name: @@ -296,9 +297,10 @@ def createMenu(self): self.submenu_item = gui.mainFrame.sysTrayIcon.menu.Insert(2, wx.ID_ANY, "%s (%s)" % (_("&Braille Extender"), addonVersion), self.submenu) def reloadBrailleTables(self): - tabledictionaries.setDictTables() - tabledictionaries.notifyInvalidTables() - if config.conf["brailleExtender"]["tabSpace"]: + patches.louis.liblouis.lou_free() + #tabledictionaries.setDictTables() + #tabledictionaries.notifyInvalidTables() + if config.conf["brailleExtender"]["tables"]["tabSpace"]: liblouisDef = r"always \t " + ("0-" * addoncfg.getTabSize()).strip('-') patches.louis.compileString(patches.getCurrentBrailleTables(), bytes(liblouisDef, "ASCII")) undefinedchars.setUndefinedChar() @@ -792,45 +794,66 @@ def script_decreaseDelayAutoScroll(self, gesture): script_decreaseDelayAutoScroll.__doc__ = _("Decrease braille autoscroll delay") def script_switchInputBrailleTable(self, gesture): + table = config.conf["braille"]["inputTable"] usageIn = tablegroups.USAGE_INPUT - choices = tablegroups.getPreferredTables()[0] + tablegroups.getGroups(0)[0] + choices = tablegroups.TableGroups( + tablegroups.tablesToGroups( + tablegroups.getPreferredTables()[0] + tablegroups._groups.get_groups()[0], + usageIn + ) + ) if len(choices) < 2: return ui.message(_("Please fill at least two tables and/or groups of tables for this feature first")) newGroup = tablegroups.getGroup( position=tablegroups.POSITION_NEXT, - usageIn=usageIn - ) - res = tablegroups.setTableOrGroup( usageIn=usageIn, - e=newGroup + choices=choices ) - table = tablegroups.get_table_by_file_name(newGroup.members[0] if newGroup else config.conf["braille"]["inputTable"]) - if table: brailleInput.handler._table = table - if not res: raise RuntimeError("error") + if newGroup: + res = tablegroups.setTableOrGroup( + usageIn=usageIn, + e=newGroup + ) + if not res: + log.error(f"Unable to set table or group (res={res}, usageIn={usageIn} newGroup={newGroup})") + ui.message(_(f"Unable to set table or group")) + return + brailleInput.handler.table = newGroup.members[0] self.reloadBrailleTables() utils.refreshBD() - dictionaries.setDictTables() + #tabledictionaries.setDictTables() desc = (newGroup.name + (" (%s)" % _("group") if len(newGroup.members) > 1 else '') if newGroup else _("Default") + " (%s)" % brailleInput.handler.table.displayName) ui.message(_("Input: %s") % desc) script_switchInputBrailleTable.__doc__ = _("Switch between your favorite input braille tables including groups") def script_switchOutputBrailleTable(self, gesture): + table = config.conf["braille"]["translationTable"] usageIn = tablegroups.USAGE_OUTPUT - choices = tablegroups.getPreferredTables()[1] + tablegroups.getGroups(0)[1] + choices = tablegroups.TableGroups( + tablegroups.tablesToGroups( + tablegroups.getPreferredTables()[1] + tablegroups._groups.get_groups()[1], + usageIn + ) + ) if len(choices) < 2: return ui.message(_("Please fill at least two tables and/or groups of tables for this feature first")) newGroup = tablegroups.getGroup( position=tablegroups.POSITION_NEXT, - usageIn=usageIn - ) - res = tablegroups.setTableOrGroup( usageIn=usageIn, - e=newGroup + choices=choices ) - if not res: raise RuntimeError("error") + if newGroup: + res = tablegroups.setTableOrGroup( + usageIn=usageIn, + e=newGroup + ) + if not res: + log.error(f"Unable to set table or group (res={res}, usageIn={usageIn} newGroup={newGroup})") + ui.message(_(f"Unable to set table or group")) + return self.reloadBrailleTables() utils.refreshBD() - dictionaries.setDictTables() + #tabledictionaries.setDictTables() desc = (newGroup.name + (" (%s)" % _("group") if len(newGroup.members) > 1 else '') if newGroup else (_("Default") + " (%s)" % tablegroups.fileName2displayName([config.conf["braille"]["translationTable"]])[0])) ui.message(_("Output: %s") % desc) @@ -1310,7 +1333,7 @@ def terminate(self): if braille.handler._auto_scroll: braille.handler.toggle_auto_scroll() if self.autoTestPlayed: self.autoTestTimer.Stop() - tabledictionaries.removeTmpDict() + #tabledictionaries.removeTmpDict() advancedinput.terminate() super().terminate() diff --git a/addon/globalPlugins/brailleExtender/addoncfg.py b/addon/globalPlugins/brailleExtender/addoncfg.py index bfa78f95..0cfe8cc5 100644 --- a/addon/globalPlugins/brailleExtender/addoncfg.py +++ b/addon/globalPlugins/brailleExtender/addoncfg.py @@ -143,8 +143,6 @@ def getConfspec(): "backup_tetherTo": 'string(default="focus")', "backup_autoTether": "boolean(default=True)", }, - "tabSpace": "boolean(default=False)", - f"tabSize_{curBD}": "integer(min=1, default=2, max=42)", "undefinedCharsRepr": { "method": f"integer(min=0, default=8)", "hardSignPatternValue": "string(default=??)", @@ -212,7 +210,6 @@ def getConfspec(): }, "quickLaunches": {}, "roleLabels": {}, - "brailleTables": {}, "advancedInputMode": { "stopAfterOneChar": "boolean(default=True)", "escapeSignUnicodeValue": "string(default=⠼)", @@ -226,6 +223,8 @@ def getConfspec(): "shortcuts": 'string(default="?")', "preferredInput": f'string(default="{config.conf["braille"]["inputTable"]}|unicode-braille.utb")', "preferredOutput": f'string(default="{config.conf["braille"]["translationTable"]}")', + "tabSpace": "boolean(default=False)", + f"tabSize_{curBD}": "integer(min=1, default=2, max=42)", }, } diff --git a/addon/globalPlugins/brailleExtender/tabledictionaries.py b/addon/globalPlugins/brailleExtender/tabledictionaries.py index 5d8f9e3c..891ad2be 100644 --- a/addon/globalPlugins/brailleExtender/tabledictionaries.py +++ b/addon/globalPlugins/brailleExtender/tabledictionaries.py @@ -162,10 +162,6 @@ def removeTmpDict(): os.remove(path) -setDictTables() -notifyInvalidTables() - - class DictionaryDlg(gui.settingsDialogs.SettingsDialog): def __init__(self, parent, title, type_): diff --git a/addon/globalPlugins/brailleExtender/tablegroups.py b/addon/globalPlugins/brailleExtender/tablegroups.py index bba2f4dc..e540ac59 100644 --- a/addon/globalPlugins/brailleExtender/tablegroups.py +++ b/addon/globalPlugins/brailleExtender/tablegroups.py @@ -1,6 +1,6 @@ -# brailleTablesExt.py +# tablegroups.py # Part of BrailleExtender addon for NVDA -# Copyright 2016-2020 André-Abush CLAUSE, released under GPL. +# Copyright 2016-2022 André-Abush Clause, released under GPL. import codecs import json @@ -11,11 +11,14 @@ import addonHandler import config from itertools import permutations -from typing import Optional, List, Tuple -from brailleTables import listTables +from brailleTables import listTables, TABLES_DIR from logHandler import log from . import addoncfg from .common import baseDir, configDir +from .tablehelper import ( + getPreferredTables, getPreferredTablesIndexes, + get_display_names, get_tables, get_tables_file_name_by_id, get_file_names_by_display_names, get_table_by_file_name +) addonHandler.initTranslation() @@ -27,7 +30,7 @@ USAGE_INPUT = 0 USAGE_OUTPUT = 1 USAGE_BOTH = 2 -USAGES = [USAGE_INPUT, USAGE_OUTPUT, USAGE_BOTH] +USAGES = (USAGE_INPUT, USAGE_OUTPUT, USAGE_BOTH) USAGE_LABELS = { USAGE_INPUT: _("input only"), @@ -35,69 +38,147 @@ USAGE_BOTH: _("input and output") } -class GroupTable: +class TableGroups: + + _groups = [] + + def __init__(self, groups=[]): + self._groups = [] + if groups: + for group in groups: self.add_group(group) + + def __len__(self): + return len(self._groups) + + def __getitem__(self, item): + return self._groups[item] + + def __contains__(self, value): + for i, group in enumerate(self._groups): + if self.is_similar(value, group): return True + return False + + def index(self, value): + for i, group in enumerate(self._groups): + if self.is_similar(value, group): return i + raise IndexError ("Group is not in list group") + + def add_group(self, groupTable): + if not isinstance(groupTable, TableGroup): + raise TypeError("groupTable: wrong type") + self._groups.append(groupTable) + + def is_similar(self, group1, group2): + if group1.usageIn != group2.usageIn: + return False + if len(group1.members) != len(group2.members): + return False + if group1.members != group2.members: + return False + return True + + def get_json(self): + data = [ + { + "name": group.name, + "members": [m.fileName for m in group.members], + "usageIn": group.usageIn, + } + for group in self._groups + ] + return data + + def load_json(self, data): + for group in data: + self.add_group( + TableGroups( + entry["name"], + entry["members"], + entry["usageIn"] + ) + ) + + def get_groups(self): + groups = self._groups + i = [group for group in groups if group.usageIn in [USAGE_INPUT, USAGE_BOTH]] + o = [group for group in groups if group.usageIn in [USAGE_OUTPUT, USAGE_BOTH]] + return i, o + + +class TableGroup: + name = None members: list = [] usageIn = None + def __init__(self, + name: str, + members: list, + usageIn + ): + if not isinstance(name, str): + raise TypeError("name: wrong type") + if not isinstance(members, list): + raise TypeError("members: wrong type") + if not isinstance(members, list): + raise TypeError("wrong type") + members = [member for member in members if member] + if len(members) < 1: + raise ValueError("Missing member") + self.name = name + self.usageIn = usageIn + self.members = [] + for member in members: + table = get_table_by_file_name(member) + if table: + self.members.append(table) + else: + raise ValueError(f"invalid table ({member})") + + def __str__(self): + name = self.name + members = self.members + usageIn = self.usageIn + return f'{{name="{name}", members={members}, usageIn={usageIn}}}' + + def get_tables(self): + return [ + os.path.join(TABLES_DIR, member.fileName) + for member in self.members + ] + + def translateUsageIn(s): labels = USAGE_LABELS return labels[s] if s in labels.keys() else _("None") -def setDict(newGroups): - global _groups - _groups = newGroups - - def getPathGroups(): return f"{configDir}/table-groups.json" def initializeGroups(): global _groups - _groups = [] + _groups = TableGroups() fp = getPathGroups() - if not os.path.exists(fp): - return - json_ = json.load(codecs.open(fp, "r", "UTF-8")) - for entry in json_: - _groups.append( - GroupTables( - entry["name"], entry["members"], entry["usageIn"] - ) - ) + if os.path.exists(fp): + json_ = json.load(codecs.open(fp, "r", "UTF-8")) + _groups.load_json(json_) def saveGroups(entries=None): - if not entries: - entries = getGroups() - entries = [ - { - "name": entry.name, - "members": entry.members, - "usageIn": entry.usageIn, - } - for entry in entries - ] + data = tableGroups.get_json() with codecs.open(getPathGroups(), "w", "UTF-8") as outfile: json.dump(entries, outfile, ensure_ascii=False, indent=2) -def getGroups(plain=True): - if plain: - return _groups if _groups else [] - groups = getGroups() - i = [group for group in groups if group.usageIn in [USAGE_INPUT, USAGE_BOTH]] - o = [group for group in groups if group.usageIn in [USAGE_OUTPUT, USAGE_BOTH]] - return i, o - - def getAllGroups(usageIn): - return [None] usageInIndex = USAGES.index(usageIn) - return [None] + tablesToGroups(getPreferredTables()[usageInIndex], usageIn=usageIn) + getGroups(0)[usageInIndex] + groups = [] + groups.extend(tablesToGroups(getPreferredTables()[usageInIndex], usageIn=usageIn)) + groups.extend(_groups.get_groups()[usageInIndex]) + return groups def getGroup( @@ -106,40 +187,65 @@ def getGroup( choices=None ): global _currentGroup - if position not in POSITIONS or usageIn not in USAGES: - return None + if choices and not isinstance(choices, TableGroups): + raise TypeError("choices: wrong type") + if position not in POSITIONS: + raise ValueError("Invalid position") + if usageIn not in USAGES: + raise ValueError("Invalid usage") usageInIndex = USAGES.index(usageIn) currentGroup = _currentGroup[usageInIndex] if not choices: - choices = getAllGroups(usageIn) - if currentGroup not in choices: + choices = getAllGroups(usageIn=usageIn) + if not choices: + return None + if not currentGroup: currentGroup = choices[0] + if currentGroup not in choices: + choices_str = "\n - ".join([str(c) for c in choices]) + log.error(f"Unable to find the current group in group list\n- currentGroup={currentGroup}\n- choices={choices_str}") + raise RuntimeError() curPos = choices.index(currentGroup) newPos = curPos if position == POSITION_PREVIOUS: newPos = curPos - 1 elif position == POSITION_NEXT: newPos = curPos + 1 - return choices[newPos % len(choices)] + newChoice = choices[newPos % len(choices)] + if not isinstance(newChoice, TableGroup): + log.error(choices) + log.error(newChoice) + raise TypeError("newChoice: wrong type") + return newChoice -def setTableOrGroup(usageIn, e, choices=None): +def setTableOrGroup( + usageIn, + e, + choices=None +): global _currentGroup + if not isinstance(e, TableGroup): + raise TypeError("e: wrong type") if not usageIn in USAGES: - return False + raise ValueError("invalid usageIn") usageInIndex = USAGES.index(usageIn) - choices = getAllGroups(usageIn) - if not e in choices: - return False + if not choices: + choices = getAllGroups(usageIn) + """if not e in choices: + log.error(f"e={e}, choices={[str(e) for e in choices]}") + return False""" _currentGroup[usageInIndex] = e return True def tablesToGroups(tables, usageIn): + if not tables: return [] + if not isinstance(tables, list): + raise ValueError("tables wrong type") groups = [] for table in tables: - groups.append(GroupTables( - ", ".join(get_file_name_by_display_name([table])), + groups.append(TableGroup(", ".join(get_file_names_by_display_names([table])), [table], usageIn )) @@ -152,7 +258,7 @@ def groupEnabled(): _groups = None _currentGroup = [None, None] - +conf = config.conf["brailleExtender"]["tables"] class SettingsDlg(gui.settingsDialogs.SettingsPanel): @@ -161,6 +267,7 @@ class SettingsDlg(gui.settingsDialogs.SettingsPanel): def makeSettings(self, settingsSizer): listPreferredTablesIndexes = getPreferredTablesIndexes() + log.info(listPreferredTablesIndexes) currentTableLabel = _("Use the current input table") sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=settingsSizer) bHelper1 = gui.guiHelper.ButtonHelper(orientation=wx.HORIZONTAL) @@ -183,8 +290,7 @@ def makeSettings(self, settingsSizer): label = _("Input braille table to use for keyboard shortcuts") try: - selectedItem = 0 if conf["shortcuts"] == '?' else listTablesFileName( - get_tables(input=True, contracted=False) + selectedItem = 0 if conf["shortcuts"] == '?' else listTablesFileName(get_tables(input=True, contracted=False) ).index(conf["shortcuts"]) + 1 except ValueError: selectedItem = 0 @@ -206,12 +312,15 @@ def makeSettings(self, settingsSizer): # Translators: label of a dialog. self.tabSpace = sHelper.addItem(wx.CheckBox( self, label=_("Display &tab signs as spaces"))) - self.tabSpace.SetValue(config.conf["brailleExtender"]["tabSpace"]) + self.tabSpace.SetValue(conf["tabSpace"]) self.tabSpace.Bind(wx.EVT_CHECKBOX, self.onTabSpace) # Translators: label of a dialog. - self.tabSize = sHelper.addLabeledControl(_("Number of &space for a tab sign")+" "+_("for the currrent braille display"), - gui.nvdaControls.SelectOnFocusSpinCtrl, min=1, max=42, initial=int(config.conf["brailleExtender"]["tabSize_%s" % addoncfg.curBD])) + label = _("Number of &space for a tab sign")+" "+_("for the currrent braille display") + self.tabSize = sHelper.addLabeledControl( + label, + gui.nvdaControls.SelectOnFocusSpinCtrl, min=1, max=42, initial=int(conf["tabSize_%s" % addoncfg.curBD]) + ) sHelper.addItem(bHelper1) self.onTabSpace() @@ -262,8 +371,8 @@ def onSave(self): conf["preferredInput"] = inputTables conf["preferredOutput"] = outputTables conf["shortcuts"] = tablesShortcuts - config.conf["brailleExtender"]["tabSpace"] = self.tabSpace.IsChecked() - config.conf["brailleExtender"][f"tabSize_{addoncfg.curBD}"] = self.tabSize.Value + conf["tabSpace"] = self.tabSpace.IsChecked() + conf[f"tabSize_{addoncfg.curBD}"] = self.tabSize.Value def postSave(self): pass #initializePreferredTables() @@ -471,7 +580,7 @@ def onOk(self, evt): self ) return self.members.SetFocus() - self.groupEntry = GroupTables(name, members, usageIn) + self.groupEntry = TableGroups(name, members, usageIn) evt.Skip() @@ -572,7 +681,7 @@ def onOk(self, event): self.isContracted.IsChecked(), path.decode("UTF-8"), displayName ) k = hashlib.md5(path).hexdigest()[:15] - config.conf["brailleExtender"]["brailleTables"][k] = v + conf["brailleTables"][k] = v super().onOk(evt) @staticmethod diff --git a/addon/globalPlugins/brailleExtender/tablehelper.py b/addon/globalPlugins/brailleExtender/tablehelper.py index 0f924e8a..3e01f173 100644 --- a/addon/globalPlugins/brailleExtender/tablehelper.py +++ b/addon/globalPlugins/brailleExtender/tablehelper.py @@ -1,9 +1,12 @@ # tablehelper.py # Part of BrailleExtender addon for NVDA -# Copyright 2016-2020 André-Abush CLAUSE, released under GPL. +# Copyright 2016-2022 André-Abush Clause, released under GPL. +import config from brailleTables import listTables from typing import List +conf = config.conf["brailleExtender"]["tables"] + def get_tables(tables=None, contracted=None, output=None, input=None): if not tables: tables = listTables() @@ -19,6 +22,8 @@ def get_tables(tables=None, contracted=None, output=None, input=None): def get_file_names(tables=None): if not tables: tables = listTables() + if not isinstance(tables, list): + raise TypeError(f"tables: wrong type. {tables}") return [table.fileName for table in tables] @@ -37,21 +42,26 @@ def get_display_names(tables=None): return [table.displayName for table in tables] -def get_indexes(l, tables): +def get_indexes(l, tables=None): if not tables: tables = listTables() - tables = get_file_names(tables) + if not l: + raise ValueError("l: empty list") return [tables.index(e) for e in l if e in tables] -def get_table_by_file_name(FileName, tables=None): +def get_table_by_file_name(fileName, tables=None): if not tables: tables = listTables() for table in tables: - if table.fileName == FileName: + if table.fileName == fileName: return table return None +def get_table_by_file_names(l, tables=None): + if not tables: + tables = listTables() + return [get_table_by_file_name(e, tables) for e in l] def get_tables_file_name_by_id(l: List[int], tables=None) -> List[int]: file_names = get_file_names(tables or listTables()) @@ -61,3 +71,25 @@ def get_tables_file_name_by_id(l: List[int], tables=None) -> List[int]: if i < size: o.append(file_names[i]) return o + + +def getPreferredTables(): + preferredTables = ( + [e for e in conf["preferredInput"].split('|') if e], + [e for e in conf["preferredOutput"].split('|') if e] + ) + return preferredTables + + +def getPreferredTablesIndexes(): + preferredInputTables, preferredOutputTables = getPreferredTables() + preferredInputTables = get_table_by_file_names(preferredInputTables) + preferredOutputTables = get_table_by_file_names(preferredOutputTables) + inputTables = get_tables(input=True) + outputTables = get_tables(output=True) + return ( + get_indexes(preferredInputTables, inputTables), + get_indexes(preferredOutputTables, outputTables) + ) + + diff --git a/addon/globalPlugins/brailleExtender/undefinedchars.py b/addon/globalPlugins/brailleExtender/undefinedchars.py index abdadc62..19f81a1b 100644 --- a/addon/globalPlugins/brailleExtender/undefinedchars.py +++ b/addon/globalPlugins/brailleExtender/undefinedchars.py @@ -76,8 +76,7 @@ def setUndefinedChar(t=None): t = config.conf["brailleExtender"]["undefinedCharsRepr"]["method"] if t == 0: return - louis.compileString(getCurrentBrailleTables(), bytes( - f"undefined {HUCDotPattern}", "ASCII")) + louis.compileString(getCurrentBrailleTables(), f"undefined {HUCDotPattern}") def getExtendedSymbolsForString(s: str, lang) -> dict: diff --git a/addon/globalPlugins/brailleExtender/utils.py b/addon/globalPlugins/brailleExtender/utils.py index a5695f57..5096e863 100644 --- a/addon/globalPlugins/brailleExtender/utils.py +++ b/addon/globalPlugins/brailleExtender/utils.py @@ -309,21 +309,33 @@ def getCharFromValue(s): return chr(n) def getCurrentBrailleTables(input_=False, brf=False): + tables = [] if brf: - tables = [ - os.path.join(baseDir, "res", "brf.ctb").encode("UTF-8"), - os.path.join(brailleTables.TABLES_DIR, "braille-patterns.cti") - ] + tables.append( + os.path.join(baseDir, "res", "brf.ctb").encode("UTF-8") + ) else: - tables = [] app = appModuleHandler.getAppModuleForNVDAObject(api.getNavigatorObject()) if app and app.appName != "nvda": tables += tabledictionaries.dictTables - if input_: mainTable = os.path.join(brailleTables.TABLES_DIR, brailleInput.handler._table.fileName) - else: mainTable = os.path.join(brailleTables.TABLES_DIR, config.conf["braille"]["translationTable"]) - tables += [ - mainTable, - os.path.join(brailleTables.TABLES_DIR, "braille-patterns.cti") - ] + if input_: + groupTable = tablegroups._currentGroup[0] + if groupTable: + tables.extend(groupTable.get_tables()) + else: + tables.append( + os.path.join(brailleTables.TABLES_DIR, brailleInput.handler._table.fileName) + ) + else: + groupTable = tablegroups._currentGroup[1] + if groupTable: + tables.extend(groupTable.get_tables()) + else: + tables.append( + os.path.join(brailleTables.TABLES_DIR, config.conf["braille"]["translationTable"]) + ) + tables.append( + os.path.join(brailleTables.TABLES_DIR, "braille-patterns.cti") + ) return tables