Skip to content

Commit b5bed1d

Browse files
committed
Updated, refactored code
1 parent 4f5887b commit b5bed1d

1 file changed

Lines changed: 66 additions & 150 deletions

File tree

Lines changed: 66 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,23 @@
11
# -*- coding: UTF-8 -*-
22
# NumberProcessing
33
# A global plugin for NVDA
4-
# Copyright 2019 Alberto Buffolino, released under GPL
4+
# Copyright Alberto Buffolino, released under GPL
55
# Add-on to read digit by digit any number of specified length
66
# from an experimental idea of Derek Riemer
7-
from gui import guiHelper, nvdaControls
8-
from logHandler import log
9-
from scriptHandler import getLastScriptRepeatCount
10-
from versionInfo import version_year, version_major
117
import addonHandler
128
import config
139
import globalPluginHandler
1410
import globalVars
1511
import gui
16-
import os
1712
import re
18-
import speechDictHandler
13+
import speech
1914
import ui
2015
import wx
21-
try:
22-
from globalCommands import SCRCAT_SPEECH
23-
except:
24-
SCRCAT_SPEECH = None
2516

26-
addonDir = os.path.join(os.path.dirname(__file__), "..")
27-
if isinstance(addonDir, bytes):
28-
addonDir = addonDir.decode("mbcs")
29-
curAddon = addonHandler.Addon(addonDir)
30-
addonSummary = curAddon.manifest['summary']
17+
from enum import Enum
18+
from gui import guiHelper, nvdaControls, settingsDialogs
19+
from scriptHandler import script, getLastScriptRepeatCount
20+
3121

3222
addonHandler.initTranslation()
3323

@@ -43,81 +33,68 @@
4333
)
4434
confspec = {
4535
"autoEnable": "boolean(default=false)",
46-
"prevEnabled": "boolean(default=false)",
4736
"userMinLen": "integer(default=2)",
4837
}
4938
config.conf.spec["numberProcessing"] = confspec
50-
backupProcessText = speechDictHandler.processText
51-
visitedProfiles = set()
52-
globalEnabled = False
53-
nvdaVersion = '.'.join([str(version_year), str(version_major)])
54-
lastProfile = None
39+
profileStatus = {}
5540

56-
def compileExps():
57-
exp1 = re.compile(r'\d{%s,}'%userMinLen)
58-
symbols = ''.join(CURRENCY_SYMBOLS)
59-
exp2 = re.compile(r'([%s])?\s*([\d,.]+)'%symbols)
60-
return (exp1, exp2,)
41+
class Status(Enum):
42+
43+
DISABLED = 0
44+
AUTO_ENABLED = 1
45+
MANUAL_ENABLED = 2
6146

6247
# (re)load config
6348
def loadConfig():
64-
global myConf, autoEnable, prevEnabled, userMinLen, exp1, exp2
49+
global myConf, exp1, exp2, curProfile
6550
myConf = config.conf["numberProcessing"]
6651
autoEnable = myConf["autoEnable"]
67-
prevEnabled = myConf["prevEnabled"]
6852
userMinLen = myConf["userMinLen"]
69-
exp1, exp2 = compileExps()
53+
exp1 = re.compile(r'\d{%s,}'%userMinLen)
54+
symbols = ''.join(CURRENCY_SYMBOLS)
55+
exp2 = re.compile(r'([%s])?\s*([\d,.]+)'%symbols)
56+
curProfile = config.conf.profiles[-1].name
57+
# adjust status for current profile
58+
if autoEnable:
59+
profileStatus[curProfile] = Status.AUTO_ENABLED
60+
# adjust after disabling auto enable in settings
61+
elif profileStatus.get(curProfile, Status.DISABLED) == Status.AUTO_ENABLED:
62+
profileStatus[curProfile] = Status.DISABLED
7063

7164
loadConfig()
7265

66+
def filter_numberProcessing(speechSequence):
67+
if not isEnabled():
68+
return speechSequence
69+
newSpeechSequence = []
70+
for item in speechSequence:
71+
if not isinstance(item, str):
72+
newSpeechSequence.append(item)
73+
continue
74+
# pre-process to avoid problems with decimal separator,
75+
# appending currency sign to the end of the amount
76+
item = exp2.sub(r'\2\1', item)
77+
# add whitespace around digits
78+
item = exp1.sub(replaceFunc, item)
79+
newSpeechSequence.append(item)
80+
return newSpeechSequence
81+
82+
def isEnabled():
83+
status = profileStatus.get(curProfile, Status.DISABLED)
84+
return bool(status.value)
85+
7386
def replaceFunc(match):
7487
# group(0) returns digits captured by match
7588
fixedText = ' '.join(list(match.group(0)))
7689
return fixedText
7790

