source: src/mlx/gui/update.py@ 981:3fa8c08f4b8f

Last change on this file since 981:3fa8c08f4b8f was 755:2b64e14287fc, checked in by István Váradi <ivaradi@…>, 9 years ago

Added a check for any signs of a previous running of the program, and if none found, a question about registration (re #285)

File size: 10.9 KB
Line 
1
2from mlx.gui.common import *
3
4from mlx.update import update
5from mlx.i18n import xstr
6
7import mlx.const as const
8
9import threading
10import os
11import sys
12
13#-------------------------------------------------------------------------------
14
15## @package mlx.gui.update
16#
17# The GUI part of the update.
18#
19# This module implements the GUI portion of the \ref mlx.update
20# "automatic update" function. The update runs in a separate thread, which puts
21# the relevant events into the Gtk event loop.
22
23#-------------------------------------------------------------------------------
24
25class Updater(threading.Thread):
26 """The updater thread."""
27
28 # The removal or renaming of one file equals to the downloading of this
29 # many bytes in time (for the progress calculation)
30 REMOVE2BYTES = 100
31
32 _progressWindow = None
33
34 _progressLabel = None
35
36 _progressBar = None
37
38 _progressOKButton = None
39
40 _sudoDialog = None
41
42 @staticmethod
43 def _createGUI(parentWindow):
44 """Create the GUI elements, if needed."""
45 if Updater._progressWindow is not None:
46 return
47
48 Updater._progressWindow = window = gtk.Window()
49 window.set_title(WINDOW_TITLE_BASE + " " + xstr("update_title"))
50 window.set_transient_for(parentWindow)
51 #win.set_icon_from_file(os.path.join(iconDirectory, "logo.ico"))
52 window.set_size_request(400, -1)
53 window.set_resizable(False)
54 window.set_modal(True)
55 window.connect("delete-event", lambda a, b: True)
56 window.set_deletable(False)
57 window.set_position(gtk.WindowPosition.CENTER_ON_PARENT if pygobject
58 else gtk.WIN_POS_CENTER_ON_PARENT)
59
60 mainAlignment = gtk.Alignment(xscale = 1.0)
61 mainAlignment.set_padding(padding_top = 4, padding_bottom = 10,
62 padding_left = 16, padding_right = 16)
63 window.add(mainAlignment)
64
65 mainVBox = gtk.VBox()
66 mainAlignment.add(mainVBox)
67
68 labelAlignment = gtk.Alignment(xalign = 0.0, xscale = 0.0)
69 Updater._progressLabel = progressLabel = gtk.Label()
70 labelAlignment.add(progressLabel)
71 mainVBox.pack_start(labelAlignment, True, True, 4)
72
73 Updater._progressBar = progressBar = gtk.ProgressBar()
74 mainVBox.pack_start(progressBar, True, True, 4)
75
76 buttonAlignment = gtk.Alignment(xalign = 0.5, xscale = 0.1)
77 Updater._progressOKButton = progressOKButton = gtk.Button("OK")
78 buttonAlignment.add(progressOKButton)
79 mainVBox.pack_start(buttonAlignment, True, True, 4)
80
81 Updater._sudoDialog = sudoDialog = \
82 gtk.Dialog(WINDOW_TITLE_BASE + " " + xstr("update_title"),
83 parentWindow,
84 gtk.DialogFlags.MODAL if pygobject else gtk.DIALOG_MODAL)
85 sudoDialog.add_button(xstr("button_cancel"), 0)
86 sudoDialog.add_button(xstr("button_ok"), 1)
87
88 infoLabelAlignment = gtk.Alignment(xalign = 0.5, xscale = 0.1)
89 infoLabelAlignment.set_padding(padding_top = 4, padding_bottom = 10,
90 padding_left = 16, padding_right = 16)
91
92 infoLabel = gtk.Label(xstr("update_needsudo"))
93 infoLabel.set_justify(gtk.Justification.CENTER if pygobject
94 else gtk.JUSTIFY_CENTER)
95 infoLabelAlignment.add(infoLabel)
96 sudoDialog.vbox.pack_start(infoLabelAlignment, True, True, 4)
97
98 sudoDialog.set_position(gtk.WindowPosition.CENTER_ON_PARENT if pygobject
99 else gtk.WIN_POS_CENTER_ON_PARENT)
100
101 def __init__(self, gui, programDirectory, updateURL, parentWindow):
102 """Construct the updater. If not created yet, the windows used by the
103 updater are also created."""
104 super(Updater, self).__init__()
105
106 self._gui = gui
107
108 self._programDirectory = programDirectory
109 self._updateURL = updateURL
110
111 self._totalProgress = 0
112 self._waitAfterFinish = False
113 self._restart = False
114
115 self._sudoReply = None
116 self._sudoCondition = threading.Condition()
117
118 Updater._createGUI(parentWindow)
119
120 def run(self):
121 """Execute the thread's operation."""
122 gobject.idle_add(self._startUpdate)
123 update(self._programDirectory, self._updateURL, self, fromGUI = True)
124 if not self._waitAfterFinish:
125 gobject.idle_add(self._progressWindow.hide)
126 self._gui.updateDone()
127
128 def downloadingManifest(self):
129 """Called when the downloading of the manifest has started."""
130 gobject.idle_add(self._downloadingManifest)
131
132 def _downloadingManifest(self):
133 """Called when the downloading of the manifest has started."""
134 self._progressLabel.set_text(xstr("update_manifest_progress"))
135 self._progressBar.set_fraction(0)
136
137 def downloadedManifest(self):
138 """Called when the downloading of the manifest has finished."""
139 gobject.idle_add(self._downloadedManifest)
140
141 def _downloadedManifest(self):
142 """Called when the downloading of the manifest has finished."""
143 self._progressLabel.set_text(xstr("update_manifest_done"))
144 self._progressBar.set_fraction(0.05)
145
146 def needSudo(self):
147 """Called when the program is interested in whether we want to run a
148 program with administrator rights to do the update."""
149 gobject.idle_add(self._needSudo)
150 with self._sudoCondition:
151 while self._sudoReply is None:
152 self._sudoCondition.wait(1)
153 return self._sudoReply
154
155 def _needSudo(self):
156 """Called when the program is interested in whether we want to run a
157 program with administrator rights to do the update."""
158 self._sudoDialog.show_all()
159 result = self._sudoDialog.run()
160 self._sudoDialog.hide()
161 with self._sudoCondition:
162 self._sudoReply = result!=0
163 self._sudoCondition.notify()
164
165 def setTotalSize(self, numToModifyAndNew, totalSize, numToRemove,
166 numToRemoveLocal):
167 """Called when the downloading of the files has started."""
168 self._numToModifyAndNew = numToModifyAndNew
169 self._numModifiedOrNew = 0
170 self._totalSize = totalSize
171 self._downloaded = 0
172 self._numToRemove = numToRemove
173 self._numToRemoveLocal = numToRemoveLocal
174 self._numRemoved = 0
175
176 self._totalProgress = self._totalSize + \
177 (self._numToModifyAndNew + \
178 self._numToRemove + self._numToRemoveLocal) * \
179 Updater.REMOVE2BYTES
180 self._waitAfterFinish = self._totalSize > 0 or self._numToRemove > 0
181
182 def _startDownload(self):
183 """Called when the download has started."""
184 self._progressLabel.set_text(xstr("update_files_progress"))
185
186 def setDownloaded(self, downloaded):
187 """Called when a certain number of bytes are downloaded."""
188 self._downloaded = downloaded
189 gobject.idle_add(self._setDownloaded, downloaded)
190
191 def _setDownloaded(self, downloaded):
192 """Called when a certain number of bytes are downloaded."""
193 self._progressLabel.set_text(xstr("update_files_bytes") % \
194 (downloaded, self._totalSize))
195 self._setProgress()
196
197 def startRenaming(self):
198 """Called when the renaming of files has started."""
199 gobject.idle_add(self._startRenaming)
200
201 def _startRenaming(self):
202 """Called when the renaming of files has started."""
203 self._progressLabel.set_text(xstr("update_renaming"))
204
205 def renamed(self, path, count):
206 """Called when a file has been renamed."""
207 self._numModifiedOrNew = count
208 gobject.idle_add(self._renamed, path, count)
209
210 def _renamed(self, path, count):
211 """Called when a file has been renamed."""
212 self._progressLabel.set_text(xstr("update_renamed") % (path,))
213 self._setProgress()
214
215 def startRemoving(self):
216 """Called when the removing of files has started."""
217 gobject.idle_add(self._startRemoving)
218
219 def _startRemoving(self):
220 """Called when the removing of files has started."""
221 self._progressLabel.set_text(xstr("update_removing"))
222
223 def removed(self, path, count):
224 """Called when a file has been removed."""
225 self._numRemoved = count
226 gobject.idle_add(self._removed, path, count)
227
228 def _removed(self, path, count):
229 """Called when a file has been removed."""
230 self._progressLabel.set_text(xstr("update_removed") % (path,))
231 self._setProgress()
232
233 def writingManifest(self):
234 """Called when the writing of the new manifest file has started."""
235 gobject.idle_add(self._writingManifest)
236
237 def _writingManifest(self):
238 """Called when the writing of the new manifest file has started."""
239 self._progressLabel.set_text(xstr("update_writing_manifest"))
240
241 def done(self):
242 """Called when the update has been done."""
243 gobject.idle_add(self._done)
244 self._restart = self._waitAfterFinish
245
246 def _done(self):
247 """Called when the writing of the new manifest file has started."""
248 self._progressBar.set_fraction(1)
249 if self._totalProgress>0:
250 self._progressLabel.set_text(xstr("update_finished"))
251 self._progressOKButton.set_sensitive(True)
252 else:
253 self._progressLabel.set_text(xstr("update_nothing"))
254
255 def _setProgress(self):
256 """Set the progress bar based on the current stage."""
257 if self._totalProgress>0:
258 progress = self._downloaded + \
259 (self._numModifiedOrNew + self._numRemoved) * \
260 Updater.REMOVE2BYTES
261 self._progressBar.set_fraction(0.05 + 0.94 * progress / self._totalProgress)
262
263 def failed(self, what):
264 """Called when the downloading has failed."""
265 self._waitAfterFinish = True
266 gobject.idle_add(self._failed, what)
267
268 def _failed(self, what):
269 """Called when the downloading has failed."""
270 self._progressLabel.set_text(xstr("update_failed"))
271 self._progressBar.set_fraction(1)
272 self._progressOKButton.set_sensitive(True)
273
274 def _startUpdate(self):
275 """Start the update.
276
277 It resets the GUI elements."""
278 self._progressLabel.set_text("")
279 self._progressBar.set_fraction(0)
280 self._progressWindow.show_all()
281 self._progressOKButton.set_sensitive(False)
282 self._progressOKButton.connect("clicked", self._progressOKClicked)
283
284 def _progressOKClicked(self, button):
285 """Called when the OK button on the progress window is clicked."""
286 self._progressWindow.hide()
287 if self._restart:
288 self._gui.restart()
289 else:
290 self._gui.updateDone()
291
292#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.