def test_addonCompat_addonRequiresNewFeature(self):
		"""Test an addon that has just been developed, requiring an API feature introduced in the current release."""
		addon = mockAddon(minAPIVersion=latestVersionTuple, lastTestedAPIVersion=latestVersionTuple)
		nvda_current, nvda_backwardsCompatTo = latestVersionTuple, previousVersionTuple
		self.assertTrue(addonVersionCheck.hasAddonGotRequiredSupport(addon, nvda_current))
		self.assertTrue(addonVersionCheck.isAddonTested(addon, nvda_backwardsCompatTo))
		self.assertTrue(addonVersionCheck.isAddonCompatible(addon, nvda_current, nvda_backwardsCompatTo))
Exemplo n.º 2
0
	def refreshAddonsList(self,activeIndex=0):
		self.addonsList.DeleteAllItems()
		self.curAddons=[]
		shouldEnableIncompatAddonsButton = False
		for addon in addonHandler.getAvailableAddons():
			self.addonsList.Append((
				addon.manifest['summary'],
				self.getAddonStatus(addon),
				addon.manifest['version'],
				addon.manifest['author']
			))
			self.curAddons.append(addon)
			shouldEnableIncompatAddonsButton = (
				shouldEnableIncompatAddonsButton or (
					addonVersionCheck.hasAddonGotRequiredSupport(addon, version=addonVersionCheck.CURRENT_NVDA_VERSION)
					and not addonVersionCheck.isAddonTested(addon, version=addonVersionCheck.CURRENT_NVDA_VERSION)
				)
			)
		self.incompatAddonsButton.Enable(shouldEnableIncompatAddonsButton)
		# select the given active addon or the first addon if not given
		curAddonsLen=len(self.curAddons)
		if curAddonsLen>0:
			if activeIndex==-1:
				activeIndex=curAddonsLen-1
			elif activeIndex<0 or activeIndex>=curAddonsLen:
				activeIndex=0
			self.addonsList.Select(activeIndex,on=1)
			self.addonsList.SetItemState(activeIndex,wx.LIST_STATE_FOCUSED,wx.LIST_STATE_FOCUSED)
		else:
			self.aboutButton.Disable()
			self.helpButton.Disable()
			self.removeButton.Disable()
Exemplo n.º 3
0
 def test_addonWithUpToDateTesting(self):
     uptoDate = mockAddon()
     self.assertTrue(
         addonVersionCheck.hasAddonGotRequiredSupport(
             uptoDate, CurrentNVDAVersionTuple))
     self.assertTrue(
         addonVersionCheck.isAddonTested(uptoDate, CurrentNVDAVersionTuple))
	def test_addonCompat_testedAgainstLastBackwardsCompatVersion(self):
		"""Test an addon has been maintained and tested against the backwardsCompatTo version."""
		addon = mockAddon(minAPIVersion=oldVersionTuple, lastTestedAPIVersion=previousVersionTuple)
		nvda_current, nvda_backwardsCompatTo = latestVersionTuple, previousVersionTuple
		self.assertTrue(addonVersionCheck.hasAddonGotRequiredSupport(addon, nvda_current))
		self.assertTrue(addonVersionCheck.isAddonTested(addon, nvda_backwardsCompatTo))
		self.assertTrue(addonVersionCheck.isAddonCompatible(addon, nvda_current, nvda_backwardsCompatTo))
Exemplo n.º 5
0
 def refreshAddonsList(self, activeIndex=0):
     self.addonsList.DeleteAllItems()
     self.curAddons = []
     shouldEnableIncompatAddonsButton = False
     for addon in addonHandler.getAvailableAddons():
         self.addonsList.Append(
             (addon.manifest['summary'], self.getAddonStatus(addon),
              addon.manifest['version'], addon.manifest['author']))
         self.curAddons.append(addon)
         shouldEnableIncompatAddonsButton = (
             shouldEnableIncompatAddonsButton or
             (addonVersionCheck.hasAddonGotRequiredSupport(
                 addon, version=addonVersionCheck.CURRENT_NVDA_VERSION)
              and not addonVersionCheck.isAddonTested(
                  addon, version=addonVersionCheck.CURRENT_NVDA_VERSION)))
     self.incompatAddonsButton.Enable(shouldEnableIncompatAddonsButton)
     # select the given active addon or the first addon if not given
     curAddonsLen = len(self.curAddons)
     if curAddonsLen > 0:
         if activeIndex == -1:
             activeIndex = curAddonsLen - 1
         elif activeIndex < 0 or activeIndex >= curAddonsLen:
             activeIndex = 0
         self.addonsList.Select(activeIndex, on=1)
         self.addonsList.SetItemState(activeIndex, wx.LIST_STATE_FOCUSED,
                                      wx.LIST_STATE_FOCUSED)
     else:
         self.aboutButton.Disable()
         self.helpButton.Disable()
         self.removeButton.Disable()
