source: src/mlx/gui/update.py@ 996:8035d80d5feb

python3
Last change on this file since 996:8035d80d5feb 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
RevLine 
[36]1
2from mlx.gui.common import *
3
[38]4from mlx.update import update
[115]5from mlx.i18n import xstr
[36]6
7import mlx.const as const
8
9import threading
10import os
11import sys
12
13#-------------------------------------------------------------------------------
14
[300]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
[36]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
[996]48 Updater._progressWindow = window = Gtk.Window()
[115]49 window.set_title(WINDOW_TITLE_BASE + " " + xstr("update_title"))
[36]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)
[996]57 window.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
[36]58
[996]59 mainAlignment = Gtk.Alignment(xscale = 1.0)
[36]60 mainAlignment.set_padding(padding_top = 4, padding_bottom = 10,
61 padding_left = 16, padding_right = 16)
62 window.add(mainAlignment)
63
[996]64 mainVBox = Gtk.VBox()
[36]65 mainAlignment.add(mainVBox)
66
[996]67 labelAlignment = Gtk.Alignment(xalign = 0.0, xscale = 0.0)
68 Updater._progressLabel = progressLabel = Gtk.Label()
[36]69 labelAlignment.add(progressLabel)
70 mainVBox.pack_start(labelAlignment, True, True, 4)
71
[996]72 Updater._progressBar = progressBar = Gtk.ProgressBar()
[36]73 mainVBox.pack_start(progressBar, True, True, 4)
74
[996]75 buttonAlignment = Gtk.Alignment(xalign = 0.5, xscale = 0.1)
76 Updater._progressOKButton = progressOKButton = Gtk.Button("OK")
[36]77 buttonAlignment.add(progressOKButton)
78 mainVBox.pack_start(buttonAlignment, True, True, 4)
79
80 Updater._sudoDialog = sudoDialog = \
[996]81 Gtk.Dialog(WINDOW_TITLE_BASE + " " + xstr("update_title"),
[36]82 parentWindow,
[996]83 Gtk.DialogFlags.MODAL)
[124]84 sudoDialog.add_button(xstr("button_cancel"), 0)
85 sudoDialog.add_button(xstr("button_ok"), 1)
86
[996]87 infoLabelAlignment = Gtk.Alignment(xalign = 0.5, xscale = 0.1)
[36]88 infoLabelAlignment.set_padding(padding_top = 4, padding_bottom = 10,
89 padding_left = 16, padding_right = 16)
90
[996]91 infoLabel = Gtk.Label(xstr("update_needsudo"))
92 infoLabel.set_justify(Gtk.Justification.CENTER)
[36]93 infoLabelAlignment.add(infoLabel)
94 sudoDialog.vbox.pack_start(infoLabelAlignment, True, True, 4)
95
[996]96 sudoDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
[36]97
[38]98 def __init__(self, gui, programDirectory, updateURL, parentWindow):
[36]99 """Construct the updater. If not created yet, the windows used by the
100 updater are also created."""
101 super(Updater, self).__init__()
[38]102
103 self._gui = gui
[36]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."""
[995]119 GObject.idle_add(self._startUpdate)
[36]120 update(self._programDirectory, self._updateURL, self, fromGUI = True)
121 if not self._waitAfterFinish:
[995]122 GObject.idle_add(self._progressWindow.hide)
[755]123 self._gui.updateDone()
[36]124
125 def downloadingManifest(self):
126 """Called when the downloading of the manifest has started."""
[995]127 GObject.idle_add(self._downloadingManifest)
[36]128
129 def _downloadingManifest(self):
130 """Called when the downloading of the manifest has started."""
[115]131 self._progressLabel.set_text(xstr("update_manifest_progress"))
[36]132 self._progressBar.set_fraction(0)
133
134 def downloadedManifest(self):
135 """Called when the downloading of the manifest has finished."""
[995]136 GObject.idle_add(self._downloadedManifest)
[36]137
138 def _downloadedManifest(self):
139 """Called when the downloading of the manifest has finished."""
[115]140 self._progressLabel.set_text(xstr("update_manifest_done"))
[36]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."""
[995]146 GObject.idle_add(self._needSudo)
[36]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
[37]162 def setTotalSize(self, numToModifyAndNew, totalSize, numToRemove,
163 numToRemoveLocal):
[36]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
[37]170 self._numToRemoveLocal = numToRemoveLocal
[36]171 self._numRemoved = 0
172
173 self._totalProgress = self._totalSize + \
[37]174 (self._numToModifyAndNew + \
175 self._numToRemove + self._numToRemoveLocal) * \
[36]176 Updater.REMOVE2BYTES
[37]177 self._waitAfterFinish = self._totalSize > 0 or self._numToRemove > 0
[36]178
179 def _startDownload(self):
180 """Called when the download has started."""
[115]181 self._progressLabel.set_text(xstr("update_files_progress"))
[36]182
183 def setDownloaded(self, downloaded):
184 """Called when a certain number of bytes are downloaded."""
185 self._downloaded = downloaded
[995]186 GObject.idle_add(self._setDownloaded, downloaded)
[36]187
188 def _setDownloaded(self, downloaded):
189 """Called when a certain number of bytes are downloaded."""
[115]190 self._progressLabel.set_text(xstr("update_files_bytes") % \
[36]191 (downloaded, self._totalSize))
192 self._setProgress()
193
194 def startRenaming(self):
195 """Called when the renaming of files has started."""
[995]196 GObject.idle_add(self._startRenaming)
[36]197
198 def _startRenaming(self):
199 """Called when the renaming of files has started."""
[115]200 self._progressLabel.set_text(xstr("update_renaming"))
[36]201
202 def renamed(self, path, count):
203 """Called when a file has been renamed."""
204 self._numModifiedOrNew = count
[995]205 GObject.idle_add(self._renamed, path, count)
[36]206
207 def _renamed(self, path, count):
208 """Called when a file has been renamed."""
[115]209 self._progressLabel.set_text(xstr("update_renamed") % (path,))
[36]210 self._setProgress()
211
212 def startRemoving(self):
213 """Called when the removing of files has started."""
[995]214 GObject.idle_add(self._startRemoving)
[36]215
216 def _startRemoving(self):
217 """Called when the removing of files has started."""
[115]218 self._progressLabel.set_text(xstr("update_removing"))
[36]219
220 def removed(self, path, count):
221 """Called when a file has been removed."""
222 self._numRemoved = count
[995]223 GObject.idle_add(self._removed, path, count)
[36]224
225 def _removed(self, path, count):
226 """Called when a file has been removed."""
[115]227 self._progressLabel.set_text(xstr("update_removed") % (path,))
[36]228 self._setProgress()
229
230 def writingManifest(self):
231 """Called when the writing of the new manifest file has started."""
[995]232 GObject.idle_add(self._writingManifest)
[36]233
234 def _writingManifest(self):
235 """Called when the writing of the new manifest file has started."""
[115]236 self._progressLabel.set_text(xstr("update_writing_manifest"))
[36]237
238 def done(self):
239 """Called when the update has been done."""
[995]240 GObject.idle_add(self._done)
[37]241 self._restart = self._waitAfterFinish
[36]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:
[115]247 self._progressLabel.set_text(xstr("update_finished"))
[36]248 self._progressOKButton.set_sensitive(True)
249 else:
[115]250 self._progressLabel.set_text(xstr("update_nothing"))
[36]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
[995]263 GObject.idle_add(self._failed, what)
[36]264
265 def _failed(self, what):
266 """Called when the downloading has failed."""
[115]267 self._progressLabel.set_text(xstr("update_failed"))
[36]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:
[38]285 self._gui.restart()
[755]286 else:
287 self._gui.updateDone()
[36]288
289#-------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.