78-
def newProcessText(text):
79-
# pre-process to avoid problems with decimal separator,
80-
# appending currency sign to the end of the amount
81-
text = exp2.sub(r'\2\1', text)
82-
# get spoken version
83-
text = backupProcessText(text)
84-
# add whitespace around digits
85-
text = exp1.sub(replaceFunc, text)
86-
return text
87-
88-
def enableProcessing():
89-
global prevEnabled, myConf, globalEnabled
90-
speechDictHandler.processText = newProcessText
91-
if autoEnable:
92-
prevEnabled = myConf["prevEnabled"] = True
93-
else:
94-
globalEnabled = True
95-
96-
def disableProcessing():
97-
global prevEnabled, myConf, globalEnabled
98-
speechDictHandler.processText = backupProcessText
99-
if autoEnable:
100-
prevEnabled = myConf["prevEnabled"] = False
101-
else:
102-
globalEnabled = False
103-
104-
# for settings presentation compatibility
105-
if hasattr(gui.settingsDialogs, "SettingsPanel"):
106-
superDialogClass = gui.settingsDialogs.SettingsPanel
107-
else:
108-
superDialogClass = gui.SettingsDialog
10991

110-
class NumberProcessingSettingsDialog(superDialogClass):
111-
"""Class to define settings dialog."""
92+
class NumberProcessingSettings(settingsDialogs.SettingsPanel):
93+
"""Class to define settings."""
11294

113-
if hasattr(gui.settingsDialogs, "SettingsPanel"):
114-
# Translators: title of settings dialog
115-
title = _("Number Processing")
116-
else:
117-
# Translators: title of settings dialog
118-
title = _("Number Processing Settings")
95+
# Translators: title of settings dialog
96+
title = _("Number Processing")
11997

120-
# common to dialog and panel
12198
def makeSettings(self, settingsSizer):
12299
loadConfig()
123100
settingsSizerHelper = guiHelper.BoxSizerHelper(self, sizer=settingsSizer)
@@ -133,34 +110,13 @@ def makeSettings(self, settingsSizer):
133110
min=2,
134111
initial=myConf["userMinLen"])
135112

136-
# for dialog only
137-
def postInit(self):
138-
self.autoEnableCheckBox.SetFocus()
139-
140-
# shared between onOk and onSave
141-
def saveConfig(self):
113+
def onSave(self):
142114
# Update Configuration
143-
prevAutoEnable = myConf["autoEnable"]
144115
myConf["autoEnable"] = self.autoEnableCheckBox.IsChecked()
145116
myConf["userMinLen"] = self.userMinLenEdit.GetValue()
146-
# update global variables
117+
# reload new config
147118
loadConfig()
148-
if autoEnable:
149-
#log.info("autoEnable after configuration")
150-
enableProcessing()
151-
elif prevAutoEnable and prevEnabled:
152-
#log.info("Fix status to avoid manual enabled at first script invocation")
153-
global globalEnabled
154-
globalEnabled = True
155119

156-
# for dialog only
157-
def onOk(self, evt):
158-
self.saveConfig()
159-
super(NumberProcessingSettingsDialog, self).onOk(evt)
160-
161-
# for panel only
162-
def onSave(self):
163-
self.saveConfig()
164120

165121
class QuickSettingsDialog(wx.Dialog):
166122

@@ -185,98 +141,58 @@ def __init__(self, parent, profileName):
185141
def onOk(self, evt):
186142
# Update Configuration
187143
myConf["userMinLen"] = self.userMinLenEdit.GetValue()
188-
# update global variables
144+
# reload new config
189145
loadConfig()
190146
self.Destroy()
191147

192148
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
193149

194-
scriptCategory = addonSummary
150+
scriptCategory = addonHandler.getCodeAddon().manifest["summary"]
195151

196152
def __init__(self, *args, **kwargs):
197153
super(GlobalPlugin, self).__init__(*args, **kwargs)
198154
if globalVars.appArgs.secure:
199155
return
200156
self.createMenu()
201157
loadConfig()
202-
if hasattr(config, "post_configProfileSwitch"):
203-
config.post_configProfileSwitch.register(self.handleConfigProfileSwitch)
204-
if autoEnable:
205-
#log.info("autoEnable at start")
206-
enableProcessing()
158+
config.post_configProfileSwitch.register(self.handleConfigProfileSwitch)
159+
speech.extensions.filter_speechSequence.register(filter_numberProcessing)
207160

