source: src/mlx/gui/update.py@ 227:50c3ae93007d

Last change on this file since 227:50c3ae93007d was 124:6633722f7f86, checked in by István Váradi <ivaradi@…>, 12 years ago

The buttons are now explicitly defined for message dialogs to avoid language problems

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