Skip to content

Commit d1662c5

Browse files
authored
Merge ab2b985 into dd645d6
2 parents dd645d6 + ab2b985 commit d1662c5

9 files changed

Lines changed: 104 additions & 48 deletions

File tree

source/_addonStore/models/status.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -255,22 +255,39 @@ class _StatusFilterKey(DisplayStringEnum):
255255

256256
@property
257257
def _displayStringLabels(self) -> Dict["_StatusFilterKey", str]:
258-
return {k: v.replace('&', '') for (k, v) in self._displayStringLabelsWithAccelerators.items()}
258+
return {
259+
# Translators: The label of a tab to display installed add-ons in the add-on store.
260+
# Ensure the translation matches the label for the add-on list which includes an accelerator key.
261+
self.INSTALLED: pgettext("addonStore", "Installed add-ons"),
262+
# Translators: The label of a tab to display updatable add-ons in the add-on store.
263+
# Ensure the translation matches the label for the add-on list which includes an accelerator key.
264+
self.UPDATE: pgettext("addonStore", "Updatable add-ons"),
265+
# Translators: The label of a tab to display available add-ons in the add-on store.
266+
# Ensure the translation matches the label for the add-on list which includes an accelerator key.
267+
self.AVAILABLE: pgettext("addonStore", "Available add-ons"),
268+
# Translators: The label of a tab to display incompatible add-ons in the add-on store.
269+
# Ensure the translation matches the label for the add-on list which includes an accelerator key.
270+
self.INCOMPATIBLE: pgettext("addonStore", "Installed incompatible add-ons"),
271+
}
259272

260273
@property
261274
def _displayStringLabelsWithAccelerators(self) -> Dict["_StatusFilterKey", str]:
262275
return {
263-
# Translators: The label of a tab to display installed add-ons in the add-on store and the label of the
264-
# add-ons list in the corresponding panel (preferably use the same accelerator key for the four labels)
276+
# Translators: The label of the add-ons list in the corresponding panel.
277+
# Preferably use the same accelerator key for the four labels.
278+
# Ensure the translation matches the label for the add-on tab which has the accelerator key removed.
265279
self.INSTALLED: pgettext("addonStore", "Installed &add-ons"),
266-
# Translators: The label of a tab to display updatable add-ons in the add-on store and the label of the
267-
# add-ons list in the corresponding panel (preferably use the same accelerator key for the four labels)
280+
# Translators: The label of the add-ons list in the corresponding panel.
281+
# Preferably use the same accelerator key for the four labels.
282+
# Ensure the translation matches the label for the add-on tab which has the accelerator key removed.
268283
self.UPDATE: pgettext("addonStore", "Updatable &add-ons"),
269-
# Translators: The label of a tab to display available add-ons in the add-on store and the label of the
270-
# add-ons list in the corresponding panel (preferably use the same accelerator key for the four labels)
284+
# Translators: The label of the add-ons list in the corresponding panel.
285+
# Preferably use the same accelerator key for the four labels.
286+
# Ensure the translation matches the label for the add-on tab which has the accelerator key removed.
271287
self.AVAILABLE: pgettext("addonStore", "Available &add-ons"),
272-
# Translators: The label of a tab to display incompatible add-ons in the add-on store and the label of the
273-
# add-ons list in the corresponding panel (preferably use the same accelerator key for the four labels)
288+
# Translators: The label of the add-ons list in the corresponding panel.
289+
# Preferably use the same accelerator key for the four labels.
290+
# Ensure the translation matches the label for the add-on tab which has the accelerator key removed.
274291
self.INCOMPATIBLE: pgettext("addonStore", "Installed incompatible &add-ons"),
275292
}
276293

source/gui/_addonStoreGui/controls/messageDialogs.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
ButtonHelper,
2525
SPACE_BETWEEN_VERTICAL_DIALOG_ITEMS,
2626
)
27-
from gui.message import messageBox
27+
from gui.message import displayDialogAsModal, messageBox
2828
import windowUtils
2929