208161
def createMenu(self):
209-
# Dialog or the panel.
210-
if hasattr(gui.settingsDialogs, "SettingsPanel"):
211-
gui.settingsDialogs.NVDASettingsDialog.categoryClasses.append(NumberProcessingSettingsDialog)
212-
else:
213-
self.prefsMenu = gui.mainFrame.sysTrayIcon.menu.GetMenuItems()[0].GetSubMenu()
214-
# Translators: menu item in preferences
215-
self.NumberProcessingItem = self.prefsMenu.Append(wx.ID_ANY, _("Number Processing Settings..."), "")
216-
gui.mainFrame.sysTrayIcon.Bind(wx.EVT_MENU, lambda e: gui.mainFrame._popupSettingsDialog(NumberProcessingSettingsDialog), self.NumberProcessingItem)
162+
gui.settingsDialogs.NVDASettingsDialog.categoryClasses.append(NumberProcessingSettings)
217163

218164
def terminate(self):
219-
if hasattr(gui.settingsDialogs, "SettingsPanel"):
220-
gui.settingsDialogs.NVDASettingsDialog.categoryClasses.remove(NumberProcessingSettingsDialog)
221-
else:
222-
try:
223-
self.prefsMenu.RemoveItem(self.NumberProcessingItem)
224-
except wx.PyDeadObjectError:
225-
pass
226-
loadConfig()
227-
disableProcessing()
228-
165+
profileStatus.clear()
166+
gui.settingsDialogs.NVDASettingsDialog.categoryClasses.remove(NumberProcessingSettings)
167+
168+
@script(
169+
# Translators: Message presented in input help mode.
170+
description=_("Pressed once, enables/disables digit processing; twice, launches quick settings"),
171+
gesture="kb:nvda+shift+l"
172+
)
229173
def script_toggleDigitManager(self, gesture, repeating=False):
230174
if getLastScriptRepeatCount() and not repeating:
231175
self.launchQuickSettings()
232176
self.script_toggleDigitManager(None, repeating=True)
233177
return
234178
loadConfig()
235-
if (autoEnable and not prevEnabled) or (not autoEnable and not globalEnabled):
236-
#log.info("manual enabled")
237-
enableProcessing()
179+
if not isEnabled():
180+
profileStatus[curProfile] = Status.MANUAL_ENABLED
238181
message = _("Digit processing on")
239182
else:
240-
#log.info("manual disabled")
241-
disableProcessing()
183+
profileStatus[curProfile] = Status.DISABLED
242184
message = _("Digit processing off")
243185
if not repeating:
244186
ui.message(message)
245187

246-
script_toggleDigitManager.__doc__ = _("Pressed once, enables/disables digit processing; twice, launches quick settings")
247-
248188
def launchQuickSettings(self):
249189
def run():
250190
gui.mainFrame.prePopup()
251-
d = QuickSettingsDialog(None, config.conf.profiles[-1].name)
191+
d = QuickSettingsDialog(None, curProfile)
252192
if d:
253193
d.Show()
254194
gui.mainFrame.postPopup()
255195
wx.CallAfter(run)
256196

257197
def handleConfigProfileSwitch(self):
258-
global curProfile
259198
loadConfig()
260-
profileName = config.conf.profiles[-1].name
261-
lastProfile = profileName
262-
if autoEnable and profileName not in visitedProfiles:
263-
visitedProfiles.add(profileName)
264-
#log.info("autoEnable in %s for first time"%profileName)
265-
enableProcessing()
266-
elif (autoEnable and prevEnabled) or (not autoEnable and globalEnabled):
267-
#log.info("enable after changing profile")
268-
enableProcessing()
269-
else:
270-
#log.info("disable after changing profile")
271-
disableProcessing()
272-
273-
def event_foreground(self, obj, nextHandler):
274-
if nvdaVersion < '2018.3':
275-
curProfile = config.conf.profiles[-1].name
276-
if lastProfile != curProfile:
277-
self.handleConfigProfileSwitch()
278-
nextHandler()
279-
280-
__gestures = {
281-
"kb:NVDA+shift+l": "toggleDigitManager"
282-
}

0 commit comments

Comments
 (0)