OSDN Git Service

Installation changes:
authorMichael Curran <mick@kulgan.net>
Fri, 6 Jan 2012 02:46:45 +0000 (12:46 +1000)
committerMichael Curran <mick@kulgan.net>
Fri, 6 Jan 2012 02:46:45 +0000 (12:46 +1000)
* 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.

source/gui/__init__.py
source/gui/installerGui.py
source/installer.py
source/nvda_slave.pyw

index 7909365..bf0c846 100644 (file)
@@ -237,8 +237,12 @@ class MainFrame(wx.Frame):
                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
@@ -296,8 +300,9 @@ class SysTrayIcon(wx.TaskBarIcon):
                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
index 4c0e2a2..913b45a 100644 (file)
@@ -3,6 +3,7 @@ import ctypes
 import wx\r
 import config\r
 import versionInfo\r
+import installer\r
 import gui\r
 \r
 class InstallerDialog(wx.Dialog):\r
@@ -23,7 +24,7 @@ class InstallerDialog(wx.Dialog):
 \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
@@ -32,7 +33,7 @@ class InstallerDialog(wx.Dialog):
 \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
@@ -69,6 +70,12 @@ class InstallerDialog(wx.Dialog):
                                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
@@ -78,6 +85,34 @@ class InstallerDialog(wx.Dialog):
        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
@@ -99,7 +134,6 @@ def createPortableCopy():
                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
index 36ae195..9d93503 100644 (file)
@@ -8,6 +8,7 @@ import tempfile
 import shutil\r
 import shellapi\r
 import languageHandler\r
+import config\r
 import versionInfo\r
 from logHandler import log\r
 \r
@@ -19,13 +20,17 @@ def _getWSH():
                _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
@@ -38,15 +43,36 @@ def createShortcut(path,targetPath=None,arguments=None,iconLocation=None,working
                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
@@ -162,19 +188,17 @@ def unregisterInstallation(forUpdate=False):
                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
@@ -184,7 +208,8 @@ def unregisterInstallation(forUpdate=False):
                        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
@@ -201,6 +226,9 @@ def install(installDir,startMenuFolder,shouldInstallService=True,shouldCreateDes
                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
index 1488e55..9b06dbf 100755 (executable)
@@ -22,6 +22,9 @@ def main():
                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