* Added installer.update() which Updates the installed copy of NVDA to the current version being run.
* gui: Added an UpdaterDialog which contains an update button, which calls installer.update to update the currently installed NVDA. The "install NVDA..." item in the tools menu now will show the update dialog rather than the install dialog, if a previous copy of NVDA is installed.
* installer.py: Added a few useful functions such as getStartMenuFolder, getInstallPath, validateStartMenuFolder and validateInstallPath. These are now used by the installer GUI to collect default/current installer values.
* installer.py: install only now calls unregisterInstallation if forUpdate is true. Otherwize we expect there is no previous install and or the previous install has already been uninstalled.
* installer.unregisterInstallation: don't remove individual startMenu shortcuts, instead just delete all shortcuts in NVDA's startMenu folder, as this is wht the old uninstaller used to do.
* installer.registerInstallation: fix a typo that was stopping start menu shortcuts from being created.
if isInMessageBox:\r
return\r
self.prePopup()\r
- from gui.installerGui import InstallerDialog\r
- InstallerDialog(self).Show()\r
+ from gui.installerGui import InstallerDialog, UpdaterDialog\r
+ import installer\r
+ if installer.isPreviousInstall():\r
+ UpdaterDialog(self).Show()\r
+ else:\r
+ InstallerDialog(self).Show()\r
self.postPopup()\r
\r
class SysTrayIcon(wx.TaskBarIcon):\r
if not globalVars.appArgs.secure and getattr(sys,'frozen',None):\r
item = menu_tools.Append(wx.ID_ANY, _("Create Portable copy..."))\r
self.Bind(wx.EVT_MENU, frame.onCreatePortableCopyCommand, item)\r
- item = menu_tools.Append(wx.ID_ANY, _("&Install NVDA..."))\r
- self.Bind(wx.EVT_MENU, frame.onInstallCommand, item)\r
+ if not config.isInstalledCopy():\r
+ item = menu_tools.Append(wx.ID_ANY, _("&Install NVDA..."))\r
+ self.Bind(wx.EVT_MENU, frame.onInstallCommand, item)\r
item = menu_tools.Append(wx.ID_ANY, _("Reload plugins"))\r
self.Bind(wx.EVT_MENU, frame.onReloadPluginsCommand, item)\r
self.menu.AppendMenu(wx.ID_ANY, _("Tools"), menu_tools)\r
import wx\r
import config\r
import versionInfo\r
+import installer\r
import gui\r
\r
class InstallerDialog(wx.Dialog):\r
\r
sizer = wx.StaticBoxSizer(wx.StaticBox(self, label=_("Install &to folder:")), wx.HORIZONTAL)\r
# FIXME: Don't use os.getenv to get the path to Program Files.\r
- ctrl = self.programFolderEdit = wx.TextCtrl(self, value=os.path.join(unicode(os.getenv("ProgramFiles")), versionInfo.name))\r
+ ctrl = self.programFolderEdit = wx.TextCtrl(self, value=installer.getInstallPath())\r
sizer.Add(ctrl)\r
ctrl = wx.Button(self, label=_("Browse..."))\r
ctrl.Bind(wx.EVT_BUTTON, self.onBrowseForProgramFolder)\r
\r
sizer = wx.BoxSizer(wx.HORIZONTAL)\r
sizer.Add(wx.StaticText(self, label=_("&Start Menu folder:")))\r
- ctrl = self.startMenuFolderEdit = wx.TextCtrl(self, value=versionInfo.name)\r
+ ctrl = self.startMenuFolderEdit = wx.TextCtrl(self, value=installer.getStartMenuFolder())\r
sizer.Add(ctrl)\r
advancedSizer.Add(sizer)\r
\r
self.programFolderEdit.Value = d.Path\r
\r
def onInstall(self, evt):\r
+ if not installer.validateStartMenuFolder(self.startMenuFolderEdit.Value):\r
+ gui.messageBox(_("Start menu folder already exists, please choose another name."), _("Invalid start menu folder"), wx.OK|wx.ICON_WARNING)\r
+ return\r
+ if not installer.validateInstallPath(self.programFolderEdit.Value):\r
+ gui.messageBox(_("NVDA cannot be installed to %s, please choose another location.")%self.programFolderEdit.value, _("Invalid program folder"), wx.OK|wx.ICON_WARNING)\r
+ return\r
self.Hide()\r
self.progressDialog = IndeterminateProgressDialog(self, _("Installing NVDA"), _("Please wait while NVDA is being installed."))\r
config.execElevated(config.SLAVE_FILENAME,["install",self.programFolderEdit.Value,self.startMenuFolderEdit.Value,str(int(self.installServiceCheckbox.Value)),str(int(self.createDesktopShortcutCheckbox.Value)),str(int(self.startOnLogonCheckbox.Value))],wait=True)\r
def onCancel(self, evt):\r
self.Destroy()\r
\r
+class UpdaterDialog(wx.Dialog):\r
+\r
+ def __init__(self, parent):\r
+ super(UpdaterDialog, self).__init__(parent, title=_("Update NVDA"))\r
+ mainSizer = self.mainSizer = wx.BoxSizer(wx.VERTICAL)\r
+\r
+ sizer = wx.BoxSizer(wx.HORIZONTAL)\r
+ ctrl = wx.Button(self, label=_("&Update"), id=wx.ID_OK)\r
+ ctrl.Bind(wx.EVT_BUTTON, self.onUpdate)\r
+ sizer.Add(ctrl)\r
+ sizer.Add(wx.Button(self, id=wx.ID_CANCEL))\r
+ # If we bind this using button.Bind, it fails to trigger when the dialog is closed.\r
+ self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL)\r
+ mainSizer.Add(sizer)\r
+\r
+ self.Sizer = mainSizer\r
+\r
+ def onUpdate(self, evt):\r
+ self.Hide()\r
+ self.progressDialog = IndeterminateProgressDialog(self, _("Updating NVDA installation"), _("Please wait while NVDA is being updated."))\r
+ config.execElevated(config.SLAVE_FILENAME,["updateInstall"],wait=True)\r
+ self.progressDialog.done()\r
+ self.Destroy()\r
+\r
+ def onCancel(self, evt):\r
+ self.Destroy()\r
+\r
+\r
class IndeterminateProgressDialog(wx.ProgressDialog):\r
\r
def __init__(self, parent, title, message):\r
createAutorun=(ctypes.windll.kernel32.GetDriveTypeW(os.path.splitdrive(path)[0]+u'\\')==2 and gui.messageBox(_("Would you like to create an autorun file for your removable drive to allow NVDA to start automatically?"), _("Removable Drive Detected"), wx.YES_NO|wx.ICON_QUESTION) == wx.YES)\r
\r
d = IndeterminateProgressDialog(gui.mainFrame, _("Creating Portable Copy"), _("Please wait while a portable copy of NVDA is created."))\r
- import installer\r
try:\r
installer.CreatePortableCopy(path,copyUserConfig=copyUserConfig,createAutorun=createAutorun)\r
except OSError:\r
import shutil\r
import shellapi\r
import languageHandler\r
+import config\r
import versionInfo\r
from logHandler import log\r
\r
_wsh=comtypes.client.CreateObject("wScript.Shell",dynamic=True)\r
return _wsh\r
\r
+defaultStartMenuFolder=versionInfo.name\r
+defaultInstallPath=os.path.join(unicode(os.getenv("ProgramFiles")), versionInfo.name)\r
+\r
def createShortcut(path,targetPath=None,arguments=None,iconLocation=None,workingDirectory=None,hotkey=None,prependSpecialFolder=None):\r
wsh=_getWSH()\r
if prependSpecialFolder:\r
specialPath=wsh.SpecialFolders(prependSpecialFolder)\r
path=os.path.join(specialPath,path)\r
+ log.info("Creating shortcut at %s"%path)\r
if not os.path.isdir(os.path.dirname(path)):\r
- os.makedirs(path)\r
+ os.makedirs(os.path.dirname(path))\r
short=wsh.CreateShortcut(path)\r
short.TargetPath=targetPath\r
if arguments:\r
short.workingDirectory=workingDirectory\r
short.Save()\r
\r
-def deleteShortcut(path,prependSpecialFolder=None):\r
- wsh=_getWSH()\r
- if prependSpecialFolder:\r
- specialPath=wsh.SpecialFolders(prependSpecialFolder)\r
- path=os.path.join(specialPath,path)\r
+def getStartMenuFolder(noDefault=False):\r
try:\r
- os.remove(path)\r
- except OSError:\r
- pass\r
+ with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,u"SOFTWARE\\NVDA") as k:\r
+ return _winreg.QueryValueEx(k,u"Start Menu Folder")[0]\r
+ except WindowsError:\r
+ return defaultStartMenuFolder if not noDefault else None\r
+\r
+def getInstallPath(noDefault=False):\r
+ try:\r
+ k=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\NVDA")\r
+ return _winreg.QueryValueEx(k,"UninstallDirectory")[0]\r
+ except WindowsError:\r
+ return defaultInstallPath if not noDefault else None\r
+\r
+def isPreviousInstall():\r
+ return bool(getInstallPath(True))\r
+\r
+def validateStartMenuFolder(startMenuFolder):\r
+ if startMenuFolder==getStartMenuFolder():\r
+ return True\r
+ wsh=_getWSH()\r
+ specialPath=wsh.SpecialFolders("AllUsersPrograms")\r
+ oldStartMenuFolder=getStartMenuFolder(True)\r
+ startMenuPath=os.path.join(specialPath,startMenuFolder)\r
+ return (oldStartMenuFolder and os.stat(startMenuPath)==os.stat(os.path.join(specialPath,oldStartMenuFolder))) or (not os.path.isfile(startMenuPath) and not os.path.isdir(startMenuPath))\r
+\r
+def validateInstallPath(installPath):\r
+ if installPath==defaultInstallPath:\r
+ return True\r
+ return False\r
\r
def getDocFilePath(fileName,installDir):\r
rootPath=os.path.join(installDir,'documentation')\r
nvda_service.removeService()\r
except:\r
pass\r
- deleteShortcut(u"nvda.lnk",prependSpecialFolder="AllUsersDesktop")\r
- try:\r
- with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,u"SOFTWARE\\NVDA") as k:\r
- startMenuFolder=_winreg.QueryValueEx(k,u"startMenuFolder")[0]\r
- except WindowsError:\r
- startMenuFolder=None\r
+ wsh=_getWSH()\r
+ if not forUpdate:\r
+ desktopPath=wsh.SpecialFolders("AllUsersDesktop")\r
+ try:\r
+ os.remove(os.path.join(desktopPath,"nvda.lnk"))\r
+ except WindowsError:\r
+ pass\r
+ startMenuFolder=getStartMenuFolder()\r
if startMenuFolder:\r
- deleteShortcut(os.path.join(startMenuFolder,"NVDA.lnk"),prependSpecialFolder="AllUsersPrograms")\r
- deleteShortcut(os.path.join(startMenuFolder,_("NVDA Website")+".lnk"),prependSpecialFolder="AllUsersPrograms")\r
- deleteShortcut(os.path.join(startMenuFolder,_("Uninstall NVDA")+".lnk"),prependSpecialFolder="AllUsersPrograms")\r
- deleteShortcut(os.path.join(startMenuFolder,_("Explore NVDA user configuration directory")+".lnk"),prependSpecialFolder="AllUsersPrograms")\r
- deleteShortcut(os.path.join(startMenuFolder,_("Documentation"),_("Key Command quick reference")+".lnk"),prependSpecialFolder="AllUsersPrograms")\r
- deleteShortcut(os.path.join(startMenuFolder,_("Documentation"),_("User Guide")+".lnk"),prependSpecialFolder="AllUsersPrograms")\r
+ programsPath=wsh.SpecialFolders("AllUsersPrograms")\r
+ shutil.rmtree(os.path.join(programsPath,startMenuFolder))\r
if not forUpdate:\r
try:\r
_winreg.DeleteKeyEx(_winreg.HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\nvda",0,0)\r
pass\r
\r
def install(installDir,startMenuFolder,shouldInstallService=True,shouldCreateDesktopShortcut=True,shouldRunAtLogon=None,forUpdate=False):\r
- unregisterInstallation(forUpdate)\r
+ if forUpdate:\r
+ unregisterInstallation(forUpdate)\r
#Remove all the main executables always\r
for f in ("nvda.exe","nvda_noUIAccess.exe","nvda_UIAccess.exe"):\r
f=os.path.join(installDir,f)\r
raise RuntimeError("No available executable to use as nvda.exe")\r
registerInstallation(installDir,startMenuFolder,shouldInstallService,shouldCreateDesktopShortcut,shouldRunAtLogon)\r
\r
+def update():\r
+ install(getInstallPath(),getStartMenuFolder(),shouldInstallService=config.isServiceInstalled())\r
+\r
autorunTemplate="""[AutoRun]\r
open={exe}\r
action={name} {version}\r
elif action=="install":\r
import installer\r
installer.install(args[0],args[1],bool(int(args[2])),bool(int(args[3])),bool(int(args[4])))\r
+ elif action=="updateInstall":\r
+ import installer\r
+ installer.update()\r
elif action=="launchNVDA":\r
import subprocess\r
import shellapi\r