source: src/mlx/gui/update.py@ 357:95a02e0c97d3

Last change on this file since 357:95a02e0c97d3 was 300:f101bd18f39d, checked in by István Váradi <ivaradi@…>, 12 years ago

Added the module comments for the GUI

File size: 10.8 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
127 def downloadingManifest(self):
128 """Called when the downloading of the manifest has started."""
129 gobject.idle_add(self._downloadingManifest)
130
131 def _downloadingManifest(self):
132 """Called when the downloading of the manifest has started."""
133 self._progressLabel.set_text(xstr("update_manifest_progress"))
134 self._progressBar.set_fraction(0)
135
136 def downloadedManifest(self):
137 """Called when the downloading of the manifest has finished."""
138 gobject.idle_add(self._downloadedManifest)
139
140 def _downloadedManifest(self):
141 """Called when the downloading of the manifest has finished."""
142 self._progressLabel.set_text(xstr("update_manifest_done"))
143 self._progressBar.set_fraction(0.05)
144
145 def needSudo(self):
146 """Called when the program is interested in whether we want to run a
147 program with administrator rights to do the update."""
148 gobject.idle_add(self._needSudo)
149 with self._sudoCondition:
150 while self._sudoReply is None:
151 self._sudoCondition.wait(1)
152 return self._sudoReply
153
154 def _needSudo(self):
155 """Called when the program is interested in whether we want to run a
156 program with administrator rights to do the update."""
157 self._sudoDialog.show_all()
158 result = self._sudoDialog.run()
159 self._sudoDialog.hide()
160 with self._sudoCondition:
161 self._sudoReply = result!=0
162 self._sudoCondition.notify()
163
164 def setTotalSize(self, numToModifyAndNew, totalSize, numToRemove,
165 numToRemoveLocal):
166 """Called when the downloading of the files has started."""
167 self._numToModifyAndNew = numToModifyAndNew
168 self._numModifiedOrNew = 0
169 self._totalSize = totalSize
170 self._downloaded = 0
171 self._numToRemove = numToRemove
172 self._numToRemoveLocal = numToRemoveLocal
173 self._numRemoved = 0
174
175 self._totalProgress = self._totalSize + \
176 (self._numToModifyAndNew + \
177 self._numToRemove + self._numToRemoveLocal) * \
178 Updater.REMOVE2BYTES
179 self._waitAfterFinish = self._totalSize > 0 or self._numToRemove > 0
180
181 def _startDownload(self):
182 """Called when the download has started."""
183 self._progressLabel.set_text(xstr("update_files_progress"))
184
185 def setDownloaded(self, downloaded):
186 """Called when a certain number of bytes are downloaded."""
187 self._downloaded = downloaded
188 gobject.idle_add(self._setDownloaded, downloaded)
189
190 def _setDownloaded(self, downloaded):
191 """Called when a certain number of bytes are downloaded."""
192 self._progressLabel.set_text(xstr("update_files_bytes") % \
193 (downloaded, self._totalSize))
194 self._setProgress()
195
196 def startRenaming(self):
197 """Called when the renaming of files has started."""
198 gobject.idle_add(self._startRenaming)
199
200 def _startRenaming(self):
201 """Called when the renaming of files has started."""
202 self._progressLabel.set_text(xstr("update_renaming"))
203
204 def renamed(self, path, count):
205 """Called when a file has been renamed."""
206 self._numModifiedOrNew = count
207 gobject.idle_add(self._renamed, path, count)
208
209 def _renamed(self, path, count):
210 """Called when a file has been renamed."""
211 self._progressLabel.set_text(xstr("update_renamed") % (path,))
212 self._setProgress()
213
214 def startRemoving(self):
215 """Called when the removing of files has started."""
216 gobject.idle_add(self._startRemoving)
217
218 def _startRemoving(self):
219 """Called when the removing of files has started."""
220 self._progressLabel.set_text(xstr("update_removing"))
221
222 def removed(self, path, count):
223 """Called when a file has been removed."""
224 self._numRemoved = count
225 gobject.idle_add(self._removed, path, count)
226
227 def _removed(self, path, count):
228 """Called when a file has been removed."""
229 self._progressLabel.set_text(xstr("update_removed") % (path,))
230 self._setProgress()
231
232 def writingManifest(self):
233 """Called when the writing of the new manifest file has started."""
234 gobject.idle_add(self._writingManifest)
235
236 def _writingManifest(self):
237 """Called when the writing of the new manifest file has started."""
238 self._progressLabel.set_text(xstr("update_writing_manifest"))
239
240 def done(self):
241 """Called when the update has been done."""
242 gobject.idle_add(self._done)
243 self._restart = self._waitAfterFinish
244
245 def _done(self):
246 """Called when the writing of the new manifest file has started."""
247 self._progressBar.set_fraction(1)
248 if self._totalProgress>0:
249 self._progressLabel.set_text(xstr("update_finished"))
250 self._progressOKButton.set_sensitive(True)
251 else:
252 self._progressLabel.set_text(xstr("update_nothing"))
253
254 def _setProgress(self):
255 """Set the progress bar based on the current stage."""
256 if self._totalProgress>0:
257 progress = self._downloaded + \
258 (self._numModifiedOrNew + self._numRemoved) * \
259 Updater.REMOVE2BYTES
260 self._progressBar.set_fraction(0.05 + 0.94 * progress / self._totalProgress)
261
262 def failed(self, what):
263 """Called when the downloading has failed."""
264 self._waitAfterFinish = True
265 gobject.idle_add(self._failed, what)
266
267 def _failed(self, what):
268 """Called when the downloading has failed."""
269 self._progressLabel.set_text(xstr("update_failed"))
270 self._progressBar.set_fraction(1)
271 self._progressOKButton.set_sensitive(True)
272
273 def _startUpdate(self):
274 """Start the update.
275
276 It resets the GUI elements."""
277 self._progressLabel.set_text("")
278 self._progressBar.set_fraction(0)
279 self._progressWindow.show_all()
280 self._progressOKButton.set_sensitive(False)
281 self._progressOKButton.connect("clicked", self._progressOKClicked)
282
283 def _progressOKClicked(self, button):
284 """Called when the OK button on the progress window is clicked."""
285 self._progressWindow.hide()
286 if self._restart:
287 self._gui.restart()
288
289#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.