Skip to content

Commit bd9f0f3

Browse files
authored
Merge 68e62cb into 4b74c7b
2 parents 4b74c7b + 68e62cb commit bd9f0f3

File tree

7 files changed

+188
-149
lines changed

7 files changed

+188
-149
lines changed

source/core.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
# -*- coding: UTF-8 -*-
21
# A part of NonVisual Desktop Access (NVDA)
3-
# Copyright (C) 2006-2019 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner,
2+
# Copyright (C) 2006-2021 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner,
43
# Derek Riemer, Babbage B.V., Zahari Yurukov, Łukasz Golonka
54
# This file is covered by the GNU General Public License.
65
# See the file COPYING for more details.
76

7+
from typing import Optional, TYPE_CHECKING
8+
if TYPE_CHECKING:
9+
import wx
10+
811
"""NVDA core"""
912

1013
RPC_E_CALL_CANCELED = -2147418110
@@ -207,6 +210,27 @@ def _setInitialFocus():
207210
except:
208211
log.exception("Error retrieving initial focus")
209212

213+
214+
def getWxLangOrNone() -> Optional[wx.LanguageInfo]:
215+
import languageHandler
216+
import wx
217+
lang = languageHandler.getLanguage()
218+
locale = wx.Locale()
219+
wxLang = locale.FindLanguageInfo(lang)
220+
if not wxLang and '_' in lang:
221+
wxLang = locale.FindLanguageInfo(lang.split('_')[0])
222+
# #8064: Wx might know the language, but may not actually contain a translation database for that language.
223+
# If we try to initialize this language, wx will show a warning dialog.
224+
# #9089: some languages (such as Aragonese) do not have language info, causing language getter to fail.
225+
# In this case, wxLang is already set to None.
226+
# Therefore treat these situations like wx not knowing the language at all.
227+
if wxLang and not locale.IsAvailable(wxLang.Language):
228+
wxLang = None
229+
if not wxLang:
230+
log.debugWarning("wx does not support language %s" % lang)
231+
return wxLang
232+
233+
210234
def main():
211235
"""NVDA's core main loop.
212236
This initializes all modules such as audio, IAccessible, keyboard, mouse, and GUI.
@@ -418,26 +442,14 @@ def handlePowerStatusChange(self):
418442

419443
# initialize wxpython localization support
420444
locale = wx.Locale()
421-
lang=languageHandler.getLanguage()
422-
wxLang=locale.FindLanguageInfo(lang)
423-
if not wxLang and '_' in lang:
424-
wxLang=locale.FindLanguageInfo(lang.split('_')[0])
445+
wxLang = getWxLangOrNone()
425446
if hasattr(sys,'frozen'):
426447
locale.AddCatalogLookupPathPrefix(os.path.join(globalVars.appDir, "locale"))
427-
# #8064: Wx might know the language, but may not actually contain a translation database for that language.
428-
# If we try to initialize this language, wx will show a warning dialog.
429-
# #9089: some languages (such as Aragonese) do not have language info, causing language getter to fail.
430-
# In this case, wxLang is already set to None.
431-
# Therefore treat these situations like wx not knowing the language at all.
432-
if wxLang and not locale.IsAvailable(wxLang.Language):
433-
wxLang=None
434448
if wxLang:
435449
try:
436450
locale.Init(wxLang.Language)
437451
except:
438452
log.error("Failed to initialize wx locale",exc_info=True)
439-
else:
440-
log.debugWarning("wx does not support language %s" % lang)
441453

442454
log.debug("Initializing garbageHandler")
443455
garbageHandler.initialize()

source/gui/__init__.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,10 @@ def initialize():
596596
if mainFrame:
597597
raise RuntimeError("GUI already initialized")
598598
mainFrame = MainFrame()
599+
wxLang = core.getWxLangOrNone()
600+
if wxLang:
601+
# otherwise the system default will be used
602+
mainFrame.SetLayoutDirection(wxLang.LayoutDirection)
599603
wx.GetApp().SetTopWindow(mainFrame)
600604
# In wxPython >= 4.1,
601605
# wx.CallAfter no longer executes callbacks while NVDA's main thread is within apopup menu or message box.
@@ -725,14 +729,10 @@ def __init__(self, parent):
725729
welcomeTextDetail = wx.StaticText(self, wx.ID_ANY, self.WELCOME_MESSAGE_DETAIL)
726730
mainSizer.Add(welcomeTextDetail,border=20,flag=wx.EXPAND|wx.LEFT|wx.RIGHT)
727731

728-
optionsSizer = wx.StaticBoxSizer(
729-
wx.StaticBox(
730-
self,
731-
# Translators: The label for a group box containing the NVDA welcome dialog options.
732-
label=_("Options")
733-
),
734-
wx.VERTICAL
735-
)
732+
# Translators: The label for a group box containing the NVDA welcome dialog options.
733+
optionsLabel = _("Options")
734+
optionsSizer = wx.StaticBoxSizer(wx.VERTICAL, self, label=optionsLabel)
735+
optionsBox = optionsSizer.GetStaticBox()
736736
sHelper = guiHelper.BoxSizerHelper(self, sizer=optionsSizer)
737737
# Translators: The label of a combobox in the Welcome dialog.
738738
kbdLabelText = _("&Keyboard layout:")
@@ -747,17 +747,18 @@ def __init__(self, parent):
747747
log.error("Could not set Keyboard layout list to current layout",exc_info=True)
748748
# Translators: The label of a checkbox in the Welcome dialog.
749749
capsAsNVDAModifierText = _("&Use CapsLock as an NVDA modifier key")
750-
self.capsAsNVDAModifierCheckBox = sHelper.addItem(wx.CheckBox(self, label=capsAsNVDAModifierText))
750+
self.capsAsNVDAModifierCheckBox = sHelper.addItem(wx.CheckBox(optionsBox, label=capsAsNVDAModifierText))
751751
self.capsAsNVDAModifierCheckBox.SetValue(config.conf["keyboard"]["useCapsLockAsNVDAModifierKey"])
752752
# Translators: The label of a checkbox in the Welcome dialog.
753753
startAfterLogonText = _("St&art NVDA after I sign in")
754-
self.startAfterLogonCheckBox = sHelper.addItem(wx.CheckBox(self, label=startAfterLogonText))
754+
self.startAfterLogonCheckBox = sHelper.addItem(wx.CheckBox(optionsBox, label=startAfterLogonText))
755755
self.startAfterLogonCheckBox.Value = config.getStartAfterLogon()
756756
if globalVars.appArgs.secure or config.isAppX or not config.isInstalledCopy():
757757
self.startAfterLogonCheckBox.Disable()
758758
# Translators: The label of a checkbox in the Welcome dialog.
759759
showWelcomeDialogAtStartupText = _("&Show this dialog when NVDA starts")
760-
self.showWelcomeDialogAtStartupCheckBox = sHelper.addItem(wx.CheckBox(self, label=showWelcomeDialogAtStartupText))
760+
_showWelcomeDialogAtStartupCheckBox = wx.CheckBox(optionsBox, label=showWelcomeDialogAtStartupText)
761+
self.showWelcomeDialogAtStartupCheckBox = sHelper.addItem(_showWelcomeDialogAtStartupCheckBox)
761762
self.showWelcomeDialogAtStartupCheckBox.SetValue(config.conf["general"]["showWelcomeDialogAtStartup"])
762763
mainSizer.Add(optionsSizer, border=guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL)
763764
mainSizer.Add(self.CreateButtonSizer(wx.OK), border=guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL|wx.ALIGN_RIGHT)
@@ -810,7 +811,8 @@ def __init__(self, parent):
810811

811812
# Translators: The label of the license text which will be shown when NVDA installation program starts.
812813
groupLabel = _("License Agreement")
813-
sizer = sHelper.addItem(wx.StaticBoxSizer(wx.StaticBox(self, label=groupLabel), wx.VERTICAL))
814+
sizer = wx.StaticBoxSizer(wx.VERTICAL, self, label=groupLabel)
815+
sHelper.addItem(sizer)
814816
licenseTextCtrl = wx.TextCtrl(self, size=(500, 400), style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH)
815817
licenseTextCtrl.Value = codecs.open(getDocFilePath("copying.txt", False), "r", encoding="UTF-8").read()
816818
sizer.Add(licenseTextCtrl)

source/gui/configProfiles.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,24 @@ def __init__(self, parent):
4242

4343
mainSizer = wx.BoxSizer(wx.VERTICAL)
4444
sHelper = guiHelper.BoxSizerHelper(self,orientation=wx.VERTICAL)
45-
profilesListGroupSizer = wx.StaticBoxSizer(wx.StaticBox(self), wx.HORIZONTAL)
45+
profilesListGroupSizer = wx.StaticBoxSizer(wx.HORIZONTAL, self)
46+
profilesListBox = profilesListGroupSizer.GetStaticBox()
4647
profilesListGroupContents = wx.BoxSizer(wx.HORIZONTAL)
4748

4849
#contains the profile list and activation button in vertical arrangement.
4950
changeProfilesSizer = wx.BoxSizer(wx.VERTICAL)
50-
item = self.profileList = wx.ListBox(self,
51-
choices=[self.getProfileDisplay(name, includeStates=True) for name in self.profileNames])
51+
item = self.profileList = wx.ListBox(
52+
profilesListBox,
53+
choices=[self.getProfileDisplay(name, includeStates=True) for name in self.profileNames]
54+
)
5255
self.bindHelpEvent("ProfilesBasicManagement", self.profileList)
5356
item.Bind(wx.EVT_LISTBOX, self.onProfileListChoice)
5457
item.Selection = self.profileNames.index(config.conf.profiles[-1].name)
5558
changeProfilesSizer.Add(item, proportion=1.0)
5659

5760
changeProfilesSizer.AddSpacer(guiHelper.SPACE_BETWEEN_BUTTONS_VERTICAL)
5861

59-
self.changeStateButton = wx.Button(self)
62+
self.changeStateButton = wx.Button(profilesListBox)
6063
self.bindHelpEvent("ConfigProfileManual", self.changeStateButton)
6164
self.changeStateButton.Bind(wx.EVT_BUTTON, self.onChangeState)
6265
self.AffirmativeId = self.changeStateButton.Id
@@ -68,17 +71,17 @@ def __init__(self, parent):
6871

6972
buttonHelper = guiHelper.ButtonHelper(wx.VERTICAL)
7073
# Translators: The label of a button to create a new configuration profile.
71-
newButton = buttonHelper.addButton(self, label=_("&New"))
74+
newButton = buttonHelper.addButton(profilesListBox, label=_("&New"))
7275
self.bindHelpEvent("ProfilesCreating", newButton)
7376
newButton.Bind(wx.EVT_BUTTON, self.onNew)
7477

7578
# Translators: The label of a button to rename a configuration profile.
76-
self.renameButton = buttonHelper.addButton(self, label=_("&Rename"))
79+
self.renameButton = buttonHelper.addButton(profilesListBox, label=_("&Rename"))
7780
self.bindHelpEvent("ProfilesBasicManagement", self.renameButton)
7881
self.renameButton.Bind(wx.EVT_BUTTON, self.onRename)
7982

8083
# Translators: The label of a button to delete a configuration profile.
81-
self.deleteButton = buttonHelper.addButton(self, label=_("&Delete"))
84+
self.deleteButton = buttonHelper.addButton(profilesListBox, label=_("&Delete"))
8285
self.bindHelpEvent("ProfilesBasicManagement", self.deleteButton)
8386
self.deleteButton.Bind(wx.EVT_BUTTON, self.onDelete)
8487

source/gui/guiHelper.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,10 @@ def addLabeledControl(self, labelText, wxCtrlClass, **kwargs):
324324
Relies on guiHelper.LabeledControlHelper and thus guiHelper.associateElements, and therefore inherits any
325325
limitations from there.
326326
"""
327-
labeledControl = LabeledControlHelper(self._parent, labelText, wxCtrlClass, **kwargs)
327+
parent = self._parent
328+
if isinstance(self.sizer, wx.StaticBoxSizer):
329+
parent = self.sizer.GetStaticBox()
330+
labeledControl = LabeledControlHelper(parent, labelText, wxCtrlClass, **kwargs)
328331
if(isinstance(labeledControl.control, (wx.ListCtrl,wx.ListBox,wx.TreeCtrl))):
329332
self.addItem(labeledControl.sizer, flag=wx.EXPAND, proportion=1)
330333
else:
@@ -345,6 +348,9 @@ def addDialogDismissButtons(self, buttons, separated=False):
345348
Should be set to L{False} for message or single input dialogs, L{True} otherwise.
346349
@type separated: L{bool}
347350
"""
351+
parent = self._parent
352+
if isinstance(self.sizer, wx.StaticBoxSizer):
353+
parent = self.sizer.GetStaticBox()
348354
if self.sizer.GetOrientation() != wx.VERTICAL:
349355
raise NotImplementedError(
350356
"Adding dialog dismiss buttons to a horizontal BoxSizerHelper is not implemented."
@@ -354,16 +360,15 @@ def addDialogDismissButtons(self, buttons, separated=False):
354360
elif isinstance(buttons, (wx.Sizer, wx.Button)):
355361
toAdd = buttons
356362
elif isinstance(buttons, int):
357-
toAdd = self._parent.CreateButtonSizer(buttons)
363+
toAdd = parent.CreateButtonSizer(buttons)
358364
else:
359365
raise NotImplementedError("Unknown type: {}".format(buttons))
360366
if separated:
361-
self.addItem(wx.StaticLine(self._parent), flag=wx.EXPAND)
367+
self.addItem(wx.StaticLine(parent), flag=wx.EXPAND)
362368
self.addItem(toAdd, flag=wx.ALIGN_RIGHT)
363369
self.dialogDismissButtonsAdded = True
364370
return buttons
365371

366372
class SIPABCMeta(wx.siplib.wrappertype, ABCMeta):
367373
"""Meta class to be used for wx subclasses with abstract methods."""
368374
pass
369-

source/gui/installerGui.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,15 @@ def __init__(self, parent, isUpdate):
175175
self.bindHelpEvent("InstallWithIncompatibleAddons", self.confirmationCheckbox)
176176
self.confirmationCheckbox.SetFocus()
177177

178-
optionsSizer = guiHelper.BoxSizerHelper(self, sizer=sHelper.addItem(wx.StaticBoxSizer(
179-
wx.StaticBox(
180-
self,
181-
# Translators: The label for a group box containing the NVDA installation dialog options.
182-
label=_("Options")
183-
),
184-
wx.VERTICAL
185-
)))
178+
# Translators: The label for a group box containing the NVDA installation dialog options.
179+
optionsLabel = _("Options")
180+
optionsHelper = sHelper.addItem(wx.StaticBoxSizer(wx.VERTICAL, self, label=optionsLabel))
181+
optionsSizer = guiHelper.BoxSizerHelper(self, sizer=optionsHelper)
182+
optionsBox = optionsSizer.GetStaticBox()
186183

187184
# Translators: The label of a checkbox option in the Install NVDA dialog.
188185
startOnLogonText = _("Use NVDA during sign-in")
189-
self.startOnLogonCheckbox = optionsSizer.addItem(wx.CheckBox(self, label=startOnLogonText))
186+
self.startOnLogonCheckbox = optionsSizer.addItem(wx.CheckBox(optionsBox, label=startOnLogonText))
190187
self.bindHelpEvent("StartAtWindowsLogon", self.startOnLogonCheckbox)
191188
if globalVars.appArgs.enableStartOnLogon is not None:
192189
self.startOnLogonCheckbox.Value = globalVars.appArgs.enableStartOnLogon
@@ -197,19 +194,22 @@ def __init__(self, parent, isUpdate):
197194
if self.isUpdate and shortcutIsPrevInstalled:
198195
# Translators: The label of a checkbox option in the Install NVDA dialog.
199196
keepShortCutText = _("&Keep existing desktop shortcut")
200-
self.createDesktopShortcutCheckbox = optionsSizer.addItem(wx.CheckBox(self, label=keepShortCutText))
197+
keepShortCutBox = wx.CheckBox(optionsBox, label=keepShortCutText)
198+
self.createDesktopShortcutCheckbox = optionsSizer.addItem(keepShortCutBox)
201199
else:
202200
# Translators: The label of the option to create a desktop shortcut in the Install NVDA dialog.
203201
# If the shortcut key has been changed for this locale,
204202
# this change must also be reflected here.
205203
createShortcutText = _("Create &desktop icon and shortcut key (control+alt+n)")
206-
self.createDesktopShortcutCheckbox = optionsSizer.addItem(wx.CheckBox(self, label=createShortcutText))
204+
createShortcutBox = wx.CheckBox(optionsBox, label=createShortcutText)
205+
self.createDesktopShortcutCheckbox = optionsSizer.addItem(createShortcutBox)
207206
self.bindHelpEvent("CreateDesktopShortcut", self.createDesktopShortcutCheckbox)
208207
self.createDesktopShortcutCheckbox.Value = shortcutIsPrevInstalled if self.isUpdate else True
209208

210209
# Translators: The label of a checkbox option in the Install NVDA dialog.
211210
createPortableText = _("Copy &portable configuration to current user account")
212-
self.copyPortableConfigCheckbox = optionsSizer.addItem(wx.CheckBox(self, label=createPortableText))
211+
createPortableBox = wx.CheckBox(optionsBox, label=createPortableText)
212+
self.copyPortableConfigCheckbox = optionsSizer.addItem(createPortableBox)
213213
self.bindHelpEvent("CopyPortableConfigurationToCurrentUserAccount", self.copyPortableConfigCheckbox)
214214
self.copyPortableConfigCheckbox.Value = bool(globalVars.appArgs.copyPortableConfig)
215215
if globalVars.appArgs.copyPortableConfig is None:
@@ -220,12 +220,12 @@ def __init__(self, parent, isUpdate):
220220
bHelper = sHelper.addDialogDismissButtons(guiHelper.ButtonHelper(wx.HORIZONTAL))
221221
if shouldAskAboutAddons:
222222
# Translators: The label of a button to launch the add-on compatibility review dialog.
223-
reviewAddonButton = bHelper.addButton(self, label=_("&Review add-ons..."))
223+
reviewAddonButton = bHelper.addButton(optionsBox, label=_("&Review add-ons..."))
224224
self.bindHelpEvent("InstallWithIncompatibleAddons", reviewAddonButton)
225225
reviewAddonButton.Bind(wx.EVT_BUTTON, self.onReviewAddons)
226226

227227
# Translators: The label of a button to continue with the operation.
228-
continueButton = bHelper.addButton(self, label=_("&Continue"), id=wx.ID_OK)
228+
continueButton = bHelper.addButton(optionsBox, label=_("&Continue"), id=wx.ID_OK)
229229
continueButton.SetDefault()
230230
continueButton.Bind(wx.EVT_BUTTON, self.onInstall)
231231
if shouldAskAboutAddons:
@@ -235,7 +235,7 @@ def __init__(self, parent, isUpdate):
235235
)
236236
continueButton.Enable(False)
237237

238-
bHelper.addButton(self, id=wx.ID_CANCEL)
238+
bHelper.addButton(optionsBox, id=wx.ID_CANCEL)
239239
# If we bind this using button.Bind, it fails to trigger when the dialog is closed.
240240
self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL)
241241

@@ -349,35 +349,38 @@ def __init__(self, parent):
349349
# Translators: The label of a grouping containing controls to select the destination directory
350350
# in the Create Portable NVDA dialog.
351351
directoryGroupText = _("Portable &directory:")
352-
groupHelper = sHelper.addItem(gui.guiHelper.BoxSizerHelper(self, sizer=wx.StaticBoxSizer(wx.StaticBox(self, label=directoryGroupText), wx.VERTICAL)))
352+
groupSizer = wx.StaticBoxSizer(wx.VERTICAL, self, label=directoryGroupText)
353+
groupHelper = sHelper.addItem(gui.guiHelper.BoxSizerHelper(self, sizer=groupSizer))
354+
groupBox = groupSizer.GetStaticBox()
353355
# Translators: The label of a button to browse for a directory.
354356
browseText = _("Browse...")
355357
# Translators: The title of the dialog presented when browsing for the
356358
# destination directory when creating a portable copy of NVDA.
357359
dirDialogTitle = _("Select portable directory")
358-
directoryEntryControl = groupHelper.addItem(gui.guiHelper.PathSelectionHelper(self, browseText, dirDialogTitle))
360+
directoryPathHelper = gui.guiHelper.PathSelectionHelper(groupBox, browseText, dirDialogTitle)
361+
directoryEntryControl = groupHelper.addItem(directoryPathHelper)
359362
self.portableDirectoryEdit = directoryEntryControl.pathControl
360363
if globalVars.appArgs.portablePath:
361364
self.portableDirectoryEdit.Value = globalVars.appArgs.portablePath
362365

363366
# Translators: The label of a checkbox option in the Create Portable NVDA dialog.
364367
copyConfText = _("Copy current &user configuration")
365-
self.copyUserConfigCheckbox = sHelper.addItem(wx.CheckBox(self, label=copyConfText))
368+
self.copyUserConfigCheckbox = sHelper.addItem(wx.CheckBox(groupBox, label=copyConfText))
366369
self.copyUserConfigCheckbox.Value = False
367370
if globalVars.appArgs.launcher:
368371
self.copyUserConfigCheckbox.Disable()
369372
# Translators: The label of a checkbox option in the Create Portable NVDA dialog.
370373
startAfterCreateText = _("&Start the new portable copy after creation")
371-
self.startAfterCreateCheckbox = sHelper.addItem(wx.CheckBox(self, label=startAfterCreateText))
374+
self.startAfterCreateCheckbox = sHelper.addItem(wx.CheckBox(groupBox, label=startAfterCreateText))
372375
self.startAfterCreateCheckbox.Value = False
373376

374377
bHelper = sHelper.addDialogDismissButtons(gui.guiHelper.ButtonHelper(wx.HORIZONTAL), separated=True)
375378

376-
continueButton = bHelper.addButton(self, label=_("&Continue"), id=wx.ID_OK)
379+
continueButton = bHelper.addButton(groupBox, label=_("&Continue"), id=wx.ID_OK)
377380
continueButton.SetDefault()
378381
continueButton.Bind(wx.EVT_BUTTON, self.onCreatePortable)
379382

380-
bHelper.addButton(self, id=wx.ID_CANCEL)
383+
bHelper.addButton(groupBox, id=wx.ID_CANCEL)
381384
# If we bind this using button.Bind, it fails to trigger when the dialog is closed.
382385
self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL)
383386

0 commit comments

Comments
 (0)