3030
if TYPE_CHECKING:
@@ -81,13 +81,14 @@ def _shouldProceedWhenInstalledAddonVersionUnknown(
8181
lastTestedNVDAVersion=addonAPIVersion.formatForGUI(addon.lastTestedNVDAVersion),
8282
NVDAVersion=addonAPIVersion.formatForGUI(addonAPIVersion.CURRENT)
8383
)
84-
return ErrorAddonInstallDialogWithYesNoButtons(
84+
res = displayDialogAsModal(ErrorAddonInstallDialogWithYesNoButtons(
8585
parent=parent,
8686
# Translators: The title of a dialog presented when an error occurs.
8787
title=pgettext("addonStore", "Add-on not compatible"),
8888
message=incompatibleMessage,
8989
showAddonInfoFunction=lambda: _showAddonInfo(addon)
90-
).ShowModal() == wx.YES
90+
))
91+
return res == wx.YES
9192

9293

9394
def _shouldProceedToRemoveAddonDialog(
@@ -127,13 +128,14 @@ def _shouldInstallWhenAddonTooOldDialog(
127128
lastTestedNVDAVersion=addonAPIVersion.formatForGUI(addon.lastTestedNVDAVersion),
128129
NVDAVersion=addonAPIVersion.formatForGUI(addonAPIVersion.CURRENT)
129130
)
130-
return ErrorAddonInstallDialogWithYesNoButtons(
131+
res = displayDialogAsModal(ErrorAddonInstallDialogWithYesNoButtons(
131132
parent=parent,
132133
# Translators: The title of a dialog presented when an error occurs.
133134
title=pgettext("addonStore", "Add-on not compatible"),
134135
message=incompatibleMessage,
135136
showAddonInfoFunction=lambda: _showAddonInfo(addon)
136-
).ShowModal() == wx.YES
137+
))
138+
return res == wx.YES
137139

138140

139141
def _shouldEnableWhenAddonTooOldDialog(
@@ -156,13 +158,14 @@ def _shouldEnableWhenAddonTooOldDialog(
156158
lastTestedNVDAVersion=addonAPIVersion.formatForGUI(addon.lastTestedNVDAVersion),
157159
NVDAVersion=addonAPIVersion.formatForGUI(addonAPIVersion.CURRENT)
158160
)
159-
return ErrorAddonInstallDialogWithYesNoButtons(
161+
res = displayDialogAsModal(ErrorAddonInstallDialogWithYesNoButtons(
160162
parent=parent,
161163
# Translators: The title of a dialog presented when an error occurs.
162164
title=pgettext("addonStore", "Add-on not compatible"),
163165
message=incompatibleMessage,
164166
showAddonInfoFunction=lambda: _showAddonInfo(addon)
165-
).ShowModal() == wx.YES
167+
))
168+
return res == wx.YES
166169

167170

168171
def _showAddonInfo(addon: _AddonGUIModel) -> None:

source/gui/_addonStoreGui/controls/storeDialog.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
guiHelper,
2929
addonGui,
3030
)
31-
from gui.message import DisplayableError
31+
from gui.message import DisplayableError, displayDialogAsModal
3232
from gui.settingsDialogs import SettingsDialog
3333
from logHandler import log
3434

@@ -53,7 +53,7 @@ def __init__(self, parent: wx.Window, storeVM: AddonStoreVM):
5353
self._actionsContextMenu = _ActionsContextMenu(self._storeVM)
5454
super().__init__(parent, resizeable=True, buttons={wx.CLOSE})
5555
if config.conf["addonStore"]["showWarning"]:
56-
_SafetyWarningDialog(parent).ShowModal()
56+
displayDialogAsModal(_SafetyWarningDialog(parent))
5757
self.Maximize()
5858

5959
def _enterActivatesOk_ctrlSActivatesApply(self, evt: wx.KeyEvent):
@@ -367,7 +367,7 @@ def openExternalInstall(self, evt: wx.EVT_BUTTON):
367367
defaultDir="c:",
368368
style=wx.FD_OPEN,
369369
)
370-
if fd.ShowModal() != wx.ID_OK:
370+
if displayDialogAsModal(fd) != wx.ID_OK:
371371
return
372372
addonPath = fd.GetPath()
373373
try:

source/gui/addonGui.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import globalVars
2424
from . import guiHelper
2525
from . import nvdaControls
26+
from .message import displayDialogAsModal
2627
from .dpiScalingHelper import DpiScalingHelperMixinWithoutInit
2728
import gui.contextHelp
2829

