diff --git a/source/gui/__init__.py b/source/gui/__init__.py index d9c348a37b..7360c83106 100644 --- a/source/gui/__init__.py +++ b/source/gui/__init__.py @@ -37,6 +37,7 @@ VoiceDictionaryDialog, TemporaryDictionaryDialog, ) +from .nvdaControls import _ContinueCancelDialog # ExitDialog is accessed through `import gui.ExitDialog` as opposed to `gui.exit.ExitDialog`. # Be careful when removing, and only do in a compatibility breaking release. @@ -479,50 +480,90 @@ def onInstallCommand(self, evt): installerGui.showInstallGui() + _CRFT_INTRO_MESSAGE: str = _( + # Translators: Explain the COM Registration Fixing tool to users before running + "Welcome to the COM Registration Fixing tool.\n\n" + "Installing and uninstalling programs, as well as other events, can damage accessibility entries in the " + "Windows registry. This can cause previously accessible elements to be presented incorrectly, " + 'or can cause "unknown" or "pane" to be spoken or brailled in some applications or Windows components, ' + "instead of the content you were expecting.\n\n" + "This tool attempts to fix such common problems. " + "Note that the tool must access the system registry, which requires administrative privileges.\n\n" + "Press Continue to run the tool now.", + ) + """ + Contains the intro dialog contents for the COM Registration Fixing Tool. + Used by `gui.MainFrame.onRunCOMRegistrationFixesCommand`. + """ + @blockAction.when( blockAction.Context.SECURE_MODE, blockAction.Context.MODAL_DIALOG_OPEN, ) - def onRunCOMRegistrationFixesCommand(self, evt): - if ( - messageBox( - _( - # Translators: A message to warn the user when starting the COM Registration Fixing tool - "You are about to run the COM Registration Fixing tool. " - "This tool will try to fix common system problems that stop NVDA from being able to access content " - "in many programs including Firefox and Internet Explorer. " - "This tool must make changes to the System registry and therefore requires administrative access. " - "Are you sure you wish to proceed?", - ), - # Translators: The title of the warning dialog displayed when launching the COM Registration Fixing tool - _("Warning"), - wx.YES | wx.NO | wx.ICON_WARNING, - self, - ) - == wx.NO - ): + def onRunCOMRegistrationFixesCommand(self, evt: wx.CommandEvent) -> None: + """Manages the interactive running of the COM Registration Fixing Tool. + Shows a dialog to the user, giving an overview of what is going to happen. + If the user chooses to continue: runs the tool, and displays a completion dialog. + Cancels the run attempt if the user fails or declines the UAC prompt. + """ + # Translators: The title of various dialogs displayed when using the COM Registration Fixing tool + genericTitle: str = _("Fix COM Registrations") + introDialog = _ContinueCancelDialog( + self, + genericTitle, + self._CRFT_INTRO_MESSAGE, + helpId="RunCOMRegistrationFixingTool", + ) + response: int = introDialog.ShowModal() + if response == wx.CANCEL: + log.debug("Run of COM Registration Fixing Tool canceled before UAC.") return progressDialog = IndeterminateProgressDialog( mainFrame, - # Translators: The title of the dialog presented while NVDA is running the COM Registration fixing tool - _("COM Registration Fixing Tool"), + genericTitle, # Translators: The message displayed while NVDA is running the COM Registration fixing tool - _("Please wait while NVDA tries to fix your system's COM registrations."), + _("Please wait while NVDA attempts to fix your system's COM registrations..."), ) + error: str | None = None try: systemUtils.execElevated(config.SLAVE_FILENAME, ["fixCOMRegistrations"]) - except: # noqa: E722 + except WindowsError as e: + # 1223 is "The operation was canceled by the user." + if e.winerror == 1223: + # Same as if the user selected "no" in the initial dialog. + log.debug("Run of COM Registration Fixing Tool canceled during UAC.") + return + else: + log.error("Could not execute fixCOMRegistrations command", exc_info=True) + error = e # Hold for later display to the user + return # Safe because of finally block + except Exception: log.error("Could not execute fixCOMRegistrations command", exc_info=True) - progressDialog.done() - del progressDialog + return # Safe because of finally block + finally: # Clean up the progress dialog, and display any important error to the user before returning + progressDialog.done() + del progressDialog + self.postPopup() + # If there was a Windows error, inform the user because it may have support value + if error is not None: + messageBox( + _( + # Translators: message shown to the user on COM Registration Fix fail + "The COM Registration Fixing Tool was unsuccessful. This Windows " + "error may provide more information.\n{error}", + ).format(error=error), + # Translators: The title of a COM Registration Fixing Tool dialog, when the tool has failed + _("COM Registration Fixing Tool Failed"), + wx.OK, + ) + # Display success dialog if there were no errors messageBox( _( - # Translators: The message displayed when the COM Registration Fixing tool completes. - "The COM Registration Fixing tool has finished. " + # Translators: Message shown when the COM Registration Fixing tool completes. + "The COM Registration Fixing Tool has completed successfully.\n" "It is highly recommended that you restart your computer now, to make sure the changes take full effect.", ), - # Translators: The title of a dialog presented when the COM Registration Fixing tool is complete. - _("COM Registration Fixing Tool"), + genericTitle, wx.OK, ) diff --git a/source/gui/logViewer.py b/source/gui/logViewer.py old mode 100755 new mode 100644 diff --git a/source/gui/nvdaControls.py b/source/gui/nvdaControls.py index fe1aaa7077..66016ebc01 100644 --- a/source/gui/nvdaControls.py +++ b/source/gui/nvdaControls.py @@ -2,6 +2,7 @@ # Copyright (C) 2016-2024 NV Access Limited, Derek Riemer, Cyrille Bougot, Luke Davis, Leonard de Ruijter # This file is covered by the GNU General Public License. # See the file COPYING for more details. + import collections import enum import typing @@ -21,7 +22,10 @@ FlagValueEnum as FeatureFlagEnumT, ) from .dpiScalingHelper import DpiScalingHelperMixin -from . import guiHelper +from . import ( + guiHelper, + contextHelp, +) import winUser import winsound @@ -288,7 +292,7 @@ class MessageDialog(DPIScaledDialog): DIALOG_TYPE_WARNING: winsound.MB_ICONASTERISK, } - def _addButtons(self, buttonHelper): + def _addButtons(self, buttonHelper: guiHelper.ButtonHelper) -> None: """Adds ok / cancel buttons. Can be overridden to provide alternative functionality.""" ok = buttonHelper.addButton( self, @@ -376,6 +380,65 @@ def _onShowEvt(self, evt): evt.Skip() +class _ContinueCancelDialog( + contextHelp.ContextHelpMixin, + MessageDialog, +): + """ + This implementation of a `gui.nvdaControls.MessageDialog`, provides `Continue` and `Cancel` buttons as its controls. + These serve the same functions as `OK` and `Cancel` in other dialogs, but may be more desirable in some situations. + It also supports NVDA's context sensitive help. + """ + + def __init__( + self, + parent: wx.Frame, + title: str, + message: str, + dialogType: int = MessageDialog.DIALOG_TYPE_STANDARD, + continueButtonFirst: bool = True, + helpId: str | None = None, + ) -> None: + """Creates a ContinueCancelDialog MessageDialog. + + :param parent: The parent window for the dialog, usually `gui.mainFrame`. + :param title: The title or caption of the dialog. + :param message: The message to be shown in the dialog. + :param dialogType: One of the dialog type constants from `MessageDialog`, defaults to standard. + :param continueButtonFirst: If True, the Continue button will appear first, and be selected when the dialog + opens; if False, the Cancel button will. Defaults to True. + :param helpId: a helpId, as used with the `gui.contextHelp` module, enabling the help key (`F1`) + to open a browser to a specific heading in the NVDA user guide. + """ + self.continueButtonFirst: bool = continueButtonFirst + if helpId is not None: + self.helpId = helpId + super().__init__(parent, title, message, dialogType) + + def _addButtons(self, buttonHelper: guiHelper.ButtonHelper) -> None: + """Override to add Continue and Cancel buttons.""" + + # Note: the order of the Continue and Cancel buttons is important, because running SetDefault() + # on the Cancel button while the Continue button is first, has no effect. Therefore the only way to + # allow a caller to make Cancel the default, is to put it first. + def _makeContinue(self, buttonHelper: guiHelper.ButtonHelper) -> wx.Button: + # Translators: The label for the Continue button in an NVDA dialog. + return buttonHelper.addButton(self, id=wx.ID_OK, label=_("&Continue")) + + def _makeCancel(self, buttonHelper: guiHelper.ButtonHelper) -> wx.Button: + # Translators: The label for the Cancel button in an NVDA dialog. + return buttonHelper.addButton(self, id=wx.ID_CANCEL, label=_("Cancel")) + + if self.continueButtonFirst: + continueButton = _makeContinue(self, buttonHelper) + cancelButton = _makeCancel(self, buttonHelper) + else: + cancelButton = _makeCancel(self, buttonHelper) + continueButton = _makeContinue(self, buttonHelper) + continueButton.Bind(wx.EVT_BUTTON, lambda evt: self.EndModal(wx.OK)) + cancelButton.Bind(wx.EVT_BUTTON, lambda evt: self.EndModal(wx.CANCEL)) + + class EnhancedInputSlider(wx.Slider): def __init__(self, *args, **kwargs): super(EnhancedInputSlider, self).__init__(*args, **kwargs) diff --git a/user_docs/en/changes.md b/user_docs/en/changes.md index a3bf6a386e..4dd672f39c 100644 --- a/user_docs/en/changes.md +++ b/user_docs/en/changes.md @@ -27,6 +27,10 @@ In order to use this feature, the application volume adjuster needs to be enable * The exit dialog now allows you to restart NVDA with add-ons disabled and debug logging enabled simultaneously. (#11538, @CyrilleB79) * Unicode Normalization is now enabled by default for speech output. (#17017, @LeonarddeR). * You can still disable this functionality in the Speech category of the NVDA Settings dialog. +* Changes to the COM Registration Fixing Tool: (#12355, @XLTechie) + * It now starts with a more user friendly explanation of its purpose, instead of a warning. (#12351) + * The initial window can now be exited with `escape` or `alt+f4`. (#10799) + * It will now show a message to the user, including the error, in the rare event of a Windows error while attempting COM re-registrations. ### Bug Fixes @@ -39,6 +43,7 @@ In order to use this feature, the application volume adjuster needs to be enable * Braille is no longer dysfunctional when activating 'say all' with an associated configuration profile. (#17163, @LeonarddeR) * Fixed an issue where certain settings were explicitly saved to the active configuration profile even when the value of that setting was equal to the value in the base configuration. (#17157, @leonarddeR) * NVDA is able to read the popup submenu items on Thunderbird search results page. (#4708, @thgcode) +* The COM Registration Fixing Tool no longer reports success on failure. (#12355, @XLTechie) ### Changes for Developers @@ -60,7 +65,7 @@ Add-ons will need to be re-tested and have their manifest updated. * `BrowseModeTreeInterceptor` object has a new `getLinkTypeInDocument` method which accepts an URL to check the link type of the object * A `toggleBooleanValue` helper function has been added to `globalCommands`. It can be used in scripts to report the result when a boolean is toggled in `config.conf` -* Removed the requirement to indent function parameter lists by two tabs from NVDA's Coding Standards, to be compatible with modern automatic linting. (#17126, XLTechie) +* Removed the requirement to indent function parameter lists by two tabs from NVDA's Coding Standards, to be compatible with modern automatic linting. (#17126, @XLTechie) #### API Breaking Changes diff --git a/user_docs/en/userGuide.md b/user_docs/en/userGuide.md index e5142282af..3a6ce5aa1b 100644 --- a/user_docs/en/userGuide.md +++ b/user_docs/en/userGuide.md @@ -3806,19 +3806,19 @@ Follow the directions in [Creating a portable copy](#CreatingAPortableCopy) for ### Run COM registration fixing tool... {#RunCOMRegistrationFixingTool} -Installing and uninstalling programs on a computer can, in certain cases, cause COM DLL files to get unregistered. -As COM Interfaces such as IAccessible depend on correct COM DLL registrations, issues can appear in case the correct registration is missing. +Sometimes, problems can develop with the Windows Registry, that result in NVDA behaving abnormally. +This can be caused by, for example, installing or uninstalling certain programs (such as Adobe Reader or Math Player), as well as Windows updates and other events. +THE COM Registration Fixing Tool attempts to fix these issues by repairing accessibility entries in the registry. -This can happen i.e. after installing and uninstalling Adobe Reader, Math Player and other programs. +The types of problem this tool can fix include: -The missing registration can cause issues in browsers, desktop apps, task bar and other interfaces. +* NVDA reporting "unknown" or "pane", when navigating in browsers such as Firefox or Edge, mail programs such as Thunderbird, Windows Explorer, the task bar, and other programs. +* NVDA failing to switch between focus mode and browse mode when you expect it to. +* Buttons which previously had their names spoken, suddenly being reported only as "button". +* NVDA being very slow when navigating in browsers while using browse mode. -Specifically, following issues can be solved by running this tool: - -* NVDA reports "unknown" when navigating in browsers such as Firefox, Thunderbird etc. -* NVDA fails to switch between focus mode and browse mode -* NVDA is very slow when navigating in browsers while using browse mode -* And possibly other issues. +Because this tool corrects entries in the Windows registry, it requires administrative access to work, just like when installing a program. +If you have UAC (User Access Control) enabled, as most users do, you will need to follow whatever prompts are presented by UAC, to run the tool successfully. ### Reload plugins {#ReloadPlugins}