def on_load_password_list(self, evt): evt.Skip() self.load_password_list.Enable(False) self.extend_password_list.Enable(False) self.unload_password_list.Enable(False) if len(self.passwords) < 1: # translators: strings to indicate the password list is being loaded. self.prog = gui.IndeterminateProgressDialog( gui.mainFrame, _("Loading password list"), _("Please wait while the password list is loaded.")) gui.ExecAndPump(self._load) self.prog.done() del self.prog # translators: text displayed by NVDA when the password list is loaded. gui.messageBox(_("Password list loaded."), _("Finished")) else: # translators: strings to indicate the password list is being reloaded. self.prog = gui.IndeterminateProgressDialog( gui.mainFrame, _("Reloading password list"), _("Please wait while the password list is reloaded.")) gui.ExecAndPump(self._reload) self.prog.done() del self.prog # translators: text displayed by NVDA when the password list is reloaded. gui.messageBox(_("Password list reloaded."), _("Finished")) self.load_password_list.Enable(True) self.extend_password_list.Enable(True) self.unload_password_list.Enable(True)
def script_nvdaStore(self, gesture): if self.lastData is None or self.lastData["type"] is GP_DISCONNECTED: ui.message(self.lastData["message"]) return gui.mainFrame.prePopup() progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, _("Updating addons' list"), _("Please wait while the add-on list is being updated.")) try: gui.ExecAndPump(self.doRefreshAddons) except: progressDialog.done() del progressDialog gui.mainFrame.postPopup() return progressDialog.done() del progressDialog gui.mainFrame.postPopup() gui.mainFrame.prePopup() dlg = storeGui.StoreDialog(gui.mainFrame, self.storeClient, self.addons) dlg.Show() gui.mainFrame.postPopup() del dlg
def updateAll(self): updated = 0 if len(self.updates) is 0: self.refreshAddons(True) if len(self.updates) == 0: ui.message(_(u"NVDAStore: No update available.")) return for update in self.updates: gui.mainFrame.prePopup() progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, _("NVDAStore"), _(u"Updating {name}...".format(name=update.name))) ui.message(_("Updating {name}".format(name=update.name))) try: gui.ExecAndPump(storeUtils.installAddon, self.storeClient, update, False, True) except: progressDialog.done() del progressDialog gui.mainFrame.postPopup() break progressDialog.done() del progressDialog updated += 1 gui.mainFrame.postPopup() if updated: core.restart()
def installAddon(self, addonPath, closeAfter=False): try: try: bundle=addonHandler.AddonBundle(addonPath) except: log.error("Error opening addon bundle from %s"%addonPath,exc_info=True) # Translators: The message displayed when an error occurs when opening an add-on package for adding. gui.messageBox(_("Failed to open add-on package file at %s - missing file or invalid file format")%addonPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return # Translators: A message asking the user if they really wish to install an addon. if gui.messageBox(_("Are you sure you want to install this add-on? Only install add-ons from trusted sources.\nAddon: {summary} {version}\nAuthor: {author}").format(**bundle.manifest), # Translators: Title for message asking if the user really wishes to install an Addon. _("Add-on Installation"), wx.YES|wx.NO|wx.ICON_WARNING)!=wx.YES: return bundleName=bundle.manifest['name'] prevAddon=None for addon in self.curAddons: if not addon.isPendingRemove and bundleName==addon.manifest['name']: prevAddon=addon break if prevAddon: # Translators: A message asking if the user wishes to update a previously installed add-on with this one. if gui.messageBox(_("A version of this add-on is already installed. Would you like to update it?"), # Translators: A title for the dialog asking if the user wishes to update a previously installed add-on with this one. _("Add-on Installation"), wx.YES|wx.NO|wx.ICON_WARNING)!=wx.YES: return prevAddon.requestRemove() progressDialog = gui.IndeterminateProgressDialog(gui.mainFrame, # Translators: The title of the dialog presented while an Addon is being installed. _("Installing Add-on"), # Translators: The message displayed while an addon is being installed. _("Please wait while the add-on is being installed.")) try: gui.ExecAndPump(addonHandler.installAddonBundle,bundle) except: log.error("Error installing addon bundle from %s"%addonPath,exc_info=True) self.refreshAddonsList() progressDialog.done() del progressDialog # Translators: The message displayed when an error occurs when installing an add-on package. gui.messageBox(_("Failed to install add-on from %s")%addonPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return else: self.refreshAddonsList(activeIndex=-1) progressDialog.done() del progressDialog finally: if closeAfter: # #4460: If we do this immediately, wx seems to drop the WM_QUIT sent if the user chooses to restart. # This seems to have something to do with the wx.ProgressDialog. # The CallLater seems to work around this. wx.CallLater(1, self.Close)
def deactivate(self, evt): progressDialog = gui.IndeterminateProgressDialog( self, _("Performing request"), _("Please wait while your license is being deactivated...")) try: success, message = watchdog.cancellableExecute( self.lib.DeactivateLicense) except: success = False message = _("There was a timeout while performing your request.") log.ERROR("Activation error", exc_info=True) if not success: wx.CallAfter( gui.messageBox, _("An error has occured:\n{error}").format(error=message), _("Error"), wx.OK | wx.ICON_ERROR) else: evt.Skip() wx.CallAfter( gui.messageBox, _("UnicornDVC has been deactivated!\nAdditional info: {message}" ).format(message=message), _("Congratulations!"), wx.OK | wx.ICON_EXCLAMATION) progressDialog.done()
def doCreatePortable(portableDirectory,copyUserConfig=False): d = gui.IndeterminateProgressDialog(gui.mainFrame, # Translators: The title of the dialog presented while a portable copy of NVDA is bieng created. _("Creating Portable Copy"), # Translators: The message displayed while a portable copy of NVDA is bieng created. _("Please wait while a portable copy of NVDA is created.")) try: gui.ExecAndPump(installer.createPortableCopy,portableDirectory,copyUserConfig) except Exception as e: log.error("Failed to create portable copy",exc_info=True) d.done() if isinstance(e,installer.RetriableFailure): # Translators: a message dialog asking to retry or cancel when NVDA portable copy creation fails message=_("NVDA is unable to remove or overwrite a file.") # Translators: the title of a retry cancel dialog when NVDA portable copy creation fails title=_("File in Use") if winUser.MessageBox(None,message,title,winUser.MB_RETRYCANCEL)==winUser.IDRETRY: return doCreatePortable(portableDirectory,copyUserConfig) # Translators: The message displayed when an error occurs while creating a portable copy of NVDA. # %s will be replaced with the specific error message. gui.messageBox(_("Failed to create portable copy: %s")%e, _("Error"), wx.OK | wx.ICON_ERROR) return d.done() # Translators: The message displayed when a portable copy of NVDA has been successfully created. # %s will be replaced with the destination directory. gui.messageBox(_("Successfully created a portable copy of NVDA at %s")%portableDirectory, _("Success"))
def _started(self): self._progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog displayed while manually checking for an NVDA update. _("Checking for Update"), # Translators: The progress message displayed while manually checking for an NVDA update. _("Checking for update"))
def doInstall(createDesktopShortcut,startOnLogon,copyPortableConfig,isUpdate,silent=False,startAfterInstall=True): progressDialog = gui.IndeterminateProgressDialog(gui.mainFrame, # Translators: The title of the dialog presented while NVDA is being updated. _("Updating NVDA") if isUpdate # Translators: The title of the dialog presented while NVDA is being installed. else _("Installing NVDA"), # Translators: The message displayed while NVDA is being updated. _("Please wait while your previous installation of NVDA is being updated.") if isUpdate # Translators: The message displayed while NVDA is being installed. else _("Please wait while NVDA is being installed")) try: res=config.execElevated(config.SLAVE_FILENAME,["install",str(int(createDesktopShortcut)),str(int(startOnLogon))],wait=True,handleAlreadyElevated=True) if res==2: raise installer.RetriableFailure if copyPortableConfig: installedUserConfigPath=config.getInstalledUserConfigPath() if installedUserConfigPath: gui.ExecAndPump(installer.copyUserConfig,installedUserConfigPath) except Exception as e: res=e log.error("Failed to execute installer",exc_info=True) progressDialog.done() del progressDialog if isinstance(res,installer.RetriableFailure): # Translators: a message dialog asking to retry or cancel when NVDA install fails message=_("The installation is unable to remove or overwrite a file. Another copy of NVDA may be running on another logged-on user account. Please make sure all installed copies of NVDA are shut down and try the installation again.") # Translators: the title of a retry cancel dialog when NVDA installation fails title=_("File in Use") if winUser.MessageBox(None,message,title,winUser.MB_RETRYCANCEL)==winUser.IDRETRY: return doInstall(createDesktopShortcut,startOnLogon,copyPortableConfig,isUpdate,silent,startAfterInstall) if res!=0: log.error("Installation failed: %s"%res) # Translators: The message displayed when an error occurs during installation of NVDA. gui.messageBox(_("The installation of NVDA failed. Please check the Log Viewer for more information."), # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return if not silent: msg = ( # Translators: The message displayed when NVDA has been successfully installed. _("Successfully installed NVDA. ") if not isUpdate # Translators: The message displayed when NVDA has been successfully updated. else _("Successfully updated your installation of NVDA. ")) # Translators: The message displayed to the user after NVDA is installed # and the installed copy is about to be started. gui.messageBox(msg+_("Please press OK to start the installed copy."), # Translators: The title of a dialog presented to indicate a successful operation. _("Success")) if startAfterInstall: # #4475: ensure that the first window of the new process is not hidden by providing SW_SHOWNORMAL shellapi.ShellExecute( None, None, os.path.join(installer.defaultInstallPath,'nvda.exe'), None, None, winUser.SW_SHOWNORMAL ) else: wx.GetApp().ExitMainLoop()
def activate(self, evt): if not self.key.Value: gui.messageBox(_("You must enter a valid license key."), _("Error"), wx.OK | wx.ICON_ERROR) self.key.SetFocus() return progressDialog = gui.IndeterminateProgressDialog( self, _("Performing request"), _("Please wait while your license is being activated...")) try: success, message = watchdog.cancellableExecute( self.lib.ActivateLicense, self.key.Value) except Exception: success = False message = _("There was an error while performing your request.") log.error("Activation error", exc_info=True) if not success: wx.CallAfter( gui.messageBox, _("An error has occured:\n{error}").format(error=message), _("Error"), wx.OK | wx.ICON_ERROR) else: evt.Skip() wx.CallAfter( gui.messageBox, _("UnicornDVC has been activated!\nAdditional info: {message}" ).format(message=message), _("Congratulations!"), wx.OK | wx.ICON_EXCLAMATION) progressDialog.done()
def onUpdateCheck(self, evt): self.onOk(None) global progressDialog progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while checking for add-on updates. _("Add-on update check"), # Translators: The message displayed while checking for newer version of WinTenApps add-on. _("Checking for new version of Windows 10 App Essentials add-on..." )) threading.Thread(target=addonUpdateCheck).start()
def onAddonUpdateCheck(evt): AddonUpdaterManualUpdateCheck.notify() global _progressDialog _progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while checking for add-on updates. _("Add-on update check"), # Translators: The message displayed while checking for add-on updates. _("Checking for add-on updates...")) t = threading.Thread(target=addonUpdateCheck) t.daemon = True t.start()
def onInstallMSRCommands(evt): dialog = gui.IndeterminateProgressDialog(gui.mainFrame, #Translators: Title for a dialog shown when Microsoft speech recognition Commands are being installed! _("Microsoft Speech Recognition Command Installation"), #Translators: Message shown in the progress dialog for MSR command installation. _("Please wait while microsoft speech recognition commands are installed.")) try: gui.ExecAndPump(_onInstallMSRCommands) except: #Catch all, because if this fails, bad bad bad. log.error("DictationBridge commands failed to install!", exc_info=True) finally: dialog.done()
def doCreatePortable(portableDirectory, copyUserConfig=False, silent=False, startAfterCreate=False): d = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while a portable copy of NVDA is bieng created. _("Creating Portable Copy"), # Translators: The message displayed while a portable copy of NVDA is bieng created. _("Please wait while a portable copy of NVDA is created.")) try: gui.ExecAndPump(installer.createPortableCopy, portableDirectory, copyUserConfig) except Exception as e: log.error("Failed to create portable copy", exc_info=True) d.done() if isinstance(e, installer.RetriableFailure): # Translators: a message dialog asking to retry or cancel when NVDA portable copy creation fails message = _("NVDA is unable to remove or overwrite a file.") # Translators: the title of a retry cancel dialog when NVDA portable copy creation fails title = _("File in Use") if winUser.MessageBox(None, message, title, winUser.MB_RETRYCANCEL) == winUser.IDRETRY: return doCreatePortable(portableDirectory, copyUserConfig, silent, startAfterCreate) # Translators: The message displayed when an error occurs while creating a portable copy of NVDA. # %s will be replaced with the specific error message. gui.messageBox( _("Failed to create portable copy: %s") % e, _("Error"), wx.OK | wx.ICON_ERROR) return d.done() if silent: wx.GetApp().ExitMainLoop() else: # Translators: The message displayed when a portable copy of NVDA has been successfully created. # %s will be replaced with the destination directory. gui.messageBox( _("Successfully created a portable copy of NVDA at %s") % portableDirectory, _("Success")) if startAfterCreate: # #4475: ensure that the first window of the new process is not hidden by providing SW_SHOWNORMAL shellapi.ShellExecute( None, None, os.path.join(os.path.abspath(portableDirectory), 'nvda.exe'), u"-r", None, winUser.SW_SHOWNORMAL)
def onInstallDragonCommands(evt): #Translators: Warning about having custom commands already. goAhead = gui.messageBox(_("If you are on a computer with shared commands, and you have multiple users using these commands, this will override them. Please do not proceed unless you are sure you aren't sharing commands over a network. if you are, please read \"Importing Commands Into a Shared System\" in the Dictation Bridge documentation for manual steps.\nDo you want to proceed?"), #Translators: Warning dialog title. _("Warning: Potentially Dangerous Opperation Will be Performed"), wx.YES|wx.NO) if goAhead==wx.NO: return dialog = gui.IndeterminateProgressDialog(gui.mainFrame, #Translators: Title for a dialog shown when Dragon Commands are being installed! _("Dragon Command Installation"), #Translators: Message shown in the progress dialog for dragon command installation. _("Please wait while Dragon commands are installed.")) try: gui.ExecAndPump(_onInstallDragonCommands) except: #Catch all, because if this fails, bad bad bad. log.error("DictationBridge commands failed to install!", exc_info=True) finally: dialog.done()
def _onSetLocalClick(self, evt): # Translators: The message displayed when the current source path is relative. if not path.isabs(self._ttsPath.GetValue()): # Translators: The message displayed when the current source path is relative. gui.messageBox(_("Relative paths are not allowed."), _("Error"), wx.OK|wx.ICON_ERROR, self) return # Translators: A message to ask the user to copy IBMTTS files to Add-on folder. if gui.messageBox(_("Are you sure to copy IBMTTS files to local NVDA driver Add-on? It may not work in some IBMTTS distributions."), # Translators: The title of the Asking dialog displayed when trying to copy IBMTTS files. _("Copy IBMTTS files"), wx.YES|wx.NO|wx.ICON_QUESTION, self) == wx.YES: progressDialog = gui.IndeterminateProgressDialog(gui.mainFrame, # Translators: The title of the dialog presented while IBMTTS files are being copied. _("Copying files"), # Translators: The message displayed while IBMTTS files are being copied. _("Please wait while IBMTTS files are copied into add-on.")) while True: try: gui.ExecAndPump(self.copyTtsFiles) res = True break except Exception: # Translators: a message dialog asking to retry or cancel when copying IBMTTS files. message=_("Unable to copy a file. Perhaps it is currently being used by another process or you have run out of disc space on the drive you are copying to.") # Translators: the title of a retry cancel dialog when copying IBMTTS files. title=_("Error Copying") if winUser.MessageBox(None,message,title,winUser.MB_RETRYCANCEL) != winUser.IDRETRY: res=False log.debugWarning("Error when copying IBMTTS files into Add-on",exc_info=True) break progressDialog.done() del progressDialog if res: self._ttsPath.SetValue("ibmtts") # this parameter is saved even if the user doesn't click accept button. config.conf['ibmeci']['TTSPath'] = self._ttsPath.GetValue() # Translators: The message displayed when copying IBMTTS files to Add-on was successful. gui.messageBox(_("Successfully copied IBMTTS files. The local copy will be used after restart NVDA."), # Translators: The title displayed when copying IBMTTS files to Add-on was successful. _("Success"),wx.OK|wx.ICON_INFORMATION,self) else: # Translators: The message displayed when errors were found while trying to copy IBMTTS files to Add-on. gui.messageBox(_("Error copying IBMTTS files"), _("Error"), wx.OK|wx.ICON_ERROR, self)
def onAddonUpdateCheck(evt): # If toast was shown, this will launch the results dialog directly as there is already update info. # Update info is valid only once, and this check will nullify it. from . import addonHandlerEx if addonHandlerEx._updateInfo is not None: wx.CallAfter(AddonUpdatesDialog, gui.mainFrame, dict(addonHandlerEx._updateInfo), auto=False) addonHandlerEx._updateInfo = None return AddonUpdaterManualUpdateCheck.notify() global _progressDialog _progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while checking for add-on updates. _("Add-on update check"), # Translators: The message displayed while checking for add-on updates. _("Checking for add-on updates...")) t = threading.Thread(target=addonUpdateCheck) t.daemon = True t.start()
def on_extend_password_list(self, evt): evt.Skip() if self.inDialog: # translators: text to indicate that another dialog is already open. gui.messageBox( _("Another dialog is already open; close it first!"), _("Cannot continue")) return self.load_password_list.Enable(False) self.extend_password_list.Enable(False) self.unload_password_list.Enable(False) # translators: the open file dialog for extending the password list. openfile = wx.FileDialog( parent=gui.mainFrame, message=_( "Select a password list to append to the list of currently loaded passwords (currently {} passwords)" .format(len(self.passwords))), defaultDir=_(""), defaultFile=_(""), wildcard=_("Password list files (*.txt)|.txt"), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) self.inDialog = True if openfile.ShowModal() == wx.ID_OK: self.inDialog = False # translators: strings to indicate the password list is being loaded. self.prog = gui.IndeterminateProgressDialog( gui.mainFrame, _("Loading password list"), _("Please wait while the password list is loaded.")) gui.ExecAndPump(self._load_list, openfile.GetPath()) self.prog.done() del self.prog # translators: text announced by NVDA when the password list is loaded. gui.messageBox(_("Password list loaded!"), _("Finished")) else: logHandler.log.error("Could not open password extender dialog") self.load_password_list.Enable(True) self.extend_password_list.Enable(True) self.unload_password_list.Enable(True)
def _downloadSuccess(self): self._stopped() # Emulate add-on update (don't prompt to install). from gui import addonGui closeAfter = addonGui.AddonsDialog._instance is None try: try: bundle = addonHandler.AddonBundle(self.destPath.decode("mbcs")) except: log.error("Error opening addon bundle from %s" % self.destPath, exc_info=True) # Translators: The message displayed when an error occurs when opening an add-on package for adding. gui.messageBox( _("Failed to open add-on package file at %s - missing file or invalid file format" ) % self.destPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return bundleName = bundle.manifest['name'] for addon in addonHandler.getAvailableAddons(): if not addon.isPendingRemove and bundleName == addon.manifest[ 'name']: addon.requestRemove() break progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while an Addon is being updated. _("Updating Add-on"), # Translators: The message displayed while an addon is being updated. _("Please wait while the add-on is being updated.")) try: gui.ExecAndPump(addonHandler.installAddonBundle, bundle) except: log.error("Error installing addon bundle from %s" % self.destPath, exc_info=True) if not closeAfter: addonGui.AddonsDialog(gui.mainFrame).refreshAddonsList() progressDialog.done() del progressDialog # Translators: The message displayed when an error occurs when installing an add-on package. gui.messageBox( _("Failed to update add-on from %s") % self.destPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return else: if not closeAfter: addonGui.AddonsDialog( gui.mainFrame).refreshAddonsList(activeIndex=-1) progressDialog.done() del progressDialog finally: try: os.remove(self.destPath) except OSError: pass if closeAfter: wx.CallLater(1, addonGui.AddonsDialog(gui.mainFrame).Close)
def _downloadSuccess(self): self._stopped() try: try: bundle = addonHandler.AddonBundle(self.destPath.decode("mbcs")) except AttributeError: bundle = addonHandler.AddonBundle(self.destPath) except: log.error("Error opening addon bundle from %s" % self.destPath, exc_info=True) # Translators: The message displayed when an error occurs when trying to update an add-on package due to package problems. gui.messageBox( _("Cannot update {name} - missing file or invalid file format" ).format(name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return # Check compatibility with NVDA and/or Windows release. import versionInfo minimumNVDAVersion = bundle.manifest.get("minimumNVDAVersion", None) if minimumNVDAVersion is None: minimumNVDAVersion = [ versionInfo.version_year, versionInfo.version_major ] lastTestedNVDAVersion = bundle.manifest.get( "lastTestedNVDAVersion", None) if lastTestedNVDAVersion is None: lastTestedNVDAVersion = [ versionInfo.version_year, versionInfo.version_major ] # For NVDA version, only version_year.version_major will be checked. minimumYear, minimumMajor = minimumNVDAVersion[:2] lastTestedYear, lastTestedMajor = lastTestedNVDAVersion[:2] if not ((minimumYear, minimumMajor) <= (versionInfo.version_year, versionInfo.version_major) <= (lastTestedYear, lastTestedMajor)): # Translators: The message displayed when trying to update an add-on that is not going to be compatible with the current version of NVDA. gui.messageBox( _("{name} add-on is not compatible with this version of NVDA. Minimum NVDA version: {minYear}.{minMajor}, last tested: {testedYear}.{testedMajor}." ).format(name=self.addonName, minYear=minimumYear, minMajor=minimumMajor, testedYear=lastTestedYear, testedMajor=lastTestedMajor), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return # Some add-ons require a specific Windows release or later. import winVersion minimumWindowsVersion = bundle.manifest.get( "minimumWindowsVersion", None) if minimumWindowsVersion is None: minimumWindowsVersion = winVersion.winVersion[:3] else: minimumWindowsVersion = [ int(data) for data in minimumWindowsVersion.split(".") ] minimumWinMajor, minimumWinMinor, minimumWinBuild = minimumWindowsVersion winMajor, winMinor, winBuild = winVersion.winVersion[:3] if (winMajor, winMinor, winBuild) < ( minimumWinMajor, minimumWinMinor, minimumWinBuild): # Translators: The message displayed when the add-on requires a newer version of Windows. gui.messageBox( _("{name} add-on is not compatible with this version of Windows." ).format(name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return bundleName = bundle.manifest['name'] isDisabled = False # Optimization (future): it is better to remove would-be add-ons all at once instead of doing it each time a bundle is opened. for addon in addonHandler.getAvailableAddons(): # Check for disabled state first. if bundleName == addon.manifest['name']: if addon.isDisabled: isDisabled = True if not addon.isPendingRemove: addon.requestRemove() break progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while an Addon is being updated. _("Updating {name}").format(name=self.addonName), # Translators: The message displayed while an addon is being updated. _("Please wait while the add-on is being updated.")) try: gui.ExecAndPump(addonHandler.installAddonBundle, bundle) except: log.error("Error installing addon bundle from %s" % self.destPath, exc_info=True) progressDialog.done() progressDialog.Hide() progressDialog.Destroy() # Translators: The message displayed when an error occurs when installing an add-on package. gui.messageBox( _("Failed to update {name} add-on").format( name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return else: progressDialog.done() progressDialog.Hide() progressDialog.Destroy() _updatedAddons.append(bundleName) if isDisabled: for addon in addonHandler.getAvailableAddons(): if bundleName == addon.manifest[ 'name'] and addon.isPendingInstall: addon.enable(False) break finally: try: os.remove(self.destPath) except OSError: pass self.continueUpdatingAddons()
def installAddon(storeClient, addon, closeAfter=False, silent=False): if silent == False: ui.message(_("Downloading %s") % (addon.name)) data = storeClient.getAddonFile(addon.id, addon.versionId) if data is None: if silent == False: ui.message(_("Unable to download the add-on.")) return False tmp = os.path.join(config.getUserDefaultConfigPath(), "storeDownloadedAddon.nvda-addon") logHandler.log.info(u"Saving to %s" % (tmp)) f = file(tmp, "wb") f.write(data) f.close() path = tmp if path is None: if silent == False: ui.message(_("Unable to download %s") % (addon.name)) return False if silent == False: ui.message(_("Installing")) try: bundle = addonHandler.AddonBundle(path) except: logHandler.log.error("Error opening addon bundle from %s" % path, exc_info=True) # Translators: The message displayed when an error occurs when opening an add-on package for adding. if silent == False: gui.messageBox( _("Failed to open add-on package file at %s - missing file or invalid file format" ) % path, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return False bundleName = bundle.manifest['name'] prevAddon = None for addon in addonHandler.getAvailableAddons(): if not addon.isPendingRemove and bundleName == addon.manifest['name']: prevAddon = addon break if prevAddon: prevAddon.requestRemove() if silent is False: progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while an Addon is being installed. _("Installing Add-on"), # Translators: The message displayed while an addon is being installed. _("Please wait while the add-on is being installed.")) try: gui.ExecAndPump(addonHandler.installAddonBundle, bundle) except: logHandler.log.error("Error installing addon bundle from %s" % addonPath, exc_info=True) progressDialog.done() del progressDialog # Translators: The message displayed when an error occurs when installing an add-on package. gui.messageBox( _("Failed to install add-on from %s") % (addon.name), # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return False progressDialog.done() del progressDialog else: try: addonHandler.installAddonBundle(bundle) except: return False if closeAfter: wx.CallLater(1, core.restart) return True
def installAddon(self, addonPath, closeAfter=False): try: try: bundle = addonHandler.AddonBundle(addonPath) except: log.error("Error opening addon bundle from %s" % addonPath, exc_info=True) gui.messageBox( # Translators: The message displayed when an error occurs when opening an add-on package for adding. _("Failed to open add-on package file at %s - missing file or invalid file format" ) % addonPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return if not addonVersionCheck.hasAddonGotRequiredSupport(bundle): self._showAddonRequiresNVDAUpdateDialog(bundle) return if not addonVersionCheck.isAddonTested(bundle): if wx.YES != self._showAddonUntestedDialog(bundle): return AddonCompatibilityState.setAddonCompatibility( addon=bundle, compatibilityStateValue=compatValues. MANUALLY_SET_COMPATIBLE) elif wx.YES != self._showConfirmAddonInstallDialog(bundle): return prevAddon = None for addon in self.curAddons: if not addon.isPendingRemove and bundle.name == addon.manifest[ 'name']: prevAddon = addon break if prevAddon: summary = bundle.manifest["summary"] curVersion = prevAddon.manifest["version"] newVersion = bundle.manifest["version"] if gui.messageBox( # Translators: A message asking if the user wishes to update an add-on with the same version currently installed according to the version number. _("You are about to install version {newVersion} of {summary}, which appears to be already installed. Would you still like to update?" ).format(summary=summary, newVersion=newVersion) if curVersion == newVersion else # Translators: A message asking if the user wishes to update a previously installed add-on with this one. _("A version of this add-on is already installed. Would you like to update {summary} version {curVersion} to version {newVersion}?" ).format(summary=summary, curVersion=curVersion, newVersion=newVersion), # Translators: A title for the dialog asking if the user wishes to update a previously installed add-on with this one. _("Add-on Installation"), wx.YES | wx.NO | wx.ICON_WARNING) != wx.YES: return prevAddon.requestRemove() progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while an Addon is being installed. _("Installing Add-on"), # Translators: The message displayed while an addon is being installed. _("Please wait while the add-on is being installed.")) try: gui.ExecAndPump(addonHandler.installAddonBundle, bundle) except: log.error("Error installing addon bundle from %s" % addonPath, exc_info=True) self.refreshAddonsList() progressDialog.done() del progressDialog # Translators: The message displayed when an error occurs when installing an add-on package. gui.messageBox( _("Failed to install add-on from %s") % addonPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return else: self.refreshAddonsList(activeIndex=-1) progressDialog.done() del progressDialog finally: if closeAfter: # #4460: If we do this immediately, wx seems to drop the WM_QUIT sent if the user chooses to restart. # This seems to have something to do with the wx.ProgressDialog. # The CallLater seems to work around this. wx.CallLater(1, self.Close)
def _downloadSuccess(self): self._stopped() try: try: bundle = addonHandler.AddonBundle(self.destPath) except: log.error(f"Error opening addon bundle from {self.destPath}", exc_info=True) gui.messageBox( # Translators: The message displayed when an error occurs # when trying to update an add-on package due to package problems. _("Cannot update {name} - missing file or invalid file format" ).format(name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return # NVDA itself will check add-on compatibility range. # As such, the below fragment was borrowed from NVDA Core (credit: NV Access). from addonHandler import addonVersionCheck from gui import addonGui if not addonVersionCheck.hasAddonGotRequiredSupport(bundle): addonGui._showAddonRequiresNVDAUpdateDialog( gui.mainFrame, bundle) self.continueUpdatingAddons() return elif not addonVersionCheck.isAddonTested(bundle): addonGui._showAddonTooOldDialog(gui.mainFrame, bundle) self.continueUpdatingAddons() return bundleName = bundle.manifest['name'] isDisabled = False # Optimization (future): it is better to remove would-be add-ons all at once # instead of doing it each time a bundle is opened. for addon in addonHandler.getAvailableAddons(): # Check for disabled state first. if bundleName == addon.manifest['name']: if addon.isDisabled: isDisabled = True if not addon.isPendingRemove: addon.requestRemove() break progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while an Addon is being updated. _("Updating {name}").format(name=self.addonName), # Translators: The message displayed while an addon is being updated. _("Please wait while the add-on is being updated.")) try: gui.ExecAndPump(addonHandler.installAddonBundle, bundle) except: log.error( f"Error installing addon bundle from {self.destPath}", exc_info=True) progressDialog.done() progressDialog.Hide() progressDialog.Destroy() gui.messageBox( # Translators: The message displayed when an error occurs when installing an add-on package. _("Failed to update {name} add-on").format( name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return else: progressDialog.done() progressDialog.Hide() progressDialog.Destroy() _updatedAddons.append(bundleName) if isDisabled: for addon in addonHandler.getAvailableAddons(): if bundleName == addon.manifest[ 'name'] and addon.isPendingInstall: addon.enable(False) break finally: try: os.remove(self.destPath) except OSError: pass self.continueUpdatingAddons()
def _downloadSuccess(self): def getBundle(): try: bundle = addonHandler.AddonBundle(self.destPath.decode("mbcs")) except AttributeError: bundle = addonHandler.AddonBundle(self.destPath) except Exception: log.error("Error opening addon bundle from %s" % self.destPath, exc_info=True) # Translators: The message displayed when an error occurs # when trying to update an add-on package due to package problems. gui.messageBox( # Translators: message to user _("Cannot update {name} - missing file or invalid file format" ).format(name=self.addonName), makeAddonWindowTitle(NVDAString("Error")), wx.OK | wx.ICON_ERROR) return None return bundle self._stopped() try: bundle = getBundle() if bundle is None: self.continueUpdatingAddons() return minimumNVDAVersion = bundle.manifest.get("minimumNVDAVersion", None) lastTestedNVDAVersion = bundle.manifest.get( "lastTestedNVDAVersion", None) bundleName = bundle.manifest['name'] if not checkCompatibility(bundleName, minimumNVDAVersion, lastTestedNVDAVersion): self.continueUpdatingAddons() return isDisabled = False # Optimization (future): # it is better to remove would-be add-ons all at once # instead of doing it each time a bundle is opened. for addon in addonHandler.getAvailableAddons(): # Check for disabled state first. if bundleName == addon.manifest['name']: if addon.isDisabled: isDisabled = True if not addon.isPendingRemove: addon.requestRemove() break progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog # presented while an Addon is being updated. makeAddonWindowTitle(_("Updating")), # Translators: The message displayed while an addon is being updated. _("Please wait while the add-on is being updated.")) try: if self.autoUpdate: extraAppArgs = globalVars.appArgsExtra if hasattr( globalVars, "appArgsExtra") else globalVars.unknownAppArgs extraAppArgs.append("addon-auto-update") gui.ExecAndPump(addonHandler.installAddonBundle, bundle) if self.autoUpdate: extraAppArgs.remove("addon-auto-update") except Exception: if self.autoUpdate: extraAppArgs.remove("addon-auto-update") log.error("Error installing addon bundle from %s" % self.destPath, exc_info=True) progressDialog.done() gui.messageBox( # Translators: The message displayed when an error occurs # when installing an add-on package. _("Failed to update {name} add-on").format( name=self.addonName), makeAddonWindowTitle(NVDAString("Error")), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return else: progressDialog.done() self.addonHasBeenUpdated = True if isDisabled: for addon in addonHandler.getAvailableAddons(): if bundleName == addon.manifest[ 'name'] and addon.isPendingInstall: addon.enable(False) break finally: try: os.remove(self.destPath) except OSError: pass if self.addonHasBeenUpdated: if gui.messageBox( NVDAString( "Changes were made to add-ons. " "You must restart NVDA for these changes to take effect. Would you like to restart now?" ), NVDAString("Restart NVDA"), wx.YES | wx.NO | wx.ICON_WARNING) == wx.YES: wx.CallAfter(core.restart) return self.continueUpdatingAddons()
def installAddon(parentWindow, addonPath): """ Installs the addon at path. Any error messages / warnings are presented to the user via a GUI message box. If attempting to install an addon that is pending removal, it will no longer be pending removal. :return True on success or False on failure. """ try: bundle = addonHandler.AddonBundle(addonPath) except: log.error("Error opening addon bundle from %s" % addonPath, exc_info=True) gui.messageBox( # Translators: The message displayed when an error occurs when opening an add-on package for adding. _("Failed to open add-on package file at %s - missing file or invalid file format" ) % addonPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return False # Exit early, can't install an invalid bundle if not addonVersionCheck.hasAddonGotRequiredSupport(bundle): _showAddonRequiresNVDAUpdateDialog(parentWindow, bundle) return False # Exit early, addon does not have required support elif not addonVersionCheck.isAddonTested(bundle): _showAddonTooOldDialog(parentWindow, bundle) return False # Exit early, addon is not up to date with the latest API version. elif wx.YES != _showConfirmAddonInstallDialog(parentWindow, bundle): return False # Exit early, User changed their mind about installation. prevAddon = None for addon in addonHandler.getAvailableAddons(): if not addon.isPendingRemove and bundle.name == addon.manifest['name']: prevAddon = addon break if prevAddon: summary = bundle.manifest["summary"] curVersion = prevAddon.manifest["version"] newVersion = bundle.manifest["version"] # Translators: A title for the dialog asking if the user wishes to update a previously installed # add-on with this one. messageBoxTitle = _("Add-on Installation") # Translators: A message asking if the user wishes to update an add-on with the same version # currently installed according to the version number. overwriteExistingAddonInstallationMessage = _( "You are about to install version {newVersion} of {summary}, which appears to be already installed. " "Would you still like to update?").format(summary=summary, newVersion=newVersion) # Translators: A message asking if the user wishes to update a previously installed add-on with this one. updateAddonInstallationMessage = _( "A version of this add-on is already installed. " "Would you like to update {summary} version {curVersion} to version {newVersion}?" ).format(summary=summary, curVersion=curVersion, newVersion=newVersion) if gui.messageBox( overwriteExistingAddonInstallationMessage if curVersion == newVersion else updateAddonInstallationMessage, messageBoxTitle, wx.YES | wx.NO | wx.ICON_WARNING) != wx.YES: return False prevAddon.requestRemove() from contextlib import contextmanager @contextmanager def doneAndDestroy(window): try: yield window except: # pass on any exceptions raise finally: # but ensure that done and Destroy are called. window.done() window.Destroy() # use a progress dialog so users know that something is happening. progressDialog = gui.IndeterminateProgressDialog( parentWindow, # Translators: The title of the dialog presented while an Addon is being installed. _("Installing Add-on"), # Translators: The message displayed while an addon is being installed. _("Please wait while the add-on is being installed.")) try: # Use context manager to ensure that `done` and `Destroy` are called on the progress dialog afterwards with doneAndDestroy(progressDialog): gui.ExecAndPump(addonHandler.installAddonBundle, bundle) return True except: log.error("Error installing addon bundle from %s" % addonPath, exc_info=True) gui.messageBox( # Translators: The message displayed when an error occurs when installing an add-on package. _("Failed to install add-on from %s") % addonPath, # Translators: The title of a dialog presented when an error occurs. _("Error"), wx.OK | wx.ICON_ERROR) return False
def _downloadSuccess(self): self._stopped() try: try: bundle = addonHandler.AddonBundle(self.destPath) except: log.error(f"Error opening addon bundle from {self.destPath}", exc_info=True) gui.messageBox( # Translators: The message displayed when an error occurs # when trying to update an add-on package due to package problems. _("Cannot update {name} - missing file or invalid file format" ).format(name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return # Check compatibility with NVDA and/or Windows release. # NVDA itself will check add-on compatibility range. # As such, the below fragment was borrowed from NVDA Core (credit: NV Access). from addonHandler import addonVersionCheck from gui import addonGui # Check compatibility with NVDA and/or Windows release. if not addonVersionCheck.hasAddonGotRequiredSupport(bundle): addonGui._showAddonRequiresNVDAUpdateDialog( gui.mainFrame, bundle) self.continueUpdatingAddons() return elif not addonVersionCheck.isAddonTested(bundle): addonGui._showAddonTooOldDialog(gui.mainFrame, bundle) self.continueUpdatingAddons() return # Some add-ons require a specific Windows release or later. # Prepare for winVersion.getWinVer function. import winVersion minimumWindowsVersion = bundle.manifest.get( "minimumWindowsVersion", None) if hasattr(winVersion, "getWinVer"): if minimumWindowsVersion is None: minimumWindowsVersion = winVersion.getWinVer() else: minimumWindowsVersion = winVersion.WinVersion.fromVersionText( minimumWindowsVersion) winVersionUnsupported = winVersion.getWinVer( ) < minimumWindowsVersion else: if minimumWindowsVersion is None: minimumWindowsVersion = winVersion.winVersion[:3] else: minimumWindowsVersion = [ int(data) for data in minimumWindowsVersion.split(".") ] minimumWinMajor, minimumWinMinor, minimumWinBuild = minimumWindowsVersion winMajor, winMinor, winBuild = winVersion.winVersion[:3] winVersionUnsupported = (winMajor, winMinor, winBuild) < ( minimumWinMajor, minimumWinMinor, minimumWinBuild) if winVersionUnsupported: gui.messageBox( # Translators: The message displayed when the add-on requires a newer version of Windows. _("{name} add-on is not compatible with this version of Windows." ).format(name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return bundleName = bundle.manifest['name'] isDisabled = False # Optimization (future): it is better to remove would-be add-ons all at once # instead of doing it each time a bundle is opened. for addon in addonHandler.getAvailableAddons(): # Check for disabled state first. if bundleName == addon.manifest['name']: if addon.isDisabled: isDisabled = True if not addon.isPendingRemove: addon.requestRemove() break progressDialog = gui.IndeterminateProgressDialog( gui.mainFrame, # Translators: The title of the dialog presented while an Addon is being updated. _("Updating {name}").format(name=self.addonName), # Translators: The message displayed while an addon is being updated. _("Please wait while the add-on is being updated.")) try: gui.ExecAndPump(addonHandler.installAddonBundle, bundle) except: log.error( f"Error installing addon bundle from {self.destPath}", exc_info=True) progressDialog.done() progressDialog.Hide() progressDialog.Destroy() gui.messageBox( # Translators: The message displayed when an error occurs when installing an add-on package. _("Failed to update {name} add-on").format( name=self.addonName), translate("Error"), wx.OK | wx.ICON_ERROR) self.continueUpdatingAddons() return else: progressDialog.done() progressDialog.Hide() progressDialog.Destroy() _updatedAddons.append(bundleName) if isDisabled: for addon in addonHandler.getAvailableAddons(): if bundleName == addon.manifest[ 'name'] and addon.isPendingInstall: addon.enable(False) break finally: try: os.remove(self.destPath) except OSError: pass self.continueUpdatingAddons()