/
installerGui.py
306 lines (279 loc) · 14.6 KB
/
installerGui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#gui/installerGui.py
#A part of NonVisual Desktop Access (NVDA)
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
#Copyright (C) 2011-2018 NV Access Limited, Babbage B.v.
import os
import ctypes
import shellapi
import winUser
import wx
import config
import globalVars
import versionInfo
import installer
from logHandler import log
import gui
from gui import guiHelper
import tones
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'),
u"-r",
None, winUser.SW_SHOWNORMAL)
else:
wx.GetApp().ExitMainLoop()
def doSilentInstall(startAfterInstall=True):
prevInstall=installer.comparePreviousInstall() is not None
startOnLogon=False if globalVars.appArgs.disableStartOnLogon else config.getStartOnLogonScreen() if prevInstall else True
doInstall(
installer.isDesktopShortcutInstalled() if prevInstall else True,
startOnLogon,
False,
prevInstall,
silent=True,
startAfterInstall=startAfterInstall
)
class InstallerDialog(wx.Dialog):
def __init__(self, parent, isUpdate):
self.isUpdate=isUpdate
# Translators: The title of the Install NVDA dialog.
super(InstallerDialog, self).__init__(parent, title=_("Install NVDA"))
mainSizer = self.mainSizer = wx.BoxSizer(wx.VERTICAL)
sHelper = gui.guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL)
# Translators: An informational message in the Install NVDA dialog.
msg=_("To install NVDA to your hard drive, please press the Continue button.")
if self.isUpdate:
# Translators: An informational message in the Install NVDA dialog.
msg+=" "+_("A previous copy of NVDA has been found on your system. This copy will be updated.")
if not os.path.isdir(installer.defaultInstallPath):
# Translators: a message in the installer telling the user NVDA is now located in a different place.
msg+=" "+_("The installation path for NVDA has changed. it will now be installed in {path}").format(path=installer.defaultInstallPath)
sHelper.addItem(wx.StaticText(self,label=msg))
# Translators: The label of a checkbox option in the Install NVDA dialog.
startOnLogonText = _("Use NVDA on the Windows &logon screen")
self.startOnLogonCheckbox = sHelper.addItem(wx.CheckBox(self, label=startOnLogonText))
self.startOnLogonCheckbox.Value = (
False if globalVars.appArgs.disableStartOnLogon else
config.getStartOnLogonScreen() if self.isUpdate else True
)
shortcutIsPrevInstalled=installer.isDesktopShortcutInstalled()
if self.isUpdate and shortcutIsPrevInstalled:
# Translators: The label of a checkbox option in the Install NVDA dialog.
keepShortCutText = _("&Keep existing desktop shortcut")
self.createDesktopShortcutCheckbox = sHelper.addItem(wx.CheckBox(self, label=keepShortCutText))
else:
# Translators: The label of the option to create a desktop shortcut in the Install NVDA dialog.
# If the shortcut key has been changed for this locale,
# this change must also be reflected here.
createShortcutText = _("Create &desktop icon and shortcut key (control+alt+n)")
self.createDesktopShortcutCheckbox = sHelper.addItem(wx.CheckBox(self, label=createShortcutText))
self.createDesktopShortcutCheckbox.Value = shortcutIsPrevInstalled if self.isUpdate else True
# Translators: The label of a checkbox option in the Install NVDA dialog.
createPortableText = _("Copy &portable configuration to current user account")
self.copyPortableConfigCheckbox = sHelper.addItem(wx.CheckBox(self, label=createPortableText))
self.copyPortableConfigCheckbox.Value = False
if globalVars.appArgs.launcher:
self.copyPortableConfigCheckbox.Disable()
bHelper = sHelper.addDialogDismissButtons(guiHelper.ButtonHelper(wx.HORIZONTAL))
# Translators: The label of a button to continue with the operation.
continueButton = bHelper.addButton(self, label=_("&Continue"), id=wx.ID_OK)
continueButton.SetDefault()
continueButton.Bind(wx.EVT_BUTTON, self.onInstall)
bHelper.addButton(self, id=wx.ID_CANCEL)
# If we bind this using button.Bind, it fails to trigger when the dialog is closed.
self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL)
mainSizer.Add(sHelper.sizer, border=guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL)
self.Sizer = mainSizer
mainSizer.Fit(self)
self.CentreOnScreen()
def onInstall(self, evt):
self.Hide()
doInstall(self.createDesktopShortcutCheckbox.Value,self.startOnLogonCheckbox.Value,self.copyPortableConfigCheckbox.Value,self.isUpdate)
self.Destroy()
def onCancel(self, evt):
self.Destroy()
def showInstallGui():
gui.mainFrame.prePopup()
previous = installer.comparePreviousInstall()
if previous > 0:
# The existing installation is newer, which means this will be a downgrade.
# Translators: The title of a warning dialog.
d = wx.Dialog(gui.mainFrame, title=_("Warning"))
mainSizer = wx.BoxSizer(wx.VERTICAL)
item = wx.StaticText(d,
# Translators: A warning presented when the user attempts to downgrade NVDA
# to an older version.
label=_("You are attempting to install an earlier version of NVDA than the version currently installed. "
"If you really wish to revert to an earlier version, you should first cancel this installation and completely uninstall NVDA before installing the earlier version."))
mainSizer.Add(item)
sizer = wx.BoxSizer(wx.HORIZONTAL)
item = wx.Button(d, id=wx.ID_OK,
# Translators: The label of a button to proceed with installation,
# even though this is not recommended.
label=_("&Proceed with installation (not recommended)"))
sizer.Add(item)
item = wx.Button(d, id=wx.ID_CANCEL)
sizer.Add(item)
item.SetFocus()
mainSizer.Add(sizer)
d.Sizer = mainSizer
mainSizer.Fit(d)
d.CentreOnScreen()
with d:
if d.ShowModal() == wx.ID_CANCEL:
gui.mainFrame.postPopup()
return
InstallerDialog(gui.mainFrame, previous is not None).Show()
gui.mainFrame.postPopup()
class PortableCreaterDialog(wx.Dialog):
def __init__(self, parent):
# Translators: The title of the Create Portable NVDA dialog.
super(PortableCreaterDialog, self).__init__(parent, title=_("Create Portable NVDA"))
mainSizer = self.mainSizer = wx.BoxSizer(wx.VERTICAL)
sHelper = gui.guiHelper.BoxSizerHelper(self, orientation=wx.VERTICAL)
# Translators: An informational message displayed in the Create Portable NVDA dialog.
dialogCaption=_("To create a portable copy of NVDA, please select the path and other options and then press Continue")
sHelper.addItem(wx.StaticText(self, label=dialogCaption))
# Translators: The label of a grouping containing controls to select the destination directory
# in the Create Portable NVDA dialog.
directoryGroupText = _("Portable &directory:")
groupHelper = sHelper.addItem(gui.guiHelper.BoxSizerHelper(self, sizer=wx.StaticBoxSizer(wx.StaticBox(self, label=directoryGroupText), wx.VERTICAL)))
# Translators: The label of a button to browse for a directory.
browseText = _("Browse...")
# Translators: The title of the dialog presented when browsing for the
# destination directory when creating a portable copy of NVDA.
dirDialogTitle = _("Select portable directory")
directoryEntryControl = groupHelper.addItem(gui.guiHelper.PathSelectionHelper(self, browseText, dirDialogTitle))
self.portableDirectoryEdit = directoryEntryControl.pathControl
if globalVars.appArgs.portablePath:
self.portableDirectoryEdit.Value = os.path.abspath(globalVars.appArgs.portablePath)
# Translators: The label of a checkbox option in the Create Portable NVDA dialog.
copyConfText = _("Copy current &user configuration")
self.copyUserConfigCheckbox = sHelper.addItem(wx.CheckBox(self, label=copyConfText))
self.copyUserConfigCheckbox.Value = False
if globalVars.appArgs.launcher:
self.copyUserConfigCheckbox.Disable()
# Translators: The label of a checkbox option in the Create Portable NVDA dialog.
startAfterCreateText = _("&Start the new portable copy after creation")
self.startAfterCreateCheckbox = sHelper.addItem(wx.CheckBox(self, label=startAfterCreateText))
self.startAfterCreateCheckbox.Value = False
bHelper = sHelper.addDialogDismissButtons(gui.guiHelper.ButtonHelper(wx.HORIZONTAL))
continueButton = bHelper.addButton(self, label=_("&Continue"), id=wx.ID_OK)
continueButton.SetDefault()
continueButton.Bind(wx.EVT_BUTTON, self.onCreatePortable)
bHelper.addButton(self, id=wx.ID_CANCEL)
# If we bind this using button.Bind, it fails to trigger when the dialog is closed.
self.Bind(wx.EVT_BUTTON, self.onCancel, id=wx.ID_CANCEL)
mainSizer.Add(sHelper.sizer, border=gui.guiHelper.BORDER_FOR_DIALOGS, flag=wx.ALL)
self.Sizer = mainSizer
mainSizer.Fit(self)
self.CentreOnScreen()
def onCreatePortable(self, evt):
if not self.portableDirectoryEdit.Value:
# Translators: The message displayed when the user has not specified a destination directory
# in the Create Portable NVDA dialog.
gui.messageBox(_("Please specify a directory in which to create the portable copy."),
_("Error"),
wx.OK | wx.ICON_ERROR)
return
drv=os.path.splitdrive(self.portableDirectoryEdit.Value)[0]
if drv and not os.path.isdir(drv):
# Translators: The message displayed when the user specifies an invalid destination drive
# in the Create Portable NVDA dialog.
gui.messageBox(_("Invalid drive %s")%drv,
_("Error"),
wx.OK | wx.ICON_ERROR)
return
self.Hide()
doCreatePortable(self.portableDirectoryEdit.Value,self.copyUserConfigCheckbox.Value,False,self.startAfterCreateCheckbox.Value)
self.Destroy()
def onCancel(self, evt):
self.Destroy()
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(unicode(portableDirectory)),'nvda.exe'),
u"-r",
None, winUser.SW_SHOWNORMAL)