qubes-installer-qubes-os/anaconda/pyanaconda/ui/gui/hubs/progress.py

259 lines
9.4 KiB
Python
Raw Normal View History

# Progress hub classes
#
# Copyright (C) 2011-2012 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details. You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
# Red Hat Author(s): Chris Lumens <clumens@redhat.com>
#
from __future__ import division
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
from gi.repository import GLib, Gtk
import itertools
import os
import sys
from pyanaconda.localization import expand_langs
from pyanaconda.product import productName
from pyanaconda.flags import flags
from pykickstart.constants import KS_WAIT, KS_SHUTDOWN, KS_REBOOT
from pyanaconda.ui.gui.hubs import Hub
from pyanaconda.ui.gui.utils import gtk_thread_nowait, gtk_call_once
__all__ = ["ProgressHub"]
class ProgressHub(Hub):
builderObjects = ["progressWindow"]
mainWidgetName = "progressWindow"
uiFile = "hubs/progress.glade"
def __init__(self, data, storage, payload, instclass):
Hub.__init__(self, data, storage, payload, instclass)
self._totalSteps = 0
self._currentStep = 0
self._configurationDone = False
def _do_configuration(self, widget = None, reenable_ransom = True):
from pyanaconda.install import doConfiguration
from pyanaconda.threads import threadMgr, AnacondaThread
assert self._configurationDone == False
self._configurationDone = True
# Disable all personalization spokes
self.builder.get_object("progressWindow-scroll").set_sensitive(False)
if reenable_ransom:
self._start_ransom_notes()
self._progress_id = GLib.timeout_add(250, self._update_progress, self._configuration_done)
threadMgr.add(AnacondaThread(name="AnaConfigurationThread", target=doConfiguration,
args=(self.storage, self.payload, self.data, self.instclass)))
def _start_ransom_notes(self):
# Adding this as a timeout below means it'll get called after 60
# seconds, so we need to do the first call manually.
self._cycle_rnotes()
self._rnotes_id = GLib.timeout_add_seconds(60, self._cycle_rnotes)
def _update_progress(self, callback = None):
from pyanaconda import progress
import Queue
q = progress.progressQ
# Grab all messages may have appeared since last time this method ran.
while True:
# Attempt to get a message out of the queue for how we should update
# the progress bar. If there's no message, don't error out.
try:
(code, args) = q.get(False)
except Queue.Empty:
break
if code == progress.PROGRESS_CODE_INIT:
self._init_progress_bar(args[0])
elif code == progress.PROGRESS_CODE_STEP:
self._step_progress_bar()
elif code == progress.PROGRESS_CODE_MESSAGE:
self._update_progress_message(args[0])
elif code == progress.PROGRESS_CODE_COMPLETE:
# There shouldn't be any more progress bar updates, so return False
# to indicate this method should be removed from the idle loop. Also,
# stop the rnotes cycling and display the finished message.
self._progress_bar_complete()
q.task_done()
if callback:
callback()
return False
elif code == progress.PROGRESS_CODE_QUIT:
sys.exit(args[0])
q.task_done()
return True
def _configuration_done(self):
# Configuration done, remove ransom notes timer
# and switch to the Reboot page
GLib.source_remove(self._rnotes_id)
self._progressNotebook.set_current_page(1)
# kickstart install, continue automatically if reboot or shutdown selected
if flags.automatedInstall and self.data.reboot.action in [KS_REBOOT, KS_SHUTDOWN]:
self.continueButton.emit("clicked")
def _install_done(self):
# package installation done, check personalization spokes
# and start the configuration step if all is ready
if not self._inSpoke and self.continuePossible:
self._do_configuration(reenable_ransom = False)
else:
# some mandatory spokes are not ready
# switch to configure and finish page
GLib.source_remove(self._rnotes_id)
self._progressNotebook.set_current_page(0)
def _get_rnotes(self):
import glob
# We first look for rnotes in paths containing the language, then in
# directories without the language component. You know, just in case.
langs = expand_langs(os.environ["LANG"]) + [""]
paths = ["/tmp/updates/pixmaps/rnotes/%s/*.png",
"/tmp/product/pixmaps/rnotes/%s/*.png",
"/usr/share/anaconda/pixmaps/rnotes/%s/*.png"]
for (l, d) in itertools.product(langs, paths):
pixmaps = glob.glob(d % l)
if len(pixmaps) > 0:
return pixmaps
return []
def _cycle_rnotes(self):
# Change the ransom notes image every minute by grabbing the next
# image's filename. Note that self._rnotesPages is an infinite list,
# so this will cycle through the images indefinitely.
try:
nxt = self._rnotesPages.next()
except StopIteration:
# there are no rnotes
pass
else:
self._progressNotebook.set_current_page(nxt)
return True
def initialize(self):
Hub.initialize(self)
if flags.livecdInstall:
continueText = self.builder.get_object("rebootLabel")
continueText.set_text("%s is now successfully installed on your system and ready"
"for you to use! When you are ready, reboot your system to start using it!")
self.continueButton.set_label("_Quit")
self._progressBar = self.builder.get_object("progressBar")
self._progressLabel = self.builder.get_object("progressLabel")
self._progressNotebook = self.builder.get_object("progressNotebook")
lbl = self.builder.get_object("configurationLabel")
lbl.set_text(lbl.get_text() % productName)
lbl = self.builder.get_object("rebootLabel")
lbl.set_text(lbl.get_text() % productName)
rnotes = self._get_rnotes()
if rnotes:
# Add a new page in the notebook for each ransom note image.
for f in rnotes:
img = Gtk.Image.new_from_file(f)
img.show()
self._progressNotebook.append_page(img, None)
# An infinite list of the page numbers containing ransom notes images.
self._rnotesPages = itertools.cycle(range(2, self._progressNotebook.get_n_pages()-2))
else:
# Add a blank page to the notebook and we'll just cycle to that
# over and over again.
blank = Gtk.Box()
blank.show()
self._progressNotebook.append_page(blank, None)
self._rnotesPages = itertools.cycle([2])
def refresh(self):
from pyanaconda.install import doInstall
from pyanaconda.threads import threadMgr, AnacondaThread
Hub.refresh(self)
self._start_ransom_notes()
self._progress_id = GLib.timeout_add(250, self._update_progress, self._install_done)
threadMgr.add(AnacondaThread(name="AnaInstallThread", target=doInstall,
args=(self.storage, self.payload, self.data, self.instclass)))
def _updateContinueButton(self):
if self._configurationDone:
self.continueButton.set_sensitive(self.continuePossible)
else:
self.builder.get_object("configureButton").set_sensitive(self.continuePossible)
@property
def continueButton(self):
return self.builder.get_object("rebootButton")
def _init_progress_bar(self, steps):
self._totalSteps = steps
self._currentStep = 0
gtk_call_once(self._progressBar.set_fraction, 0.0)
def _step_progress_bar(self):
if not self._totalSteps:
return
self._currentStep += 1
gtk_call_once(self._progressBar.set_fraction, self._currentStep/self._totalSteps)
def _update_progress_message(self, message):
if not self._totalSteps:
return
gtk_call_once(self._progressLabel.set_text, message)
@gtk_thread_nowait
def _progress_bar_complete(self):
self._progressBar.set_fraction(1.0)
self._progressLabel.set_text(_("Complete!"))
spinner = self.builder.get_object("progressSpinner")
spinner.stop()
spinner.hide()