Exemplo n.º 6
0
 def test_addonMissingLastTestedField(self):
     addonNoLastTested = mockAddon(lastTestedNVDAVersion=None)
     self.assertTrue(
         addonVersionCheck.hasAddonGotRequiredSupport(
             addonNoLastTested, CurrentNVDAVersionTuple))
     self.assertFalse(
         addonVersionCheck.isAddonTested(addonNoLastTested,
                                         CurrentNVDAVersionTuple))
Exemplo n.º 7
0
 def test_addonUntestedWithSupport(self):
     addonNotTested = mockAddon(lastTestedNVDAVersion=LastNVDAVersionString)
     self.assertTrue(
         addonVersionCheck.hasAddonGotRequiredSupport(
             addonNotTested, CurrentNVDAVersionTuple))
     self.assertFalse(
         addonVersionCheck.isAddonTested(addonNotTested,
                                         CurrentNVDAVersionTuple))
Exemplo n.º 8
0
 def test_addonMissingNVDASupportField(self):
     addonNoMinNVDAVer = mockAddon(minNVDAVersion=None)
     self.assertTrue(
         addonVersionCheck.hasAddonGotRequiredSupport(
             addonNoMinNVDAVer, CurrentNVDAVersionTuple))
     self.assertTrue(
         addonVersionCheck.isAddonTested(addonNoMinNVDAVer,
                                         CurrentNVDAVersionTuple))
	def test_addonCompat_attemptingToUseAddonRequiringNewAPIFeaturesWithOldNVDA(self):
		"""Test that is considered incompatible if a user tries to install a new addon with an old version of NVDA"""
		# addon requires API features in the future release
		addon = mockAddon(minAPIVersion=nextVersionTuple, lastTestedAPIVersion=nextVersionTuple)
		nvda_current, nvda_backwardsCompatTo = latestVersionTuple, previousVersionTuple
		self.assertFalse(addonVersionCheck.hasAddonGotRequiredSupport(addon, latestVersionTuple))
		self.assertTrue(addonVersionCheck.isAddonTested(addon, latestVersionTuple))
		self.assertFalse(addonVersionCheck.isAddonCompatible(addon, nvda_current, nvda_backwardsCompatTo))
Exemplo n.º 10
0
 def test_addonWithoutNVDASupportTested(self):
     addonNvdaDoesntSupport = mockAddon(
         minNVDAVersion=NextNVDAVersionString)
     self.assertFalse(
         addonVersionCheck.hasAddonGotRequiredSupport(
             addonNvdaDoesntSupport, CurrentNVDAVersionTuple))
     self.assertFalse(
         addonVersionCheck.isAddonTested(addonNvdaDoesntSupport,
                                         CurrentNVDAVersionTuple))
	def test_addonCompat_lastTestedAgainstNowNoLongerSupportedAPIVersion(self):
		"""Test an addon is considered incompatible if the backwards compatible to version is moved forward for an addon
		that has not been updated."""
		addon = mockAddon(minAPIVersion=oldVersionTuple, lastTestedAPIVersion=previousVersionTuple)
		# NVDA backwards compatible to has been moved forward one version:
		nvda_current, nvda_backwardsCompatTo = latestVersionTuple, latestVersionTuple
		self.assertTrue(addonVersionCheck.hasAddonGotRequiredSupport(addon, nvda_current))
		self.assertFalse(addonVersionCheck.isAddonTested(addon, nvda_backwardsCompatTo))
		self.assertFalse(addonVersionCheck.isAddonCompatible(addon, nvda_current, nvda_backwardsCompatTo))