@@ -269,7 +270,7 @@ def onAddClick(self, evt: wx.EVT_BUTTON):
269270
# Translators: the label for the NVDA add-on package file type in the Choose add-on dialog.
270271
wildcard=(_("NVDA Add-on Package (*.{ext})")+"|*.{ext}").format(ext=addonHandler.BUNDLE_EXTENSION),
271272
defaultDir="c:", style=wx.FD_OPEN)
272-
if fd.ShowModal() != wx.ID_OK:
273+
if displayDialogAsModal(fd) != wx.ID_OK:
273274
return
274275
addonPath = fd.GetPath()
275276
if installAddon(self, addonPath):
@@ -446,10 +447,10 @@ def onGetAddonsClick(self, evt):
446447
os.startfile(ADDONS_URL)
447448

448449
def onIncompatAddonsShowClick(self, evt):
449-
IncompatibleAddonsDialog(
450+
displayDialogAsModal(IncompatibleAddonsDialog(
450451
parent=self,
451452
# the defaults from the addon GUI are fine. We are testing against the running version.
452-
).ShowModal()
453+
))
453454

454455

455456
# C901 'installAddon' is too complex (16)
@@ -601,13 +602,13 @@ def _showAddonRequiresNVDAUpdateDialog(
601602
NVDAVersion=addonAPIVersion.formatForGUI(addonAPIVersion.CURRENT)
602603
)
603604
from gui._addonStoreGui.controls.messageDialogs import _showAddonInfo
604-
ErrorAddonInstallDialog(
605+
displayDialogAsModal(ErrorAddonInstallDialog(
605606
parent=parent,
606607
# Translators: The title of a dialog presented when an error occurs.
607608
title=_("Add-on not compatible"),
608609
message=incompatibleMessage,
609610
showAddonInfoFunction=lambda: _showAddonInfo(bundle._addonGuiModel)
610-
).ShowModal()
611+
))
611612

612613

613614
def _showConfirmAddonInstallDialog(
@@ -622,13 +623,13 @@ def _showConfirmAddonInstallDialog(
622623
).format(**bundle.manifest)
623624

624625
from gui._addonStoreGui.controls.messageDialogs import _showAddonInfo
625-
return ConfirmAddonInstallDialog(
626+
return displayDialogAsModal(ConfirmAddonInstallDialog(
626627
parent=parent,
627628
# Translators: Title for message asking if the user really wishes to install an Addon.
628629
title=_("Add-on Installation"),
629630
message=confirmInstallMessage,
630631
showAddonInfoFunction=lambda: _showAddonInfo(bundle._addonGuiModel)
631-
).ShowModal()
632+
))
632633

633634

634635
class IncompatibleAddonsDialog(

source/gui/exit.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2006-2022 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Mesar Hameed, Joseph Lee,
2+
# Copyright (C) 2006-2023 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Mesar Hameed, Joseph Lee,
33
# Thomas Stivers, Babbage B.V., Accessolutions, Julien Cochuyt, Cyrille Bougot
44
# This file may be used under the terms of the GNU General Public License, version 2 or later.
55
# For more details see: https://www.gnu.org/licenses/gpl-2.0.html
@@ -18,6 +18,7 @@
1818
import wx
1919

2020
from . import guiHelper
21+
from .message import displayDialogAsModal
2122
from .startupDialogs import WelcomeDialog
2223

2324

@@ -150,7 +151,7 @@ def onOk(self, evt):
150151
apiVersion=apiVersion,
151152
backCompatTo=backCompatTo
152153
)
153-
confirmUpdateDialog.ShowModal()
154+
displayDialogAsModal(confirmUpdateDialog)
154155
else:
155156
updateCheck.executePendingUpdate()
156157
wx.CallAfter(self.Destroy)

source/gui/installerGui.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import os
88

9-
import shellapi
109
import winUser
1110
import wx
1211
import config
@@ -20,6 +19,7 @@
2019
from gui.dpiScalingHelper import DpiScalingHelperMixinWithoutInit
2120
import systemUtils
2221
from NVDAState import WritePaths
22+
from .message import displayDialogAsModal
2323

2424

2525
def _canPortableConfigBeCopied() -> bool:
@@ -274,7 +274,7 @@ def onReviewAddons(self, evt):
274274
parent=self,
275275
# the defaults from the installer are fine. We are testing against the running version.
276276
)
277-
incompatibleAddons.ShowModal()
277+
displayDialogAsModal(incompatibleAddons)
278278

279279

