diff --git a/source/gui/__init__.py b/source/gui/__init__.py index 67d11420154..04728519a44 100644 --- a/source/gui/__init__.py +++ b/source/gui/__init__.py @@ -223,6 +223,8 @@ def popupSettingsDialog(self, dialog: Type[SettingsDialog], *args, **kwargs): dialog(self, *args, **kwargs).Show() except SettingsDialog.MultiInstanceErrorWithDialog as errorWithDialog: errorWithDialog.dialog.SetFocus() + if isinstance(errorWithDialog.dialog, MultiCategorySettingsDialog) and len(args) > 0: + errorWithDialog.dialog.selectNewCategory(args[0]) except MultiCategorySettingsDialog.CategoryUnavailableError: # Translators: Message shown when trying to open an unavailable category of a multi category settings dialog # (example: when trying to open touch interaction settings on an unsupported system). diff --git a/source/gui/settingsDialogs.py b/source/gui/settingsDialogs.py index fda570fa248..95bd6a28753 100644 --- a/source/gui/settingsDialogs.py +++ b/source/gui/settingsDialogs.py @@ -493,23 +493,16 @@ class MultiCategorySettingsDialog(SettingsDialog): class CategoryUnavailableError(RuntimeError): pass - def __init__(self, parent, initialCategory=None): + def __init__( + self, + parent: Optional[wx.Window], + initialCategory: Optional[SettingsPanel] = None, + ): """ @param parent: The parent for this dialog; C{None} for no parent. - @type parent: wx.Window @param initialCategory: The initial category to select when opening this dialog - @type parent: SettingsPanel """ - if initialCategory and not issubclass(initialCategory,SettingsPanel): - if gui._isDebug(): - log.debug("Unable to open category: {}".format(initialCategory), stack_info=True) - raise TypeError("initialCategory should be an instance of SettingsPanel") - if initialCategory and initialCategory not in self.categoryClasses: - if gui._isDebug(): - log.debug("Unable to open category: {}".format(initialCategory), stack_info=True) - raise MultiCategorySettingsDialog.CategoryUnavailableError( - "The provided initial category is not a part of this dialog" - ) + self.checkCategory(initialCategory) self.initialCategory = initialCategory self.currentCategory = None self.setPostInitFocus = None @@ -620,6 +613,25 @@ def makeSettings(self, settingsSizer): self.Bind(wx.EVT_CHAR_HOOK, self.onCharHook) self.Bind(EVT_RW_LAYOUT_NEEDED, self._onPanelLayoutChanged) + def checkCategory(self, cat: Optional[SettingsPanel]) -> None: + """ + @param cat: The class of the panel on which the dialog should be opened or C{None} if no specific panel + is targetted. + + """ + if cat is None: + return + if not issubclass(cat, SettingsPanel): + if gui._isDebug(): + log.debug("Unable to open category: {}".format(cat), stack_info=True) + raise TypeError("cat should be an instance of SettingsPanel") + if cat not in self.categoryClasses: + if gui._isDebug(): + log.debug("Unable to open category: {}".format(cat), stack_info=True) + raise MultiCategorySettingsDialog.CategoryUnavailableError( + "The provided initial category is not a part of this dialog" + ) + def _getCategoryPanel(self, catId): panel = self.catIdToInstanceMap.get(catId, None) if not panel: @@ -692,6 +704,19 @@ def _onPanelLayoutChanged(self,evt): # erase the old contents and must be redrawn self.container.Refresh() + def selectNewCategory(self, cat): + self.checkCategory(cat) + currentCat = self.currentCategory + newIndex = self.categoryClasses.index(cat) + if not currentCat or newIndex != self.categoryClasses.index(currentCat.__class__): + listHadFocus = self.catListCtrl.HasFocus() + if not listHadFocus: + self.catListCtrl.SetFocus() + self.catListCtrl.Select(newIndex) + # we must focus the new selection in the category list to trigger the change of category. + self.catListCtrl.Focus(newIndex) + self.currentCategory.SetFocus() + def _doCategoryChange(self, newCatId): oldCat = self.currentCategory # Freeze and Thaw are called to stop visual artifact's while the GUI diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index 2a26b7c2ae9..5102bbd6346 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -46,6 +46,7 @@ Unicode CLDR has been updated. * NVDA will correctly announce selection changes when editing a cell's text in Microsoft Excel. (#15843) * In applications using Java Access Bridge, NVDA will now correctly read the last blank line of a text instead of repeating the previous line. (#9376, @dmitrii-drobotov) * In LibreOffice Writer (version 24.8 and newer), when toggling text formatting (bold, italic, underline, subscript/superscript, alignment) using the corresponding keyboard shortcut, NVDA announces the new formatting attribute (e.g. "Bold on", "Bold off"). (#4248, @michaelweghorn) +* Opening the settings dialog a second time with a keyboard shortcut now opens the expected settings panel. (#12995) ### Changes for Developers