# # gui.py - Graphical front end for anaconda # # Matt Wilson # Michael Fulbright # # Copyright 1999-2006 Red Hat, Inc. # # This software may be freely redistributed under the terms of the GNU # general public license. # # 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., 675 Mass Ave, Cambridge, MA 02139, USA. # import os from flags import flags os.environ["GNOME_DISABLE_CRASH_DIALOG"] = "1" # we only want to enable the accessibility stuff if requested for now... if flags.cmdline.has_key("dogtail"): os.environ["GTK_MODULES"] = "gail:atk-bridge" import string import time import isys import sys import parted import shutil import gtk import gtk.glade import gobject import gettext from language import expandLangs from constants import * from network import hasActiveNetDev import floppy import rhpl import xutils import imputil from rhpl.translate import _, N_ from release_notes import * import logging log = logging.getLogger("anaconda") isys.bind_textdomain_codeset("redhat-dist", "UTF-8") class StayOnScreen(Exception): pass mainWindow = None stepToClass = { "language" : ("language_gui", "LanguageWindow"), "keyboard" : ("kbd_gui", "KeyboardWindow"), "mouse" : ("mouse_gui", "MouseWindow"), "welcome" : ("welcome_gui", "WelcomeWindow"), "zfcpconfig" : ("zfcp_gui", "ZFCPWindow"), "partitionmethod" : ("partmethod_gui", "PartitionMethodWindow"), "partition" : ("partition_gui", "PartitionWindow"), "parttype" : ("autopart_type", "PartitionTypeWindow"), "findinstall" : ("examine_gui", "UpgradeExamineWindow"), "addswap" : ("upgrade_swap_gui", "UpgradeSwapWindow"), "upgrademigratefs" : ("upgrade_migratefs_gui", "UpgradeMigrateFSWindow"), "bootloader": ("bootloader_main_gui", "MainBootloaderWindow"), "bootloaderadvanced": ("bootloader_advanced_gui", "AdvancedBootloaderWindow"), "upgbootloader": ("upgrade_bootloader_gui", "UpgradeBootloaderWindow"), "network" : ("network_gui", "NetworkWindow"), "timezone" : ("timezone_gui", "TimezoneWindow"), "accounts" : ("account_gui", "AccountWindow"), "tasksel": ("task_gui", "TaskWindow"), "group-selection": ("package_gui", "GroupSelectionWindow"), "confirminstall" : ("confirm_gui", "InstallConfirmWindow"), "confirmupgrade" : ("confirm_gui", "UpgradeConfirmWindow"), "install" : ("progress_gui", "InstallProgressWindow"), "complete" : ("congrats_gui", "CongratulationWindow"), } if rhpl.getArch() == 's390': stepToClass["bootloader"] = ("zipl_gui", "ZiplWindow") # # Stuff for screenshots # screenshotDir = None screenshotIndex = 0 def copyScreenshots(): global screenshotIndex global screenshotDir # see if any screenshots taken if screenshotIndex == 0: return destDir = "/mnt/sysimage/root/anaconda-screenshots" if not os.access(destDir, os.R_OK): try: os.mkdir(destDir, 0750) except: window = MessageWindow("Error Saving Screenshot", _("An error occurred copying the " "screenshots over."), type="warning") return # copy all png's over for f in os.listdir(screenshotDir): (path, fname) = os.path.split(f) (b, ext) = os.path.splitext(f) if ext == ".png": shutil.copyfile(screenshotDir + '/' + f, destDir + '/' + fname) window = MessageWindow(_("Screenshots Copied"), _("The screenshots have been saved into the " "directory:\n\n" "\t/root/anaconda-screenshots/\n\n" "You can access these when you reboot and " "login as root.")) def takeScreenShot(): global screenshotIndex global screenshotDir if screenshotDir is None: screenshotDir = "/tmp/ramfs/anaconda-screenshots" if not os.access(screenshotDir, os.R_OK): try: os.mkdir(screenshotDir) except: screenshotDir = None return try: screenshot = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, gtk.gdk.screen_width(), gtk.gdk.screen_height()) screenshot.get_from_drawable(gtk.gdk.get_default_root_window(), gtk.gdk.colormap_get_system(), 0, 0, 0, 0, gtk.gdk.screen_width(), gtk.gdk.screen_height()) if screenshot: while (1): sname = "screenshot-%04d.png" % ( screenshotIndex,) if not os.access(screenshotDir + '/' + sname, os.R_OK): break screenshotIndex = screenshotIndex + 1 if screenshotIndex > 9999: log.error("Too many screenshots!") return screenshot.save (screenshotDir + '/' + sname, "png") screenshotIndex = screenshotIndex + 1 window = MessageWindow(_("Saving Screenshot"), _("A screenshot named '%s' has been saved.") % (sname,) , type="ok") except: window = MessageWindow(_("Error Saving Screenshot"), _("An error occurred while saving " "the screenshot. If this occurred " "during package installation, you may need " "to try several times for it to succeed."), type="warning") def handleShiftPrintScrnRelease (window, event): if (event.keyval == gtk.keysyms.Print and event.state & gtk.gdk.SHIFT_MASK): takeScreenShot() # # HACK to make treeview work # def setupTreeViewFixupIdleHandler(view, store): id = {} id["id"] = gobject.idle_add(scrollToIdleHandler, (view, store, id)) def scrollToIdleHandler((view, store, iddict)): if not view or not store or not iddict: return try: id = iddict["id"] except: return selection = view.get_selection() if not selection: return model, iter = selection.get_selected() if not iter: return path = store.get_path(iter) col = view.get_column(0) view.scroll_to_cell(path, col, True, 0.5, 0.5) if id: gobject.source_remove(id) # setup globals def processEvents(): gtk.gdk.flush() while gtk.events_pending(): gtk.main_iteration(False) def partedExceptionWindow(exc): # if our only option is to cancel, let us handle the exception # in our code and avoid popping up the exception window here. if exc.options == parted.EXCEPTION_CANCEL: return parted.EXCEPTION_UNHANDLED log.critical("parted exception: %s: %s" %(exc.type_string,exc.message)) print exc.type_string print exc.message print exc.options win = gtk.Dialog(exc.type_string, mainWindow, gtk.DIALOG_MODAL) addFrame(win) win.set_position(gtk.WIN_POS_CENTER) label = WrappingLabel(exc.message) win.vbox.pack_start (label) numButtons = 0 buttonToAction = {} exflags = ((parted.EXCEPTION_FIX, N_("Fix")), (parted.EXCEPTION_YES, N_("Yes")), (parted.EXCEPTION_NO, N_("No")), (parted.EXCEPTION_OK, N_("OK")), (parted.EXCEPTION_RETRY, N_("Retry")), (parted.EXCEPTION_IGNORE, N_("Ignore")), (parted.EXCEPTION_CANCEL, N_("Cancel"))) for flag, string in exflags: if exc.options & flag: win.add_button(_(string), flag) win.show_all() rc = win.run() win.destroy() return rc def widgetExpander(widget, growTo=None): widget.connect("size-allocate", growToParent, growTo) def growToParent(widget, rect, growTo=None): if not widget.parent: return ignore = widget.__dict__.get("ignoreEvents") if not ignore: if growTo: x, y, width, height = growTo.get_allocation() widget.set_size_request(width, -1) else: widget.set_size_request(rect.width, -1) widget.ignoreEvents = 1 else: widget.ignoreEvents = 0 _busyCursor = 0 def setCursorToBusy(process=1): root = gtk.gdk.get_default_root_window() cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) root.set_cursor(cursor) if process: processEvents() def setCursorToNormal(): root = gtk.gdk.get_default_root_window() cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR) root.set_cursor(cursor) def rootPushBusyCursor(process=1): global _busyCursor _busyCursor += 1 if _busyCursor > 0: setCursorToBusy(process) def rootPopBusyCursor(): global _busyCursor _busyCursor -= 1 if _busyCursor <= 0: setCursorToNormal() def getBusyCursorStatus(): global _busyCursor return _busyCursor def runningMiniWm(): return xutils.getXatom("_ANACONDA_MINI_WM_RUNNING") class MnemonicLabel(gtk.Label): def __init__(self, text="", alignment = None): gtk.Label.__init__(self, "") self.set_text_with_mnemonic(text) if alignment is not None: apply(self.set_alignment, alignment) class WrappingLabel(gtk.Label): def __init__(self, label=""): gtk.Label.__init__(self, label) self.set_line_wrap(True) self.ignoreEvents = 0 widgetExpander(self) def titleBarMousePressCB(widget, event, data): if event.type & gtk.gdk.BUTTON_PRESS: (x, y) = data["window"].get_position() data["state"] = 1 data["button"] = event.button data["deltax"] = event.x_root - x data["deltay"] = event.y_root - y def titleBarMouseReleaseCB(widget, event, data): if data["state"] and event.button == data["button"]: data["state"] = 0 data["button"] = 0 data["deltax"] = 0 data["deltay"] = 0 def titleBarMotionEventCB(widget, event, data): if data["state"]: newx = event.x_root - data["deltax"] newy = event.y_root - data["deltay"] if newx < 0: newx = 0 if newy < 0: newy = 0 (w, h) = data["window"].get_size() if (newx+w) > gtk.gdk.screen_width(): newx = gtk.gdk.screen_width() - w if (newy+20) > (gtk.gdk.screen_height()): newy = gtk.gdk.screen_height() - 20 data["window"].move(int(newx), int(newy)) def addFrame(dialog, title=None, showtitle = 1): # We don't add a Frame in rootpath mode, as we almost certainly # have a window manager contents = dialog.get_children()[0] dialog.remove(contents) frame = gtk.Frame() if not flags.rootpath and runningMiniWm(): frame.set_shadow_type(gtk.SHADOW_OUT) else: frame.set_shadow_type(gtk.SHADOW_NONE) box = gtk.VBox() try: if title is None: title = dialog.get_title() if title and not flags.rootpath and runningMiniWm(): data = {} data["state"] = 0 data["button"] = 0 data["deltax"] = 0 data["deltay"] = 0 data["window"] = dialog eventBox = gtk.EventBox() eventBox.connect("button-press-event", titleBarMousePressCB, data) eventBox.connect("button-release-event", titleBarMouseReleaseCB, data) eventBox.connect("motion-notify-event", titleBarMotionEventCB,data) titleBox = gtk.HBox(False, 5) eventBox.add(titleBox) eventBox.modify_bg(gtk.STATE_NORMAL, eventBox.rc_get_style().bg[gtk.STATE_SELECTED]) if showtitle: titlelbl = gtk.Label("") titlelbl.set_markup(""+_(title)+"") titlelbl.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse ("white")) titlelbl.set_property("ypad", 4) titleBox.pack_start(titlelbl) else: s = gtk.Label("") titleBox.pack_start(s) eventBox.show_all() box.pack_start(eventBox, False, False) else: dialog.set_title (title) except: pass frame2=gtk.Frame() frame2.set_shadow_type(gtk.SHADOW_NONE) frame2.set_border_width(4) frame2.add(contents) contents.show() frame2.show() box.pack_start(frame2, True, True, padding=5) box.show() frame.add(box) frame.show() dialog.add(frame) # make screen shots work dialog.connect ("key-release-event", handleShiftPrintScrnRelease) def findGladeFile(file): for dir in ("/mnt/source/RHupdates/", "/tmp/updates/", "ui/", "/usr/share/anaconda/ui/", "/usr/share/pirut/ui/"): fn = dir + file if os.access(fn, os.R_OK): return fn raise RuntimeError, "Unable to find glade file %s" % file def getGladeWidget(file, rootwidget, i18ndomain="anaconda"): f = findGladeFile(file) xml = gtk.glade.XML(f, root = rootwidget, domain = i18ndomain) w = xml.get_widget(rootwidget) if w is None: raise RuntimeError, "Unable to find root widget %s in %s" %(rootwidget, file) return (xml, w) def findPixmap(file): for dir in ("/mnt/source/RHupdates/pixmaps/", "/mnt/source/RHupdates/", "/tmp/updates/pixmaps/", "/tmp/updates/", "/tmp/product/pixmaps/", "/tmp/product/", "pixmaps/", "/usr/share/anaconda/pixmaps/", "/usr/share/pixmaps/", "/usr/share/anaconda/", ""): fn = dir + file if os.access(fn, os.R_OK): return fn return None def getPixbuf(file): fn = findPixmap(file) if not fn: log.error("unable to load %s" %(file,)) return None try: pixbuf = gtk.gdk.pixbuf_new_from_file(fn) except RuntimeError, msg: log.error("unable to read %s: %s" %(file, msg)) pixbuf = None return pixbuf def readImageFromFile(file, width = None, height = None, dither = None, image = None): pixbuf = getPixbuf(file) if pixbuf is None: log.warning("can't find pixmap %s" %(file,)) return None if (width is not None and height is not None and height != pixbuf.get_height() and width != pixbuf.get_width()): pixbuf = pixbuf.scale_simple(width, height, gtk.gdk.INTERP_BILINEAR) if image is None: p = gtk.Image() else: p = image if dither: (pixmap, mask) = pixbuf.render_pixmap_and_mask() pixmap.draw_pixbuf(gtk.gdk.GC(pixmap), pixbuf, 0, 0, 0, 0, pixbuf.get_width(), pixbuf.get_height(), gtk.gdk.RGB_DITHER_MAX, 0, 0) p = gtk.Image() p.set_from_pixmap(pixmap, mask) else: source = gtk.IconSource() source.set_pixbuf(pixbuf) source.set_size(gtk.ICON_SIZE_DIALOG) source.set_size_wildcarded(False) iconset = gtk.IconSet() iconset.add_source(source) p.set_from_icon_set(iconset, gtk.ICON_SIZE_DIALOG) return p class WaitWindow: def __init__(self, title, text, parent = None): if flags.rootpath or not runningMiniWm(): self.window = gtk.Window() if parent: self.window.set_transient_for(parent) else: self.window = gtk.Window(gtk.WINDOW_POPUP) self.window.set_modal(True) self.window.set_title(title) self.window.set_position(gtk.WIN_POS_CENTER) label = WrappingLabel(text) box = gtk.Frame() box.set_border_width(10) box.add(label) box.set_shadow_type(gtk.SHADOW_NONE) self.window.add(box) addFrame(self.window, showtitle = 0) self.window.show_all() rootPushBusyCursor() def refresh(self): processEvents() def pop(self): self.window.destroy() rootPopBusyCursor() class ProgressWindow: def __init__(self, title, text, total, updpct = 0.05, updsecs=10, parent = None): if flags.rootpath or not runningMiniWm(): self.window = gtk.Window() if parent: self.window.set_transient_for(parent) else: self.window = gtk.Window(gtk.WINDOW_POPUP) self.window.set_modal(True) self.window.set_title (title) self.window.set_position (gtk.WIN_POS_CENTER) self.lastUpdate = int(time.time()) self.updsecs = updsecs box = gtk.VBox (False, 5) box.set_border_width (10) label = WrappingLabel (text) label.set_alignment (0.0, 0.5) box.pack_start (label, False) self.total = total self.updpct = updpct self.progress = gtk.ProgressBar () box.pack_start (self.progress, True) self.window.add(box) addFrame(self.window, showtitle = 0) self.window.show_all () rootPushBusyCursor() def refresh(self): processEvents() def set (self, amount): # only update widget if we've changed by 5% or our timeout has # expired curval = self.progress.get_fraction() newval = float (amount) / self.total then = self.lastUpdate now = int(time.time()) if newval < 0.998: if ((newval - curval) < self.updpct and (now-then) < self.updsecs): return self.lastUpdate = now self.progress.set_fraction (newval) processEvents () def pop(self): self.window.destroy () rootPopBusyCursor() class ScpWindow: def __init__(self, screen=None): self.scpxml = gtk.glade.XML(findGladeFile("scp.glade"), domain="anaconda") self.win = self.scpxml.get_widget("saveRemoteDlg") addFrame(self.win) self.win.show_all() self.window = self.win def getrc(self): if self.rc == 0: return None else: host = self.scpxml.get_widget("hostEntry") remotePath = self.scpxml.get_widget("remotePathEntry") userName = self.scpxml.get_widget("userNameEntry") password = self.scpxml.get_widget("passwordEntry") return (host.get_text(), remotePath.get_text(), userName.get_text(), password.get_text()) def run(self): self.rc = self.window.run() def pop(self): self.window.destroy() class InstallKeyWindow: def __init__(self, anaconda, key): (keyxml, self.win) = getGladeWidget("instkey.glade", "instkeyDialog") if anaconda.id.instClass.instkeydesc is not None: w = keyxml.get_widget("instkeyLabel") w.set_text(_(anaconda.id.instClass.instkeydesc)) if not anaconda.id.instClass.allowinstkeyskip: keyxml.get_widget("skipRadio").hide() keyName = _(anaconda.id.instClass.instkeyname) if anaconda.id.instClass.instkeyname is None: keyName = _("Installation Key") # set the install key name based on the installclass for l in ("instkeyLabel", "keyEntryLabel", "skipLabel"): w = keyxml.get_widget(l) t = w.get_text() w.set_text(t % {"instkey": keyName}) self.entry = keyxml.get_widget("keyEntry") self.entry.set_text(key) self.entry.set_sensitive(True) self.keyradio = keyxml.get_widget("keyRadio") self.skipradio = keyxml.get_widget("skipRadio") self.rc = 0 if anaconda.id.instClass.skipkey: self.skipradio.set_active(True) else: self.entry.grab_focus() self.win.connect("key-release-event", self.keyRelease) addFrame(self.win, title=keyName) def keyRelease(self, window, event): # XXX hack: remove this, too, when the accelerators work again if event.keyval == gtk.keysyms.F12: window.response(1) def run(self): self.win.show() self.rc = self.win.run() return self.rc def get_key(self): if self.skipradio.get_active(): return SKIP_KEY key = self.entry.get_text() key.strip() return key def destroy(self): self.win.destroy() class ExceptionWindow: def __init__ (self, shortTraceback, longTracebackFile=None, screen=None): # Get a bunch of widgets from the XML file. exnxml = gtk.glade.XML(findGladeFile("exn.glade"), domain="anaconda") self.win = exnxml.get_widget("exnDialog") vbox = exnxml.get_widget("mainVBox") exnView = exnxml.get_widget("exnView") expander = exnxml.get_widget("exnExpander") info = exnxml.get_widget("info") infoImage = exnxml.get_widget("infoImage") buttonBox = exnxml.get_widget("buttonBox") info.set_text(exceptionText) infoImage.clear() img = findPixmap("exception.png") if os.path.exists(img): infoImage.set_from_file(img) # Add the brief traceback message to the upper text view. textbuf = gtk.TextBuffer() textbuf.set_text(shortTraceback) # Remove the debug button since it doesn't work in livecd mode anyway if flags.livecdInstall: debugButton = exnxml.get_widget("debugButton") buttonBox.remove(debugButton) # Remove the floppy button if we don't need it. if not floppy.hasFloppyDevice() and not flags.debug: floppyButton = exnxml.get_widget("floppyButton") buttonBox.remove(floppyButton) # Remove the remote button if there's no network. if not hasActiveNetDev() and not flags.debug: remoteButton = exnxml.get_widget("remoteButton") buttonBox.remove(remoteButton) # If there's an anacdump.txt file, add it to the lower view in the # expander. If not, remove the expander. if longTracebackFile: try: f = open(longTracebackFile) lines = f.readlines() f.close() # Add text one line at a time to work around limits in # set_text. textbuf = gtk.TextBuffer() iter = textbuf.get_start_iter() for line in lines: textbuf.insert(iter, line) exnView.set_buffer(textbuf) except IOError (errnum, msg): log.error("Could not read %s, skipping: %s" % (longTracebackFile, msg)) vbox.remove(expander) else: vbox.remove(expander) addFrame(self.win) self.win.show_all () self.window = self.win def run(self): self.rc = self.window.run () def getrc (self): # I did it this way for future expantion # 0 is debug if self.rc == 0: try: # switch to VC1 so we can debug isys.vtActivate (1) except SystemError: pass return 1 # 1 is save to floppy if self.rc == 1: return 2 # 2 is OK elif self.rc == 2: return 0 # 3 is save to remote host elif self.rc == 3: return 3 def pop(self): self.window.destroy() class MessageWindow: def getrc (self): return self.rc def __init__ (self, title, text, type="ok", default=None, custom_buttons=None, custom_icon=None, run = True, parent = None, destroyAfterRun = True): self.debugRid = None self.title = title if flags.autostep: self.rc = 1 return self.rc = None self.framed = False docustom = 0 if type == 'ok': buttons = gtk.BUTTONS_OK style = gtk.MESSAGE_INFO elif type == 'warning': buttons = gtk.BUTTONS_OK style = gtk.MESSAGE_WARNING elif type == 'okcancel': buttons = gtk.BUTTONS_OK_CANCEL style = gtk.MESSAGE_WARNING elif type == 'yesno': buttons = gtk.BUTTONS_YES_NO style = gtk.MESSAGE_QUESTION elif type == 'custom': docustom = 1 buttons = gtk.BUTTONS_NONE style = gtk.MESSAGE_QUESTION if custom_icon == "warning": style = gtk.MESSAGE_WARNING elif custom_icon == "question": style = gtk.MESSAGE_QUESTION elif custom_icon == "error": style = gtk.MESSAGE_ERROR elif custom_icon == "info": style = gtk.MESSAGE_INFO self.dialog = gtk.MessageDialog(mainWindow, 0, style, buttons, text) if parent: self.dialog.set_transient_for(parent) if docustom: rid=0 for button in custom_buttons: if button == _("Cancel"): tbutton = "gtk-cancel" else: tbutton = button widget = self.dialog.add_button(tbutton, rid) rid = rid + 1 defaultchoice = rid - 1 if flags.debug: widget = self.dialog.add_button(_("_Debug"), rid) self.debugRid = rid rid += 1 else: if default == "no": defaultchoice = 0 elif default == "yes" or default == "ok": defaultchoice = 1 else: defaultchoice = 0 self.dialog.set_position (gtk.WIN_POS_CENTER) self.dialog.set_default_response(defaultchoice) if run: self.run(destroyAfterRun) def run(self, destroy = False): if not self.framed: addFrame(self.dialog, title=self.title) self.framed = True self.dialog.show_all () # XXX - Messy - turn off busy cursor if necessary busycursor = getBusyCursorStatus() setCursorToNormal() rc = self.dialog.run() if rc == gtk.RESPONSE_OK or rc == gtk.RESPONSE_YES: self.rc = 1 elif (rc == gtk.RESPONSE_CANCEL or rc == gtk.RESPONSE_NO or rc == gtk.RESPONSE_CLOSE): self.rc = 0 elif rc == gtk.RESPONSE_DELETE_EVENT: self.rc = 0 else: self.rc = rc if not self.debugRid is None and self.rc == self.debugRid: self.debugClicked(self) return self.run(destroy) if destroy: self.dialog.destroy() # restore busy cursor if busycursor: setCursorToBusy() def debugClicked (self, *args): try: # switch to VC1 so we can debug isys.vtActivate (1) except SystemError: pass import pdb try: pdb.set_trace() except: sys.exit(-1) try: # switch back isys.vtActivate (6) except SystemError: pass class EntryWindow(MessageWindow): def __init__ (self, title, text, prompt, entrylength = None): mainWindow = None MessageWindow.__init__(self, title, text, type = "okcancel", custom_icon="question", run = False) self.entry = gtk.Entry() if entrylength: self.entry.set_width_chars(entrylength) self.entry.set_max_length(entrylength) # eww, eww, eww... but if we pack in the vbox, it goes to the right # place! self.dialog.child.pack_start(self.entry) def run(self): MessageWindow.run(self) if self.rc == 0: return None t = self.entry.get_text() t.strip() if len(t) == 0: return None return t def destroy(self): self.dialog.destroy() class InstallInterface: def __init__ (self): self.icw = None # figure out if we want to run interface at 800x600 or 640x480 if gtk.gdk.screen_width() >= 800: self.runres = "800x600" else: self.runres = "640x480" root = gtk.gdk.get_default_root_window() cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR) root.set_cursor(cursor) def __del__ (self): pass def shutdown (self): pass def setPackageProgressWindow (self, ppw): self.ppw = ppw def waitWindow (self, title, text): if self.icw: return WaitWindow (title, text, self.icw.window) else: return WaitWindow (title, text) def progressWindow (self, title, text, total, updpct = 0.05): if self.icw: return ProgressWindow (title, text, total, updpct, self.icw.window) else: return ProgressWindow (title, text, total, updpct) def packageProgressWindow (self, total, totalSize): self.ppw.setSizes (total, totalSize) return self.ppw def messageWindow(self, title, text, type="ok", default = None, custom_buttons=None, custom_icon=None): if self.icw: parent = self.icw.window else: parent = None rc = MessageWindow (title, text, type, default, custom_buttons, custom_icon, run=True, parent=parent).getrc() return rc def entryWindow(self, title, text, type="ok", entrylength = None): d = EntryWindow(title, text, type, entrylength) rc = d.run() d.destroy() return rc def exceptionWindow(self, shortText, longTextFile): log.critical(shortText) win = ExceptionWindow (shortText, longTextFile) return win def scpWindow(self): return ScpWindow() def getInstallKey(self, anaconda, key = ""): d = InstallKeyWindow(anaconda, key) rc = d.run() if rc == gtk.RESPONSE_CANCEL: ret = None else: ret = d.get_key() d.destroy() return ret def beep(self): gtk.gdk.beep() def kickstartErrorWindow(self, text): s = _("The following error was found while parsing your " "kickstart configuration:\n\n%s") %(text,) return self.messageWindow(_("Error Parsing Kickstart Config"), s, type = "custom", custom_buttons = [_("_Exit installer")], custom_icon = "error") def dumpWindow(self): window = MessageWindow("Save Crash Dump", _("Please insert a floppy now. All contents " "of the disk will be erased, so please " "choose your diskette carefully."), "okcancel") rc = window.getrc() return not rc def getBootdisk (self): return None def run(self, anaconda): self.anaconda = anaconda # XXX x_already_set is a hack if anaconda.id.keyboard and not anaconda.id.x_already_set: anaconda.id.keyboard.activate() anaconda.id.fsset.registerMessageWindow(self.messageWindow) anaconda.id.fsset.registerProgressWindow(self.progressWindow) anaconda.id.fsset.registerWaitWindow(self.waitWindow) parted.exception_set_handler(partedExceptionWindow) self.icw = InstallControlWindow (self.anaconda) self.icw.run (self.runres) class InstallControlWindow: def setLanguage (self): if not self.__dict__.has_key('window'): return self.reloadRcQueued = 1 # need to reload our widgets self.setLtR() # reload the glade file, although we're going to keep our toplevel self.loadGlade() self.window.destroy() self.window = self.mainxml.get_widget("mainWindow") self.createWidgets() self.connectSignals() self.setScreen() self.window.show() def setLtR(self): ltrrtl = gettext.dgettext("gtk20", "default:LTR") if ltrrtl == "default:RTL": gtk.widget_set_default_direction (gtk.TEXT_DIR_RTL) elif ltrrtl == "default:LTR": gtk.widget_set_default_direction (gtk.TEXT_DIR_LTR) else: log.error("someone didn't translate the ltr bits right: %s" %(ltrrtl,)) gtk.widget_set_default_direction (gtk.TEXT_DIR_LTR) def prevClicked (self, *args): try: self.currentWindow.getPrev () except StayOnScreen: return self.anaconda.dispatch.gotoPrev() self.setScreen () def nextClicked (self, *args): try: rc = self.currentWindow.getNext () except StayOnScreen: return self.anaconda.dispatch.gotoNext() self.setScreen () def releaseNotesButtonClicked (self, widget): if not self.rnv.isShowing(): self.rnv.view() else: print "Release notes viewer already running" def debugClicked (self, *args): try: # switch to VC1 so we can debug isys.vtActivate (1) except SystemError: pass import pdb try: pdb.set_trace() except: sys.exit(-1) try: # switch back isys.vtActivate (6) except SystemError: pass def handleRenderCallback(self): self.currentWindow.renderCallback() if flags.autostep: if flags.autoscreenshot: # let things settle down graphically processEvents() time.sleep(1) takeScreenShot() self.nextClicked() else: gobject.source_remove(self.handle) def setScreen (self): (step, anaconda) = self.anaconda.dispatch.currentStep() if step is None: gtk.main_quit() return if not stepToClass[step]: if self.anaconda.dispatch.dir == DISPATCH_FORWARD: return self.nextClicked() else: return self.prevClicked() (file, className) = stepToClass[step] newScreenClass = None while 1: try: found = imputil.imp.find_module(file) loaded = imputil.imp.load_module(className, found[0], found[1], found[2]) newScreenClass = loaded.__dict__[className] break except ImportError, e: print e win = MessageWindow(_("Error!"), _("An error occurred when attempting " "to load an installer interface " "component.\n\nclassName = %s") % (className,), type="custom", custom_icon="warning", custom_buttons=[_("_Exit"), _("_Retry")]) if not win.getrc(): if flags.rootpath: msg = _("The installer will now exit...") buttons = [_("_Exit installer")] else: msg = _("Your system will now be rebooted...") buttons = [_("_Reboot")] MessageWindow(_("Exiting"), msg, type="custom", custom_icon="warning", custom_buttons=buttons) sys.exit(0) ics = InstallControlState (self) ics.setPrevEnabled(self.anaconda.dispatch.canGoBack()) self.destroyCurrentWindow() self.currentWindow = newScreenClass(ics) new_screen = self.currentWindow.getScreen(anaconda) if not new_screen: return self.update (ics) self.installFrame.add(new_screen) self.installFrame.show_all() self.handle = gobject.idle_add(self.handleRenderCallback) if self.reloadRcQueued: self.window.reset_rc_styles() self.reloadRcQueued = 0 def destroyCurrentWindow(self): children = self.installFrame.get_children () if children: child = children[0] self.installFrame.remove (child) child.destroy () self.currentWindow = None def update (self, ics): self.mainxml.get_widget("backButton").set_sensitive(ics.getPrevEnabled()) self.mainxml.get_widget("nextButton").set_sensitive(ics.getNextEnabled()) if ics.getGrabNext(): self.mainxml.get_widget("nextButton").grab_focus() def __init__ (self, anaconda): self.reloadRcQueued = 0 self.currentWindow = None self.anaconda = anaconda self.handle = None self.rnv = ReleaseNotesViewer(self.anaconda) def keyRelease (self, window, event): if ((event.keyval == gtk.keysyms.KP_Delete or event.keyval == gtk.keysyms.Delete) and (event.state & (gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK))): self._doExit() # XXX hack: remove me when the accelerators work again. elif (event.keyval == gtk.keysyms.F12 and self.currentWindow.getICS().getNextEnabled()): self.nextClicked() elif (event.keyval == gtk.keysyms.Print and event.state & gtk.gdk.SHIFT_MASK): takeScreenShot() def _doExit (self, *args): gtk.main_quit() os._exit(0) def createWidgets (self): self.window.set_title(_("%s Installer") %(productName,)) # FIXME: doesn't handle the lowres case i = self.mainxml.get_widget("headerImage") p = readImageFromFile("anaconda_header.png", dither = False, image = i) if p is None: print _("Unable to load title bar") if (gtk.gdk.screen_height() < 600) or \ (gtk.gdk.screen_height() <= 675 and not runningMiniWm()): i.hide() else: self.window.set_size_request(800, 600) self.window.set_position(gtk.WIN_POS_CENTER_ALWAYS) if flags.debug: self.mainxml.get_widget("debugButton").show_now() self.installFrame = self.mainxml.get_widget("installFrame") def connectSignals(self): sigs = { "on_nextButton_clicked": self.nextClicked, "on_rebootButton_clicked": self._doExit, "on_closeButton_clicked": self._doExit, "on_backButton_clicked": self.prevClicked, "on_relnotesButton_clicked": self.releaseNotesButtonClicked, "on_debugButton_clicked": self.debugClicked, "on_mainWindow_key_release_event": self.keyRelease, "on_mainWindow_delete_event": self._doExit, } self.mainxml.signal_autoconnect(sigs) def loadGlade(self): self.mainxml = gtk.glade.XML(findGladeFile("anaconda.glade"), domain="anaconda") def setup_window (self, runres): self.setLtR() self.loadGlade() self.window = self.mainxml.get_widget("mainWindow") self.createWidgets() self.connectSignals() self.setScreen() self.window.show() def busyCursorPush(self): rootPushBusyCursor() def busyCursorPop(self): rootPopBusyCursor() def run (self, runres): self.setup_window(runres) gtk.main() class InstallControlState: def __init__ (self, cw): self.cw = cw self.prevEnabled = True self.nextEnabled = True self.title = _("Install Window") self.grabNext = True def setTitle (self, title): self.title = title self.cw.update (self) def getTitle (self): return self.title def setPrevEnabled (self, value): if value == self.prevEnabled: return self.prevEnabled = value self.cw.update (self) def getPrevEnabled (self): return self.prevEnabled def setNextEnabled (self, value): if value == self.nextEnabled: return self.nextEnabled = value self.cw.update (self) def getNextEnabled (self): return self.nextEnabled def setScreenPrev (self): self.cw.prevClicked () def setScreenNext (self): self.cw.nextClicked () def setGrabNext (self, value): self.grabNext = value self.cw.update (self) def getGrabNext (self): return self.grabNext def getICW (self): return self.cw