280280
class InstallingOverNewerVersionDialog(

source/gui/message.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,39 @@ def isModalMessageBoxActive() -> bool:
3636
return _messageBoxCounter != 0
3737

3838

39+
def displayDialogAsModal(dialog: wx.Dialog) -> int:
40+
"""Display a dialog as modal.
41+
@return: Same as for wx.MessageBox.
42+
43+
`displayDialogAsModal` is a function which blocks the calling thread,
44+
until a user responds to the modal dialog.
45+
This function should be used when an answer is required before proceeding.
46+
47+
It's possible for multiple message boxes to be open at a time.
48+
Before opening a new messageBox, use `isModalMessageBoxActive`
49+
to check if another messageBox modal response is still pending.
50+
51+
Because an answer is required to continue after a modal messageBox is opened,
52+
some actions such as shutting down are prevented while NVDA is in a possibly uncertain state.
53+
"""
54+
from gui import mainFrame
55+
global _messageBoxCounter
56+
with _messageBoxCounterLock:
57+
_messageBoxCounter += 1
58+
59+
try:
60+
if not dialog.GetParent():
61+
mainFrame.prePopup()
62+
res = dialog.ShowModal()
63+
finally:
64+
if not dialog.GetParent():
65+
mainFrame.postPopup()
66+
with _messageBoxCounterLock:
67+
_messageBoxCounter -= 1
68+
69+
return res
70+
71+
3972
def messageBox(
4073
message: str,
4174
caption: str = wx.MessageBoxCaptionStr,

source/updateCheck.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import braille
4949
import gui
5050
from gui import guiHelper
51+
from gui.message import displayDialogAsModal # noqa: E402
5152
from addonHandler import getCodeAddon, AddonError, getIncompatibleAddons
5253
from _addonStore.models.version import ( # noqa: E402
5354
getAddonCompatibilityMessage,
@@ -464,7 +465,7 @@ def onReviewAddonsButton(self, evt):
464465
APIVersion=self.apiVersion,
465466
APIBackwardsCompatToVersion=self.backCompatTo
466467
)
467-
incompatibleAddons.ShowModal()
468+
displayDialogAsModal(incompatibleAddons)
468469

469470

470471
class UpdateAskInstallDialog(
@@ -540,7 +541,7 @@ def onReviewAddonsButton(self, evt):
540541
APIVersion=self.apiVersion,
541542
APIBackwardsCompatToVersion=self.backCompatTo
542543
)
543-
incompatibleAddons.ShowModal()
544+
displayDialogAsModal(incompatibleAddons)
544545

545546
def onInstallButton(self, evt):
546547
_executeUpdate(self.destPath)

user_docs/en/userGuide.t2t

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ You can then move past the list if you wish to access other objects.
597597
Similarly, a toolbar contains controls, so you must move inside the toolbar to access the controls in the toolbar.
598598

599599
If you yet prefer to move back and forth between every single object on the system, you can use commands to move to the previous/next object in a flattened view.
600-
For example, if you move to the next object in this flattened view and the current object contains other objects, NVDA will automatically move to the first object that contains it.
600+
For example, if you move to the next object in this flattened view and the current object contains other objects, NVDA will automatically move to the first object that it contains.
601601
Alternatively, if the current object doesn't contain any objects, NVDA will move to the next object at the current level of the hierarchy.
602602
If there is no such next object, NVDA will try to find the next object in the hierarchy based on containing objects until there are no more objects to move to.
603603
The same rules apply to moving backwards in the hierarchy.
@@ -2236,6 +2236,14 @@ This setting contains the following values:
22362236
- Always: where ever UI automation is available in Microsoft word (no matter how complete).
22372237
-
22382238

2239+
==== Use UI automation to access Microsoft Excel spreadsheet controls when available ====[UseUiaForExcel]
2240+
When this option is enabled, NVDA will try to use the Microsoft UI Automation accessibility API in order to fetch information from Microsoft Excel Spreadsheet controls.
2241+
This is an experimental feature, and some features of Microsoft Excel may not be available in this mode.
2242+
For instance, NVDA's Elements List for listing formulas and comments, and Browse mode quick navigation to jump to form fields on a spreadsheet features are not available.
2243+
However, for basic spreadsheet navigating / editing, this option may provide a vast performance improvement.
2244+
We still do not recommend that the majority of users turn this on by default, though we do welcome users of Microsoft Excel build 16.0.13522.10000 or higher to test this feature and provide feedback.
2245+
Microsoft Excel's UI automation implementation is ever changing, and versions of Microsoft Office older than 16.0.13522.10000 may not expose enough information for this option to be of any use.
2246+
22392247
==== Windows Console support ====[AdvancedSettingsConsoleUIA]
22402248
: Default
22412249
Automatic
@@ -2288,14 +2296,6 @@ The following options exist:
22882296
-
22892297
-
22902298

2291-
==== Use UI automation to access Microsoft Excel spreadsheet controls when available ====[UseUiaForExcel]
2292-
When this option is enabled, NVDA will try to use the Microsoft UI Automation accessibility API in order to fetch information from Microsoft Excel Spreadsheet controls.
2293-
This is an experimental feature, and some features of Microsoft Excel may not be available in this mode.
2294-
For instance, NVDA's Elements List for listing formulas and comments, and Browse mode quick navigation to jump to form fields on a spreadsheet features are not available.
2295-
However, for basic spreadsheet navigating / editing, this option may provide a vast performance improvement.
2296-
We still do not recommend that the majority of users turn this on by default, though we do welcome users of Microsoft Excel build 16.0.13522.10000 or higher to test this feature and provide feedback.
2297-
Microsoft Excel's UI automation implementation is ever changing, and versions of Microsoft Office older than 16.0.13522.10000 may not expose enough information for this option to be of any use.
2298-
22992299
==== Report live regions ====[BrailleLiveRegions]
23002300
: Default
23012301
Enabled
@@ -2682,7 +2682,7 @@ To list add-ons only for specific channels, change the "Channel" filter selectio
26822682
+++ Searching for add-ons +++[AddonStoreFilterSearch]
26832683
To search add-ons, use the "Search" text box.
26842684
You can reach it by pressing ``shift+tab`` from the list of add-ons.
2685-
Type a keyword or two for the kind of add-on you're looking for, then ``tab`` back to the list of add-ons.
2685+
Type a keyword or two for the kind of add-on you're looking for, then ``tab`` to the list of add-ons.
26862686
Add-ons will be listed if the search text can be found in the add-on ID, display name, publisher, author or description.
26872687

26882688
++ Add-on actions ++[AddonStoreActions]
@@ -2691,7 +2691,7 @@ For an add-on in the add-on list, these actions can be accessed through a menu o
26912691
This menu can also be accessed through an Actions button in the selected add-on's details.
26922692

26932693
+++ Installing add-ons +++[AddonStoreInstalling]
2694-
Just because an add-on is available in the NVDA Add-ons Store, does not mean that it has been approved or vetted by NV Access or anyone else.
2694+
Just because an add-on is available in the NVDA Add-on Store, does not mean that it has been approved or vetted by NV Access or anyone else.
26952695
It is very important to only install add-ons from sources you trust.
26962696
The functionality of add-ons is unrestricted inside NVDA.
26972697
This could include accessing your personal data or even the entire system.
@@ -3112,12 +3112,12 @@ Please see your display's documentation for descriptions of where these keys can
31123112
| Route to braille cell | ``routing`` |
31133113
| ``shift+tab`` key | ``space+dot1+dot3`` |
31143114
| ``tab`` key | ``space+dot4+dot6`` |
3115-
| ``alt`` key | ``space+dot1+dot3+dot4 (space+m)`` |
3116-
| ``escape`` key | ``space+dot1+dot5 (space+e)`` |
3115+
| ``alt`` key | ``space+dot1+dot3+dot4`` (``space+m``) |
3116+
| ``escape`` key | ``space+dot1+dot5`` (``space+e``) |
31173117
| ``windows`` key | ``space+dot3+dot4`` |
3118-
| ``alt+tab`` key | ``space+dot2+dot3+dot4+dot5 (space+t)`` |
3119-
| NVDA Menu | ``space+dot1+dot3+dot4+dot5 (space+n)`` |
3120-
| ``windows+d`` key (minimize all applications) | ``space+dot1+dot4+dot5 (space+d)`` |
3118+
| ``alt+tab`` key | ``space+dot2+dot3+dot4+dot5`` (``space+t``) |
3119+
| NVDA Menu | ``space+dot1+dot3+dot4+dot5`` (``space+n``) |
3120+
| ``windows+d`` key (minimize all applications) | ``space+dot1+dot4+dot5`` (``space+d``) |
31213121
| Say all | ``space+dot1+dot2+dot3+dot4+dot5+dot6`` |
31223122

31233123
For displays which have a joystick:

0 commit comments

Comments
 (0)