source: src/mlx/gui/update.py@ 37:a9637d8e2ea0

Last change on this file since 37:a9637d8e2ea0 was 37:a9637d8e2ea0, checked in by István Váradi <ivaradi@…>, 12 years ago

The MLXMANIFEST is generated when creating the distribution and files to be removed are really removed.

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