source: src/mlx/gui/update.py@ 1099:a2d5a4d1c6c1

python3
Last change on this file since 1099:a2d5a4d1c6c1 was 996:8035d80d5feb, checked in by István Váradi <ivaradi@…>, 5 years ago

Using 'Gtk' instead of 'gtk' (re #347)

File size: 10.6 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)
58
59 mainAlignment = Gtk.Alignment(xscale = 1.0)
60 mainAlignment.set_padding(padding_top = 4, padding_bottom = 10,
61 padding_left = 16, padding_right = 16)
62 window.add(mainAlignment)
63
64 mainVBox = Gtk.VBox()
65 mainAlignment.add(mainVBox)
66
67 labelAlignment = Gtk.Alignment(xalign = 0.0, xscale = 0.0)
68 Updater._progressLabel = progressLabel = Gtk.Label()
69 labelAlignment.add(progressLabel)
70 mainVBox.pack_start(labelAlignment, True, True, 4)
71
72 Updater._progressBar = progressBar = Gtk.ProgressBar()
73 mainVBox.pack_start(progressBar, True, True, 4)
74
75 buttonAlignment = Gtk.Alignment(xalign = 0.5, xscale = 0.1)
76 Updater._progressOKButton = progressOKButton = Gtk.Button("OK")
77 buttonAlignment.add(progressOKButton)
78 mainVBox.pack_start(buttonAlignment, True, True, 4)
79
80 Updater._sudoDialog = sudoDialog = \
81 Gtk.Dialog(WINDOW_TITLE_BASE + " " + xstr("update_title"),
82 parentWindow,
83 Gtk.DialogFlags.MODAL)
84 sudoDialog.add_button(xstr("button_cancel"), 0)
85 sudoDialog.add_button(xstr("button_ok"), 1)
86
87 infoLabelAlignment = Gtk.Alignment(xalign = 0.5, xscale = 0.1)
88 infoLabelAlignment.set_padding(padding_top = 4, padding_bottom = 10,
89 padding_left = 16, padding_right = 16)
90
91 infoLabel = Gtk.Label(xstr("update_needsudo"))
92 infoLabel.set_justify(Gtk.Justification.CENTER)
93 infoLabelAlignment.add(infoLabel)
94 sudoDialog.vbox.pack_start(infoLabelAlignment, True, True, 4)
95
96 sudoDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
97
98 def __init__(self, gui, 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._gui = gui
104
105 self._programDirectory = programDirectory
106 self._updateURL = updateURL
107
108 self._totalProgress = 0
109 self._waitAfterFinish = False
110 self._restart = False
111
112 self._sudoReply = None
113 self._sudoCondition = threading.Condition()
114
115 Updater._createGUI(parentWindow)
116
117 def run(self):
118 """Execute the thread's operation."""
119 GObject.idle_add(self._startUpdate)
120 update(self._programDirectory, self._updateURL, self, fromGUI = True)
121 if not self._waitAfterFinish:
122 GObject.idle_add(self._progressWindow.hide)
123 self._gui.updateDone()
124
125 def downloadingManifest(self):
126 """Called when the downloading of the manifest has started."""
127 GObject.idle_add(self._downloadingManifest)
128
129 def _downloadingManifest(self):
130 """Called when the downloading of the manifest has started."""
131 self._progressLabel.set_text(xstr("update_manifest_progress"))
132 self._progressBar.set_fraction(0)
133
134 def downloadedManifest(self):
135 """Called when the downloading of the manifest has finished."""
136 GObject.idle_add(self._downloadedManifest)
137
138 def _downloadedManifest(self):
139 """Called when the downloading of the manifest has finished."""
140 self._progressLabel.set_text(xstr("update_manifest_done"))
141 self._progressBar.set_fraction(0.05)
142
143 def needSudo(self):
144 """Called when the program is interested in whether we want to run a
145 program with administrator rights to do the update."""
146 GObject.idle_add(self._needSudo)
147 with self._sudoCondition:
148 while self._sudoReply is None:
149 self._sudoCondition.wait(1)
150 return self._sudoReply
151
152 def _needSudo(self):
153 """Called when the program is interested in whether we want to run a
154 program with administrator rights to do the update."""
155 self._sudoDialog.show_all()
156 result = self._sudoDialog.run()
157 self._sudoDialog.hide()
158 with self._sudoCondition:
159 self._sudoReply = result!=0
160 self._sudoCondition.notify()
161
162 def setTotalSize(self, numToModifyAndNew, totalSize, numToRemove,
163 numToRemoveLocal):
164 """Called when the downloading of the files has started."""
165 self._numToModifyAndNew = numToModifyAndNew
166 self._numModifiedOrNew = 0
167 self._totalSize = totalSize
168 self._downloaded = 0
169 self._numToRemove = numToRemove
170 self._numToRemoveLocal = numToRemoveLocal
171 self._numRemoved = 0
172
173 self._totalProgress = self._totalSize + \
174 (self._numToModifyAndNew + \
175 self._numToRemove + self._numToRemoveLocal) * \
176 Updater.REMOVE2BYTES
177 self._waitAfterFinish = self._totalSize > 0 or self._numToRemove > 0
178
179 def _startDownload(self):
180 """Called when the download has started."""
181 self._progressLabel.set_text(xstr("update_files_progress"))
182
183 def setDownloaded(self, downloaded):
184 """Called when a certain number of bytes are downloaded."""
185 self._downloaded = downloaded
186 GObject.idle_add(self._setDownloaded, downloaded)
187
188 def _setDownloaded(self, downloaded):
189 """Called when a certain number of bytes are downloaded."""
190 self._progressLabel.set_text(xstr("update_files_bytes") % \
191 (downloaded, self._totalSize))
192 self._setProgress()
193
194 def startRenaming(self):
195 """Called when the renaming of files has started."""
196 GObject.idle_add(self._startRenaming)
197
198 def _startRenaming(self):
199 """Called when the renaming of files has started."""
200 self._progressLabel.set_text(xstr("update_renaming"))
201
202 def renamed(self, path, count):
203 """Called when a file has been renamed."""
204 self._numModifiedOrNew = count
205 GObject.idle_add(self._renamed, path, count)
206
207 def _renamed(self, path, count):
208 """Called when a file has been renamed."""
209 self._progressLabel.set_text(xstr("update_renamed") % (path,))
210 self._setProgress()
211
212 def startRemoving(self):
213 """Called when the removing of files has started."""
214 GObject.idle_add(self._startRemoving)
215
216 def _startRemoving(self):
217 """Called when the removing of files has started."""
218 self._progressLabel.set_text(xstr("update_removing"))
219
220 def removed(self, path, count):
221 """Called when a file has been removed."""
222 self._numRemoved = count
223 GObject.idle_add(self._removed, path, count)
224
225 def _removed(self, path, count):
226 """Called when a file has been removed."""
227 self._progressLabel.set_text(xstr("update_removed") % (path,))
228 self._setProgress()
229
230 def writingManifest(self):
231 """Called when the writing of the new manifest file has started."""
232 GObject.idle_add(self._writingManifest)
233
234 def _writingManifest(self):
235 """Called when the writing of the new manifest file has started."""
236 self._progressLabel.set_text(xstr("update_writing_manifest"))
237
238 def done(self):
239 """Called when the update has been done."""
240 GObject.idle_add(self._done)
241 self._restart = self._waitAfterFinish
242
243 def _done(self):
244 """Called when the writing of the new manifest file has started."""
245 self._progressBar.set_fraction(1)
246 if self._totalProgress>0:
247 self._progressLabel.set_text(xstr("update_finished"))
248 self._progressOKButton.set_sensitive(True)
249 else:
250 self._progressLabel.set_text(xstr("update_nothing"))
251
252 def _setProgress(self):
253 """Set the progress bar based on the current stage."""
254 if self._totalProgress>0:
255 progress = self._downloaded + \
256 (self._numModifiedOrNew + self._numRemoved) * \
257 Updater.REMOVE2BYTES
258 self._progressBar.set_fraction(0.05 + 0.94 * progress / self._totalProgress)
259
260 def failed(self, what):
261 """Called when the downloading has failed."""
262 self._waitAfterFinish = True
263 GObject.idle_add(self._failed, what)
264
265 def _failed(self, what):
266 """Called when the downloading has failed."""
267 self._progressLabel.set_text(xstr("update_failed"))
268 self._progressBar.set_fraction(1)
269 self._progressOKButton.set_sensitive(True)
270
271 def _startUpdate(self):
272 """Start the update.
273
274 It resets the GUI elements."""
275 self._progressLabel.set_text("")
276 self._progressBar.set_fraction(0)
277 self._progressWindow.show_all()
278 self._progressOKButton.set_sensitive(False)
279 self._progressOKButton.connect("clicked", self._progressOKClicked)
280
281 def _progressOKClicked(self, button):
282 """Called when the OK button on the progress window is clicked."""
283 self._progressWindow.hide()
284 if self._restart:
285 self._gui.restart()
286 else:
287 self._gui.updateDone()
288
289#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.