source: src/mlx/gui/update.py@ 36:f79362793664

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

Update seems to work

File size: 10.7 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 """Called when the downloading of the files has started."""
161 self._numToModifyAndNew = numToModifyAndNew
162 self._numModifiedOrNew = 0
163 self._totalSize = totalSize
164 self._downloaded = 0
165 self._numToRemove = numToRemove
166 self._numRemoved = 0
167
168 self._totalProgress = self._totalSize + \
169 (self._numToModifyAndNew + self._numToRemove) * \
170 Updater.REMOVE2BYTES
171 self._waitAfterFinish = self._totalProgress > 0
172
173 def _startDownload(self):
174 """Called when the download has started."""
175 self._progressLabel.set_text("Downloading files...")
176
177 def setDownloaded(self, downloaded):
178 """Called when a certain number of bytes are downloaded."""
179 self._downloaded = downloaded
180 gobject.idle_add(self._setDownloaded, downloaded)
181
182 def _setDownloaded(self, downloaded):
183 """Called when a certain number of bytes are downloaded."""
184 self._progressLabel.set_text("Downloaded %d of %d" % \
185 (downloaded, self._totalSize))
186 self._setProgress()
187
188 def startRenaming(self):
189 """Called when the renaming of files has started."""
190 gobject.idle_add(self._startRenaming)
191
192 def _startRenaming(self):
193 """Called when the renaming of files has started."""
194 self._progressLabel.set_text("Renaming downloaded files...")
195
196 def renamed(self, path, count):
197 """Called when a file has been renamed."""
198 self._numModifiedOrNew = count
199 gobject.idle_add(self._renamed, path, count)
200
201 def _renamed(self, path, count):
202 """Called when a file has been renamed."""
203 self._progressLabel.set_text("Renamed %s" % (path,))
204 self._setProgress()
205
206 def startRemoving(self):
207 """Called when the removing of files has started."""
208 gobject.idle_add(self._startRemoving)
209
210 def _startRemoving(self):
211 """Called when the removing of files has started."""
212 self._progressLabel.set_text("Removing files...")
213
214 def removed(self, path, count):
215 """Called when a file has been removed."""
216 self._numRemoved = count
217 gobject.idle_add(self._removed, path, count)
218
219 def _removed(self, path, count):
220 """Called when a file has been removed."""
221 self._progressLabel.set_text("Removed %s" % (path,))
222 self._setProgress()
223
224 def writingManifest(self):
225 """Called when the writing of the new manifest file has started."""
226 gobject.idle_add(self._writingManifest)
227
228 def _writingManifest(self):
229 """Called when the writing of the new manifest file has started."""
230 self._progressLabel.set_text("Writing the new manifest")
231
232 def done(self):
233 """Called when the update has been done."""
234 gobject.idle_add(self._done)
235 self._restart = self._totalProgress>0
236
237 def _done(self):
238 """Called when the writing of the new manifest file has started."""
239 self._progressBar.set_fraction(1)
240 if self._totalProgress>0:
241 self._progressLabel.set_text("Finished updating. Press OK to restart the program.")
242 self._progressOKButton.set_sensitive(True)
243 else:
244 self._progressLabel.set_text("There was nothing to update")
245
246 def _setProgress(self):
247 """Set the progress bar based on the current stage."""
248 if self._totalProgress>0:
249 progress = self._downloaded + \
250 (self._numModifiedOrNew + self._numRemoved) * \
251 Updater.REMOVE2BYTES
252 self._progressBar.set_fraction(0.05 + 0.94 * progress / self._totalProgress)
253
254 def failed(self, what):
255 """Called when the downloading has failed."""
256 self._waitAfterFinish = True
257 gobject.idle_add(self._failed, what)
258
259 def _failed(self, what):
260 """Called when the downloading has failed."""
261 self._progressLabel.set_text("Failed, see the debug log for details.")
262 self._progressBar.set_fraction(1)
263 self._progressOKButton.set_sensitive(True)
264
265 def _startUpdate(self):
266 """Start the update.
267
268 It resets the GUI elements."""
269 self._progressLabel.set_text("")
270 self._progressBar.set_fraction(0)
271 self._progressWindow.show_all()
272 self._progressOKButton.set_sensitive(False)
273 self._progressOKButton.connect("clicked", self._progressOKClicked)
274
275 def _progressOKClicked(self, button):
276 """Called when the OK button on the progress window is clicked."""
277 self._progressWindow.hide()
278 if self._restart:
279 restart()
280
281#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.