Exemplo n.º 12
0
	def _getIncompatReason(self, addon):
		if not addonVersionCheck.hasAddonGotRequiredSupport(
			addon,
			currentAPIVersion=self._APIVersion
		):
			# Translators: The reason an add-on is not compatible. A more recent version of NVDA is
			# required for the add-on to work. The placeholder will be replaced with Year.Major.Minor (EG 2019.1).
			return _("An updated version of NVDA is required. NVDA version {} or later."
			).format(addonAPIVersion.formatForGUI(addon.minimumNVDAVersion))
		elif not addonVersionCheck.isAddonTested(
			addon,
			backwardsCompatToVersion=self._APIBackwardsCompatToVersion
		):
			# Translators: The reason an add-on is not compatible. The addon relies on older, removed features of NVDA,
			# an updated add-on is required. The placeholder will be replaced with Year.Major.Minor (EG 2019.1).
			return _("An updated version of this add-on is required. The minimum supported API version is now {}"
			).format(addonAPIVersion.formatForGUI(self._APIBackwardsCompatToVersion))
Exemplo n.º 13
0
	def _getIncompatReason(self, addon):
		if not addonVersionCheck.hasAddonGotRequiredSupport(
			addon,
			currentAPIVersion=self._APIVersion
		):
			# Translators: The reason an add-on is not compatible. A more recent version of NVDA is
			# required for the add-on to work. The placeholder will be replaced with Year.Major.Minor (EG 2019.1).
			return _("An updated version of NVDA is required. NVDA version {} or later."
			).format(addonAPIVersion.formatForGUI(addon.minimumNVDAVersion))
		elif not addonVersionCheck.isAddonTested(
			addon,
			backwardsCompatToVersion=self._APIBackwardsCompatToVersion
		):
			# Translators: The reason an add-on is not compatible. The addon relies on older, removed features of NVDA,
			# an updated add-on is required. The placeholder will be replaced with Year.Major.Minor (EG 2019.1).
			return _("An updated version of this add-on is required. The minimum supported API version is now {}"
			).format(addonAPIVersion.formatForGUI(self._APIBackwardsCompatToVersion))
Exemplo n.º 14
0
 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()
Exemplo n.º 15
0
 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()
Exemplo n.º 16
0
	def test_addonWithUpToDateTesting(self):
		uptoDate = mockAddon()
		self.assertTrue(addonVersionCheck.hasAddonGotRequiredSupport(uptoDate, CurrentNVDAVersionTuple))
		self.assertTrue(addonVersionCheck.isAddonTested(uptoDate, CurrentNVDAVersionTuple))
Exemplo n.º 17
0
	def test_addonUntestedWithSupport(self):
		addonNotTested = mockAddon(lastTestedNVDAVersion=LastNVDAVersionString)
		self.assertTrue(addonVersionCheck.hasAddonGotRequiredSupport(addonNotTested, CurrentNVDAVersionTuple))
		self.assertFalse(addonVersionCheck.isAddonTested(addonNotTested, CurrentNVDAVersionTuple))
Exemplo n.º 18
0
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
Exemplo n.º 19
0
	def test_addonWithoutNVDASupportUntested(self):
		addonNvdaDoesntSupport = mockAddon(minNVDAVersion=NextNVDAVersionString, lastTestedNVDAVersion=LastNVDAVersionString)
		self.assertFalse(addonVersionCheck.hasAddonGotRequiredSupport(addonNvdaDoesntSupport, CurrentNVDAVersionTuple))
		self.assertFalse(addonVersionCheck.isAddonTested(addonNvdaDoesntSupport, CurrentNVDAVersionTuple))
Exemplo n.º 20
0
	def test_addonMissingNVDASupportField(self):
		addonNoMinNVDAVer = mockAddon(minNVDAVersion=None)
		self.assertTrue(addonVersionCheck.hasAddonGotRequiredSupport(addonNoMinNVDAVer, CurrentNVDAVersionTuple))
		self.assertTrue(addonVersionCheck.isAddonTested(addonNoMinNVDAVer, CurrentNVDAVersionTuple))
Exemplo n.º 21
0
	def test_addonMissingLastTestedField(self):
		addonNoLastTested = mockAddon(lastTestedNVDAVersion=None)
		self.assertTrue(addonVersionCheck.hasAddonGotRequiredSupport(addonNoLastTested, CurrentNVDAVersionTuple))
		self.assertFalse(addonVersionCheck.isAddonTested(addonNoLastTested, CurrentNVDAVersionTuple))
Exemplo n.º 22
0
	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)
Exemplo n.º 23
0
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
Exemplo n.º 24
0
    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)