Skip to content

Commit

Permalink
Fix currently edited profile announcements, numpad enter functionalit…
Browse files Browse the repository at this point in the history
…y and validation behavior (#8253)

* Fix another case where the switch of the currently edited profile is not announced

* Restore event_appModule_loseFocus

* Fix operation of the numpad enter key in settings dialogs

* Remove obsolete char hooks from lists

* Rename handler for enter and control+s to _enterActivatesOk_ctrlSActivatesApply

* Add additional information in the enter/escape event handler that mentions wx ticket 3725

* Add preSave and postSave handlers

* Fixed doc string for SettingsPanel on discard

* preSave, explicitly check for False

* Review actions
  • Loading branch information
LeonarddeR authored and michaelDCurran committed May 31, 2018
1 parent 27c21d6 commit 0f69cd1
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 41 deletions.
5 changes: 2 additions & 3 deletions source/appModules/nvda.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ def handlePossibleProfileSwitch(cls):

class AppModule(appModuleHandler.AppModule):

def event_appModule_gainFocus(self):
NvdaSettingsCategoryPanel.handlePossibleProfileSwitch()

def event_appModule_loseFocus(self):
NvdaSettingsCategoryPanel.oldProfile = None

Expand Down Expand Up @@ -98,6 +95,8 @@ def event_gainFocus(self, obj, nextHandler):
def event_foreground (self, obj, nextHandler):
if not gui.shouldConfigProfileTriggersBeSuspended():
config.conf.resumeProfileTriggers()
else:
NvdaSettingsCategoryPanel.handlePossibleProfileSwitch()
nextHandler()

def chooseNVDAObjectOverlayClasses(self, obj, clsList):
Expand Down
92 changes: 54 additions & 38 deletions source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,20 +138,24 @@ def __init__(self, parent,
self.Bind(wx.EVT_BUTTON, self.onOk, id=wx.ID_OK)
self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL)
self.Bind(wx.EVT_BUTTON, self.onApply, id=wx.ID_APPLY)
self.Bind(wx.EVT_CHAR_HOOK, self._enterTriggersOnOk_ctrlSTriggersOnApply)
self.Bind(wx.EVT_CHAR_HOOK, self._enterActivatesOk_ctrlSActivatesApply)

self.postInit()
self.Center(wx.BOTH | wx.CENTER_ON_SCREEN)
if gui._isDebug():
log.debug("Loading %s took %.2f seconds"%(self.__class__.__name__, time.time() - startTime))

def _enterTriggersOnOk_ctrlSTriggersOnApply(self, evt):
def _enterActivatesOk_ctrlSActivatesApply(self, evt):
"""Listens for keyboard input and triggers ok button on enter and triggers apply button when control + S is
pressed. Cancel behavior is built into wx"""
if evt.KeyCode == wx.WXK_RETURN:
self.onOk(evt)
pressed. Cancel behavior is built into wx.
Pressing enter will also close the dialog when a list has focus
(e.g. the list of symbols in the symbol pronunciation dialog).
Without this custom handler, enter would propagate to the list control (wx ticket #3725).
"""
if evt.KeyCode in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
self.ProcessEvent(wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, wx.ID_OK))
elif self.hasApply and evt.UnicodeKey == ord(u'S') and evt.controlDown:
self.onApply(evt)
self.ProcessEvent(wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, wx.ID_APPLY))
else:
evt.Skip()

Expand Down Expand Up @@ -219,6 +223,7 @@ class SettingsPanel(wx.Panel):
* Optionally, extend L{onPanelActivated} to perform actions after the category has been selected in the list of categories, such as synthesizer or braille display list population.
* Optionally, extend L{onPanelDeactivated} to perform actions after the category has been deselected (i.e. another category is selected) in the list of categories.
* Optionally, extend one or both of L{onSave} or L{onDiscard} to perform actions in response to the parent dialog's OK or Cancel buttons, respectively.
* Optionally, extend one or both of L{isValid} or L{postSave} to perform validation before or steps after saving, respectively.
@ivar title: The title of the settings panel, also listed in the list of settings categories.
@type title: str
Expand Down Expand Up @@ -274,9 +279,24 @@ def onSave(self):
"""
raise NotImplementedError

def isValid(self):
"""Evaluate whether the current circumstances of this panel are valid
and allow saving all the settings in a L{MultiCategorySettingsDialog}.
Sub-classes may extend this method.
@returns: C{True} if validation should continue,
C{False} otherwise.
@rtype: bool
"""
return True

def postSave(self):
"""Take action whenever saving settings for all panels in a L{MultiCategorySettingsDialog} succeeded.
Sub-classes may extend this method.
"""

def onDiscard(self):
"""Take action in response to the parent's dialog Cancel button being pressed.
Sub-classes should override this method.
Sub-classes may override this method.
MultiCategorySettingsDialog is responsible for cleaning up the panel when Cancel is pressed.
"""

Expand Down Expand Up @@ -505,9 +525,6 @@ def onCharHook(self,evt):
self.catListCtrl.Focus(newIndex)
if not listHadFocus and self.currentCategory:
self.currentCategory.SetFocus()
elif listHadFocus and key == wx.WXK_RETURN:
# The list control captures the return key, but we want it to save the settings.
self.onOk(evt)
else:
evt.Skip()

Expand Down Expand Up @@ -552,9 +569,22 @@ def onCategoryChange(self, evt):
else:
evt.Skip()

def onOk(self,evt):
def _doSave(self):
for panel in self.catIdToInstanceMap.itervalues():
if panel.isValid() is False:
raise ValueError("Validation for %s blocked saving settings" % panel.__class__.__name__)
for panel in self.catIdToInstanceMap.itervalues():
panel.onSave()
for panel in self.catIdToInstanceMap.itervalues():
panel.postSave()

def onOk(self,evt):
try:
self._doSave()
except ValueError:
log.debugWarning("", exc_info=True)
return
for panel in self.catIdToInstanceMap.itervalues():
panel.Destroy()
super(MultiCategorySettingsDialog,self).onOk(evt)

Expand All @@ -565,8 +595,11 @@ def onCancel(self,evt):
super(MultiCategorySettingsDialog,self).onCancel(evt)

def onApply(self,evt):
for panel in self.catIdToInstanceMap.itervalues():
panel.onSave()
try:
self._doSave()
except ValueError:
log.debugWarning("", exc_info=True)
return
super(MultiCategorySettingsDialog,self).onApply(evt)

class GeneralSettingsPanel(SettingsPanel):
Expand Down Expand Up @@ -729,7 +762,9 @@ def onSave(self):
config.conf["update"]["startupNotification"]=self.notifyForPendingUpdateCheckBox.IsChecked()
updateCheck.terminate()
updateCheck.initialize()
if self.oldLanguage!=newLanguage:

def postSave(self):
if self.oldLanguage!=config.conf["general"]["language"]:
if gui.messageBox(
# Translators: The message displayed after NVDA interface language has been changed.
_("For the new language to take effect, the configuration must be saved and NVDA must be restarted. Press enter to save and restart NVDA, or cancel to manually save and exit at a later time."),
Expand Down Expand Up @@ -1234,7 +1269,7 @@ def makeSettings(self, settingsSizer):
self.handleInjectedKeysCheckBox=sHelper.addItem(wx.CheckBox(self,label=handleInjectedKeysText))
self.handleInjectedKeysCheckBox.SetValue(config.conf["keyboard"]["handleInjectedKeys"])

def onSave(self):
def isValid(self):
# #2871: check wether at least one key is the nvda key.
if not self.capsAsNVDAModifierCheckBox.IsChecked() and not self.numpadInsertAsNVDAModifierCheckBox.IsChecked() and not self.extendedInsertAsNVDAModifierCheckBox.IsChecked():
log.debugWarning("No NVDA key set")
Expand All @@ -1243,7 +1278,10 @@ def onSave(self):
_("At least one key must be used as the NVDA key."),
# Translators: The title of the message box
_("Error"), wx.OK|wx.ICON_ERROR,self)
return
return False
return super(KeyboardSettingsPanel, self).isValid()

def onSave(self):
layout=self.kbdNames[self.kbdList.GetSelection()]
config.conf['keyboard']['keyboardLayout']=layout
config.conf["keyboard"]["useCapsLockAsNVDAModifierKey"]=self.capsAsNVDAModifierCheckBox.IsChecked()
Expand Down Expand Up @@ -1952,7 +1990,6 @@ def makeSettings(self, settingsSizer):
for entry in self.tempSpeechDict:
self.dictList.Append((entry.comment,entry.pattern,entry.replacement,self.offOn[int(entry.caseSensitive)],DictionaryDialog.TYPE_LABELS[entry.type]))
self.editingIndex=-1
self.dictList.Bind(wx.EVT_CHAR, self.onListChar)

bHelper = guiHelper.ButtonHelper(orientation=wx.HORIZONTAL)
addButtonID=wx.NewId()
Expand All @@ -1974,16 +2011,6 @@ def makeSettings(self, settingsSizer):
def postInit(self):
self.dictList.SetFocus()

def onListChar(self, evt):
if evt.KeyCode == wx.WXK_RETURN:
# The enter key should be propagated to the dialog and thus activate the default button,
# but this is broken (wx ticket #3725).
# Therefore, we must catch the enter key here.
# Activate the OK button.
self.ProcessEvent(wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, wx.ID_OK))
else:
evt.Skip()

def onCancel(self,evt):
globalVars.speechDictionaryProcessing=True
super(DictionaryDialog, self).onCancel(evt)
Expand Down Expand Up @@ -2480,7 +2507,6 @@ def makeSettings(self, settingsSizer):
item = self.symbolsList.Append((symbol.displayName,))
self.updateListItem(item, symbol)
self.symbolsList.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onListItemFocused)
self.symbolsList.Bind(wx.EVT_CHAR, self.onListChar)

# Translators: The label for the group of controls in symbol pronunciation dialog to change the pronunciation of a symbol.
changeSymbolText = _("Change selected symbol")
Expand Down Expand Up @@ -2569,16 +2595,6 @@ def onListItemFocused(self, evt):
self.preserveList.Enable()
evt.Skip()

def onListChar(self, evt):
if evt.KeyCode == wx.WXK_RETURN:
# The enter key should be propagated to the dialog and thus activate the default button,
# but this is broken (wx ticket #3725).
# Therefore, we must catch the enter key here.
# Activate the OK button.
self.ProcessEvent(wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, wx.ID_OK))
else:
evt.Skip()

def OnAddClick(self, evt):
with AddSymbolDialog(self) as entryDialog:
if entryDialog.ShowModal() != wx.ID_OK:
Expand Down

0 comments on commit 0f69cd1

Please sign in to comment.