Package pyanaconda :: Module gui
[hide private]
[frames] | no frames]

Source Code for Module pyanaconda.gui

   1  # 
   2  # gui.py - Graphical front end for anaconda 
   3  # 
   4  # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 
   5  # Red Hat, Inc.  All rights reserved. 
   6  # 
   7  # This program is free software; you can redistribute it and/or modify 
   8  # it under the terms of the GNU General Public License as published by 
   9  # the Free Software Foundation; either version 2 of the License, or 
  10  # (at your option) any later version. 
  11  # 
  12  # This program is distributed in the hope that it will be useful, 
  13  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  # GNU General Public License for more details. 
  16  # 
  17  # You should have received a copy of the GNU General Public License 
  18  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  19  # 
  20  # Author(s): Matt Wilson <msw@redhat.com> 
  21  #            Michael Fulbright <msf@redhat.com> 
  22  # 
  23   
  24  import os 
  25  from flags import flags 
  26  os.environ["GNOME_DISABLE_CRASH_DIALOG"] = "1" 
  27   
  28  import string 
  29  import time 
  30  import traceback 
  31  import isys 
  32  import iutil 
  33  import sys 
  34  import shutil 
  35  import gtk 
  36  import gtk.glade 
  37  import gobject 
  38  from constants import * 
  39  from product import * 
  40  import network 
  41  from installinterfacebase import InstallInterfaceBase 
  42  import imp 
  43  import iw 
  44   
  45  import gettext 
  46  _ = lambda x: gettext.ldgettext("anaconda", x) 
  47   
  48  import logging 
  49  log = logging.getLogger("anaconda") 
  50  stdout_log = logging.getLogger("anaconda.stdout") 
  51   
  52  isys.bind_textdomain_codeset("redhat-dist", "UTF-8") 
  53  iutil.setup_translations(gtk.glade) 
  54   
55 -class StayOnScreen(Exception):
56 pass
57 58 mainWindow = None 59 60 stepToClass = { 61 "language" : ("language_gui", "LanguageWindow"), 62 "keyboard" : ("kbd_gui", "KeyboardWindow"), 63 "filtertype" : ("filter_type", "FilterTypeWindow"), 64 "filter" : ("filter_gui", "FilterWindow"), 65 "partition" : ("partition_gui", "PartitionWindow"), 66 "parttype" : ("autopart_type", "PartitionTypeWindow"), 67 "cleardiskssel": ("cleardisks_gui", "ClearDisksWindow"), 68 "findinstall" : ("examine_gui", "UpgradeExamineWindow"), 69 "upgrademigratefs" : ("upgrade_migratefs_gui", "UpgradeMigrateFSWindow"), 70 "bootloader": ("bootloader_main_gui", "MainBootloaderWindow"), 71 "upgbootloader": ("upgrade_bootloader_gui", "UpgradeBootloaderWindow"), 72 "network" : ("network_gui", "NetworkWindow"), 73 "timezone" : ("timezone_gui", "TimezoneWindow"), 74 "accounts" : ("account_gui", "AccountWindow"), 75 "tasksel": ("task_gui", "TaskWindow"), 76 "group-selection": ("package_gui", "GroupSelectionWindow"), 77 "install" : ("progress_gui", "InstallProgressWindow"), 78 "complete" : ("congrats_gui", "CongratulationWindow"), 79 } 80 81 if iutil.isS390(): 82 stepToClass["bootloader"] = ("zipl_gui", "ZiplWindow") 83
84 -def idle_gtk(func, *args, **kwargs):
85 def return_false(func, *args, **kwargs): 86 gtk.gdk.threads_enter() 87 func(*args, **kwargs) 88 gtk.gdk.threads_leave() 89 return False
90 gobject.idle_add(return_false, func, *args, **kwargs) 91 92 # 93 # Stuff for screenshots 94 # 95 screenshotDir = "/tmp/anaconda-screenshots" 96 screenshotIndex = 0 97
98 -def copyScreenshots():
99 # see if any screenshots taken 100 if screenshotIndex == 0: 101 return 102 103 destDir = "/mnt/sysimage/root/anaconda-screenshots" 104 if not os.access(destDir, os.R_OK): 105 try: 106 os.mkdir(destDir, 0750) 107 except OSError: 108 window = MessageWindow("Error Saving Screenshot", 109 _("An error occurred saving screenshots " 110 "to disk."), type="warning") 111 return 112 113 # Now copy all the PNGs over. Since some pictures could have been taken 114 # under a root changed to /mnt/sysimage, we have to try to fetch files from 115 # there as well. 116 source_dirs = [screenshotDir, os.path.join("/mnt/sysimage", screenshotDir.lstrip('/'))] 117 for source_dir in source_dirs: 118 if not os.access(source_dir, os.X_OK): 119 continue 120 for f in os.listdir(source_dir): 121 (path, fname) = os.path.split(f) 122 (b, ext) = os.path.splitext(f) 123 if ext == ".png": 124 shutil.copyfile(source_dir + '/' + f, destDir + '/' + fname) 125 126 window = MessageWindow(_("Screenshots Copied"), 127 _("The screenshots have been saved in the " 128 "directory:\n\n" 129 "\t/root/anaconda-screenshots/\n\n" 130 "You can access these when you reboot and " 131 "login as root."))
132
133 -def takeScreenShot():
134 global screenshotIndex 135 136 if not os.access(screenshotDir, os.R_OK): 137 try: 138 os.mkdir(screenshotDir) 139 except OSError as e: 140 log.error("os.mkdir() failed for %s: %s" % (screenshotDir, e.strerror)) 141 return 142 143 try: 144 screenshot = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 145 gtk.gdk.screen_width(), gtk.gdk.screen_height()) 146 screenshot.get_from_drawable(gtk.gdk.get_default_root_window(), 147 gtk.gdk.colormap_get_system(), 148 0, 0, 0, 0, 149 gtk.gdk.screen_width(), 150 gtk.gdk.screen_height()) 151 152 if screenshot: 153 while True: 154 sname = "screenshot-%04d.png" % ( screenshotIndex,) 155 if not os.access(screenshotDir + '/' + sname, os.R_OK): 156 break 157 158 screenshotIndex += 1 159 if screenshotIndex > 9999: 160 log.error("Too many screenshots!") 161 return 162 163 screenshot.save (screenshotDir + '/' + sname, "png") 164 screenshotIndex += 1 165 166 window = MessageWindow(_("Saving Screenshot"), 167 _("A screenshot named '%s' has been saved.") % (sname,) , 168 type="ok") 169 except Exception: 170 # FIXME: find out what exceptions gtk.gdk.Pixbuf might actually raise 171 window = MessageWindow(_("Error Saving Screenshot"), 172 _("An error occurred while saving " 173 "the screenshot. If this occurred " 174 "during package installation, you may need " 175 "to try several times for it to succeed."), 176 type="warning")
177
178 -def handlePrintScrnRelease (window, event):
179 if event.keyval == gtk.keysyms.Print: 180 takeScreenShot()
181 # 182 # HACK to make treeview work 183 # 184
185 -def setupTreeViewFixupIdleHandler(view, store):
186 id = {} 187 id["id"] = gobject.idle_add(scrollToIdleHandler, (view, store, id))
188
189 -def scrollToIdleHandler((view, store, iddict)):
190 if not view or not store or not iddict: 191 return 192 193 try: 194 id = iddict["id"] 195 except: 196 return 197 198 selection = view.get_selection() 199 if not selection: 200 return 201 202 model, iter = selection.get_selected() 203 if not iter: 204 return 205 206 path = store.get_path(iter) 207 col = view.get_column(0) 208 view.scroll_to_cell(path, col, True, 0.5, 0.5) 209 210 if id: 211 gobject.source_remove(id)
212 213 # setup globals
214 -def processEvents():
215 gtk.gdk.flush() 216 while gtk.events_pending(): 217 gtk.main_iteration(False)
218
219 -def widgetExpander(widget, growTo=None):
220 widget.connect("size-allocate", growToParent, growTo)
221
222 -def growToParent(widget, rect, growTo=None):
223 if not widget.parent: 224 return 225 ignore = widget.__dict__.get("ignoreEvents") 226 if not ignore: 227 if growTo: 228 x, y, width, height = growTo.get_allocation() 229 widget.set_size_request(width, -1) 230 else: 231 widget.set_size_request(rect.width, -1) 232 widget.ignoreEvents = 1 233 else: 234 widget.ignoreEvents = 0
235 236 _busyCursor = 0 237
238 -def setCursorToBusy(process=1):
239 root = gtk.gdk.get_default_root_window() 240 cursor = gtk.gdk.Cursor(gtk.gdk.WATCH) 241 root.set_cursor(cursor) 242 if process: 243 processEvents()
244
245 -def setCursorToNormal():
246 root = gtk.gdk.get_default_root_window() 247 cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR) 248 root.set_cursor(cursor)
249
250 -def rootPushBusyCursor(process=1):
251 global _busyCursor 252 _busyCursor += 1 253 if _busyCursor > 0: 254 setCursorToBusy(process)
255
256 -def rootPopBusyCursor():
257 global _busyCursor 258 _busyCursor -= 1 259 if _busyCursor <= 0: 260 setCursorToNormal()
261
262 -def getBusyCursorStatus():
263 global _busyCursor 264 265 return _busyCursor
266
267 -class MnemonicLabel(gtk.Label):
268 - def __init__(self, text="", alignment = None):
269 gtk.Label.__init__(self, "") 270 self.set_text_with_mnemonic(text) 271 if alignment is not None: 272 apply(self.set_alignment, alignment)
273
274 -class WrappingLabel(gtk.Label):
275 - def __init__(self, label=""):
276 gtk.Label.__init__(self, label) 277 self.set_line_wrap(True) 278 self.ignoreEvents = 0 279 widgetExpander(self)
280
281 -def addFrame(dialog, title=None):
282 # make screen shots work 283 dialog.connect ("key-release-event", handlePrintScrnRelease) 284 if title: 285 dialog.set_title(title)
286
287 -def findGladeFile(file):
288 path = os.environ.get("GLADEPATH", "./:ui/:/tmp/updates/:/tmp/updates/ui/") 289 for dir in path.split(":"): 290 fn = dir + file 291 if os.access(fn, os.R_OK): 292 return fn 293 raise RuntimeError, "Unable to find glade file %s" % file
294
295 -def getGladeWidget(file, rootwidget, i18ndomain="anaconda"):
296 f = findGladeFile(file) 297 xml = gtk.glade.XML(f, root = rootwidget, domain = i18ndomain) 298 w = xml.get_widget(rootwidget) 299 if w is None: 300 raise RuntimeError, "Unable to find root widget %s in %s" %(rootwidget, file) 301 302 return (xml, w)
303
304 -def findPixmap(file):
305 path = os.environ.get("PIXMAPPATH", "./:pixmaps/:/tmp/updates/:/tmp/updates/pixmaps/") 306 for dir in path.split(":"): 307 fn = dir + file 308 if os.access(fn, os.R_OK): 309 return fn 310 return None
311
312 -def getPixbuf(file):
313 fn = findPixmap(file) 314 if not fn: 315 log.error("unable to load %s" %(file,)) 316 return None 317 318 try: 319 pixbuf = gtk.gdk.pixbuf_new_from_file(fn) 320 except RuntimeError as msg: 321 log.error("unable to read %s: %s" %(file, msg)) 322 pixbuf = None 323 324 return pixbuf
325
326 -def readImageFromFile(file, dither = False, image = None):
327 pixbuf = getPixbuf(file) 328 if pixbuf is None: 329 log.warning("can't find pixmap %s" %(file,)) 330 return None 331 332 if image is None: 333 p = gtk.Image() 334 else: 335 p = image 336 if dither: 337 (pixmap, mask) = pixbuf.render_pixmap_and_mask() 338 pixmap.draw_pixbuf(gtk.gdk.GC(pixmap), pixbuf, 0, 0, 0, 0, 339 pixbuf.get_width(), pixbuf.get_height(), 340 gtk.gdk.RGB_DITHER_MAX, 0, 0) 341 p = gtk.Image() 342 p.set_from_pixmap(pixmap, mask) 343 else: 344 source = gtk.IconSource() 345 source.set_pixbuf(pixbuf) 346 source.set_size(gtk.ICON_SIZE_DIALOG) 347 source.set_size_wildcarded(False) 348 iconset = gtk.IconSet() 349 iconset.add_source(source) 350 p.set_from_icon_set(iconset, gtk.ICON_SIZE_DIALOG) 351 352 return p
353
354 -class WaitWindow:
355 - def __init__(self, title, text, parent = None):
356 if flags.livecdInstall: 357 self.window = gtk.Window() 358 if parent: 359 self.window.set_transient_for(parent) 360 else: 361 self.window = gtk.Window() 362 self.window.set_modal(True) 363 self.window.set_type_hint (gtk.gdk.WINDOW_TYPE_HINT_DIALOG) 364 self.window.set_title(title) 365 self.window.set_position(gtk.WIN_POS_CENTER) 366 label = WrappingLabel(text) 367 box = gtk.Frame() 368 box.set_border_width(10) 369 box.add(label) 370 box.set_shadow_type(gtk.SHADOW_NONE) 371 self.window.add(box) 372 box.show_all() 373 addFrame(self.window) 374 # Displaying windows should not be done outside of the gtk 375 # mainloop. With metacity this bites us and we have to do 376 # window.show_now() AND refresh() to correctly display the window and 377 # its contents: 378 self.window.show_now() 379 rootPushBusyCursor() 380 self.refresh()
381
382 - def refresh(self):
384
385 - def pop(self):
386 self.window.destroy() 387 rootPopBusyCursor()
388
389 -class ProgressWindow:
390 - def __init__(self, title, text, total, updpct = 0.05, updsecs=10, 391 parent = None, pulse = False):
392 if flags.livecdInstall: 393 self.window = gtk.Window() 394 if parent: 395 self.window.set_transient_for(parent) 396 else: 397 self.window = gtk.Window() 398 399 self.window.set_modal(True) 400 self.window.set_type_hint (gtk.gdk.WINDOW_TYPE_HINT_DIALOG) 401 self.window.set_title (title) 402 self.window.set_position (gtk.WIN_POS_CENTER) 403 self.lastUpdate = time.time() 404 self.updsecs = updsecs 405 box = gtk.VBox (False, 5) 406 box.set_border_width (10) 407 408 label = WrappingLabel (text) 409 label.set_alignment (0.0, 0.5) 410 box.pack_start (label, False) 411 412 self.total = total 413 self.updpct = updpct 414 self.progress = gtk.ProgressBar () 415 box.pack_start (self.progress, True) 416 box.show_all() 417 self.window.add(box) 418 addFrame(self.window) 419 # see comment at WaitWindow.__init__(): 420 self.window.show_now () 421 rootPushBusyCursor() 422 self.refresh()
423
424 - def refresh(self):
426
427 - def pulse(self):
428 then = self.lastUpdate 429 now = time.time() 430 delta = now-then 431 if delta < 0.01: 432 return 433 self.progress.set_pulse_step(self.updpct) 434 self.lastUpdate = now 435 # if we've had a largish gap, some smoothing does actually help, 436 # but don't go crazy 437 if delta > 2: 438 delta=2 439 while delta > 0: 440 self.progress.pulse() 441 processEvents() 442 delta -= 0.05
443
444 - def set (self, amount):
445 amount = min(amount, self.total) 446 447 # only update widget if we've changed by 5% or our timeout has 448 # expired 449 curval = self.progress.get_fraction() 450 newval = float (amount) / self.total 451 then = self.lastUpdate 452 now = time.time() 453 if newval < 0.998: 454 if ((newval - curval) < self.updpct and (now-then) < self.updsecs): 455 return 456 self.lastUpdate = now 457 self.progress.set_fraction (newval) 458 processEvents ()
459
460 - def pop(self):
461 self.window.destroy () 462 rootPopBusyCursor()
463
464 -class luksPassphraseWindow:
465 - def __init__(self, passphrase=None, preexist = False, parent = None):
466 luksxml = gtk.glade.XML(findGladeFile("lukspassphrase.glade"), 467 domain="anaconda", 468 root="luksPassphraseDialog") 469 self.passphraseEntry = luksxml.get_widget("passphraseEntry") 470 self.passphraseEntry.set_visibility(False) 471 self.confirmEntry = luksxml.get_widget("confirmEntry") 472 self.confirmEntry.set_visibility(False) 473 self.win = luksxml.get_widget("luksPassphraseDialog") 474 self.okButton = luksxml.get_widget("okbutton1") 475 self.globalcheckbutton = luksxml.get_widget("globalcheckbutton") 476 477 self.isglobal = preexist 478 if not preexist: 479 self.globalcheckbutton.hide() 480 else: 481 self.globalcheckbutton.set_active(True) 482 483 self.minimumLength = 8 # arbitrary; should probably be much larger 484 if passphrase: 485 self.initialPassphrase = passphrase 486 self.passphraseEntry.set_text(passphrase) 487 self.confirmEntry.set_text(passphrase) 488 else: 489 self.initialPassphrase = "" 490 491 txt = _("Choose a passphrase for the encrypted devices. " 492 "You will be prompted for this passphrase during system " 493 "boot.") 494 luksxml.get_widget("mainLabel").set_text(txt) 495 496 if parent: 497 self.win.set_transient_for(parent) 498 499 addFrame(self.win)
500
501 - def run(self):
502 self.win.show() 503 while True: 504 self.passphraseEntry.grab_focus() 505 self.rc = self.win.run() 506 if self.rc == gtk.RESPONSE_OK: 507 passphrase = self.passphraseEntry.get_text() 508 confirm = self.confirmEntry.get_text() 509 if passphrase != confirm: 510 MessageWindow(_("Error with passphrase"), 511 _("The passphrases you entered were " 512 "different. Please try again."), 513 type = "ok", custom_icon = "error") 514 self.confirmEntry.set_text("") 515 continue 516 517 if len(passphrase) < self.minimumLength: 518 MessageWindow(_("Error with passphrase"), 519 _("The passphrase must be at least " 520 "eight characters long."), 521 type = "ok", custom_icon = "error") 522 self.passphraseEntry.set_text("") 523 self.confirmEntry.set_text("") 524 continue 525 526 if self.isglobal: 527 self.isglobal = self.globalcheckbutton.get_active() 528 else: 529 self.passphraseEntry.set_text(self.initialPassphrase) 530 self.confirmEntry.set_text(self.initialPassphrase) 531 532 return self.rc
533
534 - def getPassphrase(self):
535 return self.passphraseEntry.get_text()
536
537 - def getGlobal(self):
538 return self.isglobal
539
540 - def getrc(self):
541 return self.rc
542
543 - def destroy(self):
544 self.win.destroy()
545
546 -class PassphraseEntryWindow:
547 - def __init__(self, device, parent = None):
548 def ok(*args): 549 self.win.response(gtk.RESPONSE_OK)
550 xml = gtk.glade.XML(findGladeFile("lukspassphrase.glade"), 551 domain="anaconda", 552 root="passphraseEntryDialog") 553 self.txt = _("Device %s is encrypted. In order to " 554 "access the device's contents during " 555 "installation you must enter the device's " 556 "passphrase below.") % (device,) 557 self.win = xml.get_widget("passphraseEntryDialog") 558 self.passphraseLabel = xml.get_widget("passphraseLabel") 559 self.passphraseEntry = xml.get_widget("passphraseEntry2") 560 561 if parent: 562 self.win.set_transient_for(parent) 563 564 self.passphraseEntry.connect('activate', ok) 565 addFrame(self.win)
566
567 - def run(self):
568 self.win.show() 569 self.passphraseLabel.set_text(self.txt) 570 self.passphraseEntry.grab_focus() 571 572 busycursor = getBusyCursorStatus() 573 setCursorToNormal() 574 575 rc = self.win.run() 576 passphrase = None 577 if rc == gtk.RESPONSE_OK: 578 passphrase = self.passphraseEntry.get_text() 579 580 if busycursor: 581 setCursorToBusy() 582 583 self.rc = passphrase 584 return self.rc
585
586 - def getrc(self):
587 return self.rc
588
589 - def destroy(self):
590 self.win.destroy()
591
592 -class MessageWindow:
593 - def getrc (self):
594 return self.rc
595
596 - def __init__ (self, title, text, type="ok", default=None, custom_buttons=None, custom_icon=None, run = True, parent = None, destroyAfterRun = True):
597 self.debugRid = None 598 self.title = title 599 if flags.autostep: 600 self.rc = 1 601 return 602 self.rc = None 603 self.framed = False 604 self.doCustom = False 605 606 style = 0 607 if type == 'ok': 608 buttons = gtk.BUTTONS_OK 609 style = gtk.MESSAGE_INFO 610 elif type == 'warning': 611 buttons = gtk.BUTTONS_OK 612 style = gtk.MESSAGE_WARNING 613 elif type == 'okcancel': 614 buttons = gtk.BUTTONS_OK_CANCEL 615 style = gtk.MESSAGE_WARNING 616 elif type == 'yesno': 617 buttons = gtk.BUTTONS_YES_NO 618 style = gtk.MESSAGE_QUESTION 619 elif type == 'custom': 620 self.doCustom = True 621 buttons = gtk.BUTTONS_NONE 622 style = gtk.MESSAGE_QUESTION 623 624 if custom_icon == "warning": 625 style = gtk.MESSAGE_WARNING 626 elif custom_icon == "question": 627 style = gtk.MESSAGE_QUESTION 628 elif custom_icon == "error": 629 style = gtk.MESSAGE_ERROR 630 elif custom_icon == "info": 631 style = gtk.MESSAGE_INFO 632 633 self.dialog = gtk.MessageDialog(mainWindow, 0, style, buttons, str(text)) 634 self.dialog.set_property("use-markup", True) 635 636 if parent: 637 self.dialog.set_transient_for(parent) 638 639 if self.doCustom: 640 rid=0 641 for button in custom_buttons: 642 if button == _("Cancel"): 643 tbutton = "gtk-cancel" 644 else: 645 tbutton = button 646 647 widget = self.dialog.add_button(tbutton, rid) 648 rid = rid + 1 649 650 if default is not None: 651 defaultchoice = default 652 else: 653 defaultchoice = rid - 1 654 if flags.debug and not _("_Debug") in custom_buttons: 655 widget = self.dialog.add_button(_("_Debug"), rid) 656 self.debugRid = rid 657 rid += 1 658 659 else: 660 if default == "no": 661 defaultchoice = 0 662 elif default == "yes" or default == "ok": 663 defaultchoice = 1 664 else: 665 defaultchoice = 0 666 667 self.dialog.set_position (gtk.WIN_POS_CENTER) 668 self.dialog.set_default_response(defaultchoice) 669 if run: 670 self.run(destroyAfterRun)
671
672 - def run(self, destroy = False):
673 if not self.framed: 674 addFrame(self.dialog, title=self.title) 675 self.framed = True 676 self.dialog.show_all () 677 678 # XXX - Messy - turn off busy cursor if necessary 679 busycursor = getBusyCursorStatus() 680 setCursorToNormal() 681 self.rc = self.dialog.run() 682 683 if not self.doCustom: 684 if self.rc in [gtk.RESPONSE_OK, gtk.RESPONSE_YES]: 685 self.rc = 1 686 elif self.rc in [gtk.RESPONSE_CANCEL, gtk.RESPONSE_NO, 687 gtk.RESPONSE_CLOSE, gtk.RESPONSE_DELETE_EVENT]: 688 self.rc = 0 689 else: 690 # generated by Esc key 691 if self.rc == gtk.RESPONSE_DELETE_EVENT: 692 self.rc = 0 693 694 if not self.debugRid is None and self.rc == self.debugRid: 695 self.debugClicked(self) 696 return self.run(destroy) 697 698 if destroy: 699 self.dialog.destroy() 700 701 # restore busy cursor 702 if busycursor: 703 setCursorToBusy()
704
705 - def debugClicked (self, *args):
706 try: 707 # switch to VC1 so we can debug 708 isys.vtActivate (1) 709 except SystemError: 710 pass 711 import pdb 712 try: 713 pdb.set_trace() 714 except Exception: 715 # FIXME: what exceptions might pdb.set_trace raise? 716 sys.exit(-1) 717 try: 718 # switch back 719 isys.vtActivate (6) 720 except SystemError: 721 pass
722
723 -class ReinitializeWindow(MessageWindow):
724
725 - def __init__ (self, title, path, size, description, 726 default=None, run=True, parent=None, destroyAfterRun=True):
727 728 self.debugRid = None 729 self.title = title 730 if flags.autostep: 731 self.rc = 1 732 return 733 self.rc = None 734 self.framed = False 735 self.doCustom = False 736 737 xml = gtk.glade.XML(findGladeFile("reinitialize-dialog.glade"), 738 domain="anaconda") 739 740 self.dialog = xml.get_widget("reinitializeDialog") 741 self.apply_to_all = xml.get_widget("apply_to_all") 742 743 self.label = xml.get_widget("disk_label") 744 text = "<b>%s</b>\n%s MB\t%s" % (description, size, path) 745 self.label.set_markup(text) 746 747 if parent: 748 self.dialog.set_transient_for(parent) 749 self.dialog.set_position(gtk.WIN_POS_CENTER) 750 751 if flags.debug: 752 widget = self.dialog.add_button(_("_Debug"), 2) 753 self.debugRid = 2 754 755 defaultchoice = 0 #no 756 self.dialog.set_default_response(defaultchoice) 757 758 if run: 759 self.run(destroyAfterRun)
760
761 - def run(self, destroy=False):
762 MessageWindow.run(self, destroy) 763 apply_all = self.apply_to_all.get_active() 764 765 # doCustom is false, so we will have self.rc set up as following: 766 # if "Yes, discard" was clicked - self.rc = 1 767 # if "No, keep" was clicked - self.rc = 0 768 if self.rc == 1: #yes 769 self.rc = 3 if apply_all else 2 770 elif self.rc == 0: #no 771 self.rc = 1 if apply_all else 0
772
773 -class DetailedMessageWindow(MessageWindow):
774 - def __init__(self, title, text, longText=None, type="ok", default=None, custom_buttons=None, custom_icon=None, run=True, parent=None, destroyAfterRun=True, expanded=False):
775 self.title = title 776 777 if flags.autostep: 778 self.rc = 1 779 return 780 781 self.debugRid = None 782 self.rc = None 783 self.framed = False 784 self.doCustom = False 785 786 if type == 'ok': 787 buttons = ["gtk-ok"] 788 elif type == 'warning': 789 buttons = ["gtk-ok"] 790 elif type == 'okcancel': 791 buttons = ["gtk-ok", "gtk-cancel"] 792 elif type == 'yesno': 793 buttons = ["gtk-yes", "gtk-no"] 794 elif type == 'custom': 795 self.doCustom = True 796 buttons = custom_buttons 797 798 xml = gtk.glade.XML(findGladeFile("detailed-dialog.glade"), domain="anaconda") 799 self.dialog = xml.get_widget("detailedDialog") 800 self.mainVBox = xml.get_widget("mainVBox") 801 self.hbox = xml.get_widget("hbox1") 802 self.info = xml.get_widget("info") 803 self.detailedExpander = xml.get_widget("detailedExpander") 804 self.detailedView = xml.get_widget("detailedView") 805 806 self.detailedExpander.set_expanded(expanded) 807 808 if parent: 809 self.dialog.set_transient_for(parent) 810 811 if custom_icon: 812 str_to_gtk_stock = { 813 "warning" : gtk.STOCK_DIALOG_WARNING, 814 "question": gtk.STOCK_DIALOG_QUESTION, 815 "error" : gtk.STOCK_DIALOG_ERROR, 816 "info" : gtk.STOCK_DIALOG_INFO } 817 img = gtk.Image() 818 stock = str_to_gtk_stock.get(custom_icon, None) 819 if stock: 820 img.set_from_stock(stock, gtk.ICON_SIZE_DIALOG) 821 else: 822 img.set_from_file(custom_icon) 823 self.hbox.pack_start(img) 824 self.hbox.reorder_child(img, 0) 825 826 rid = 0 827 for button in buttons: 828 self.dialog.add_button(button, rid) 829 rid += 1 830 831 if self.doCustom: 832 defaultchoice = rid-1 833 if flags.debug and not _("_Debug") in buttons: 834 self.dialog.add_button(_("_Debug"), rid) 835 self.debugRid = rid 836 rid += 1 837 else: 838 if default == "no": 839 defaultchoice = 0 840 elif default == "yes" or default == "ok": 841 defaultchoice = 1 842 else: 843 defaultchoice = 0 844 845 self.info.set_text(text) 846 847 if longText: 848 textbuf = gtk.TextBuffer() 849 iter = textbuf.get_start_iter() 850 851 for line in longText: 852 if __builtins__.get("type")(line) != unicode: 853 try: 854 line = unicode(line, encoding='utf-8') 855 except UnicodeDecodeError as e: 856 log.error("UnicodeDecodeException: line = %s" % (line,)) 857 log.error("UnicodeDecodeException: %s" % (str(e),)) 858 859 textbuf.insert(iter, line) 860 861 self.detailedView.set_buffer(textbuf) 862 else: 863 self.mainVBox.remove(self.detailedExpander) 864 865 self.dialog.set_position (gtk.WIN_POS_CENTER) 866 self.dialog.set_default_response(defaultchoice) 867 868 if run: 869 self.run(destroyAfterRun)
870
871 -class InstallInterface(InstallInterfaceBase):
872 - def __init__ (self):
873 InstallInterfaceBase.__init__(self) 874 self.icw = None 875 self.installProgress = None 876 877 root = gtk.gdk.get_default_root_window() 878 cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR) 879 root.set_cursor(cursor)
880
881 - def __del__ (self):
882 pass
883
884 - def shutdown(self):
885 if self.icw: 886 self.icw.close()
887
888 - def suspend(self):
889 pass
890
891 - def resume(self):
892 pass
893 894 895 # just_setup is used for [Configure Network] button
896 - def enableNetwork(self, just_setup=False):
897 898 if len(self.anaconda.network.netdevices) == 0: 899 return False 900 901 902 from iw.network_gui import (runNMCE, 903 selectInstallNetDeviceDialog, 904 selectSSIDsDialog) 905 906 networkEnabled = False 907 while not networkEnabled: 908 909 # We need to do it in each iteration because user can 910 # delete ifcfg file in nm-c-e 911 nm_controlled_devices = [devname for (devname, dev) 912 in self.anaconda.network.netdevices.items() 913 if not dev.usedByFCoE(self.anaconda)] 914 if not just_setup and not nm_controlled_devices: 915 return False 916 917 if just_setup: 918 install_device = None 919 else: 920 install_device = selectInstallNetDeviceDialog(self.anaconda.network, 921 nm_controlled_devices) 922 if not install_device: 923 break 924 925 # update ifcfg files for nm-c-e 926 self.anaconda.network.setNMControlledDevices(nm_controlled_devices) 927 928 # we might want to do this only once 929 if self.anaconda.network.hasWirelessDev(): 930 # NOTE: For wireless, we need supplicant to go to ready state, 931 # that means to get the wireless device managed by NM 932 self.anaconda.network.writeIfcfgFiles() 933 w = self.anaconda.intf.waitWindow(_("Wireless setup"), 934 _("Scanning access points for wireless devices")) 935 # get available wireless APs 936 dev_all_ssids = self.anaconda.network.getSSIDs() 937 w.pop() 938 # select wireless APs 939 dev_ssids = selectSSIDsDialog(dev_all_ssids) or dev_all_ssids 940 self.anaconda.network.writeSSIDifcfgs(dev_ssids) 941 942 self.anaconda.network.writeIfcfgFiles() 943 # Logging can race here with ifcfg-rh updating the file 944 network.logIfcfgFiles(message="Dump before nm-c-e (can race " 945 "with ifcfg updating). ") 946 runNMCE(self.anaconda) 947 network.logIfcfgFiles(message="Dump after nm-c-e. ") 948 949 self.anaconda.network.update() 950 951 if just_setup: 952 waited_devs = self.anaconda.network.getOnbootControlledIfaces() 953 else: 954 waited_devs = [install_device] 955 self.anaconda.network.updateActiveDevices([install_device]) 956 957 self.anaconda.network.write() 958 959 if waited_devs: 960 w = WaitWindow(_("Waiting for NetworkManager"), 961 _("Waiting for NetworkManager to activate " 962 "these devices: %s") % ",".join(waited_devs)) 963 failed_devs = self.anaconda.network.waitForDevicesActivation(waited_devs) 964 w.pop() 965 966 if just_setup: 967 if failed_devs: 968 self._handleDeviceActivationFail(failed_devs) 969 if len(failed_devs) < len(waited_devs): 970 # if any device was activated, remember to reset 971 # resolver 972 networkEnabled = True 973 else: 974 networkEnabled = install_device not in failed_devs 975 if not networkEnabled: 976 self._handleNetworkError(install_device) 977 978 if just_setup: 979 break 980 981 if networkEnabled: 982 network.resetResolver() 983 return networkEnabled
984
985 - def _handleDeviceActivationFail(self, devices):
986 d = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, 987 gtk.BUTTONS_OK, 988 _("Failed to activate these " 989 "network interfaces: %s" % 990 ",".join(devices))) 991 d.set_title(_("Network Configuration")) 992 d.set_position(gtk.WIN_POS_CENTER) 993 addFrame(d) 994 d.run() 995 d.destroy()
996
997 - def _handleNetworkError(self, field):
998 d = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, 999 gtk.BUTTONS_OK, 1000 _("An error occurred trying to bring up the " 1001 "%s network interface.") % (field,)) 1002 d.set_title(_("Error Enabling Network")) 1003 d.set_position(gtk.WIN_POS_CENTER) 1004 addFrame(d) 1005 d.run() 1006 d.destroy()
1007
1008 - def setInstallProgressClass(self, c):
1009 self.instProgress = c
1010
1011 - def setPackageProgressWindow (self, ppw):
1012 self.ppw = ppw
1013
1014 - def waitWindow (self, title, text):
1015 if self.icw: 1016 return WaitWindow (title, text, self.icw.window) 1017 else: 1018 return WaitWindow (title, text)
1019
1020 - def progressWindow (self, title, text, total, updpct = 0.05, pulse = False):
1021 if self.icw: 1022 return ProgressWindow (title, text, total, updpct, 1023 parent = self.icw.window, pulse = pulse) 1024 else: 1025 return ProgressWindow (title, text, total, updpct, pulse = pulse)
1026
1027 - def messageWindow(self, title, text, type="ok", default = None, 1028 custom_buttons=None, custom_icon=None):
1029 if self.icw: 1030 parent = self.icw.window 1031 else: 1032 parent = None 1033 1034 rc = MessageWindow (title, text, type, default, 1035 custom_buttons, custom_icon, run=True, parent=parent).getrc() 1036 return rc
1037
1038 - def reinitializeWindow(self, title, path, size, description):
1039 if self.icw: 1040 parent = self.icw.window 1041 else: 1042 parent = None 1043 1044 rc = ReinitializeWindow(title, path, size, description, parent=parent).getrc() 1045 return rc
1046
1047 - def editRepoWindow(self, repoObj):
1048 from iw.task_gui import RepoEditor 1049 dialog = RepoEditor(self.anaconda, repoObj) 1050 dialog.createDialog() 1051 dialog.run()
1052
1053 - def methodstrRepoWindow(self, methodstr, exception):
1054 from iw.task_gui import RepoMethodstrEditor 1055 1056 self.messageWindow( 1057 _("Error Setting Up Repository"), 1058 _("The following error occurred while setting up the " 1059 "installation repository:\n\n%(e)s\n\nPlease provide the " 1060 "correct information for installing %(productName)s.") 1061 % {'e': exception, 'productName': productName}) 1062 1063 dialog = RepoMethodstrEditor(self.anaconda, methodstr) 1064 dialog.createDialog() 1065 return dialog.run()
1066
1067 - def detailedMessageWindow(self, title, text, longText=None, type="ok", 1068 default=None, custom_buttons=None, 1069 custom_icon=None, expanded=False):
1070 if self.icw: 1071 parent = self.icw.window 1072 else: 1073 parent = None 1074 1075 rc = DetailedMessageWindow (title, text, longText, type, default, 1076 custom_buttons, custom_icon, run=True, 1077 parent=parent, expanded=expanded).getrc() 1078 return rc
1079
1080 - def mainExceptionWindow(self, shortText, longTextFile):
1081 from meh.ui.gui import MainExceptionWindow 1082 log.critical(shortText) 1083 win = MainExceptionWindow (shortText, longTextFile) 1084 addFrame(win.dialog) 1085 return win
1086
1087 - def saveExceptionWindow(self, accountManager, signature):
1088 from meh.ui.gui import SaveExceptionWindow 1089 import urlgrabber 1090 1091 if not network.hasActiveNetDev(): 1092 if self.messageWindow(_("Warning"), 1093 _("You do not have an active network connection. This is " 1094 "required by some exception saving methods. Would you " 1095 "like to configure your network now?"), 1096 type = "yesno"): 1097 1098 if not self.enableNetwork(): 1099 self.messageWindow(_("No Network Available"), 1100 _("Remote exception saving methods will not work.")) 1101 else: 1102 urlgrabber.grabber.reset_curl_obj() 1103 1104 win = SaveExceptionWindow (accountManager, signature) 1105 win.run()
1106
1107 - def exitWindow(self, title, text):
1108 if self.icw: 1109 parent = self.icw.window 1110 else: 1111 parent = None 1112 1113 rc = MessageWindow (title, text, type="custom", 1114 custom_icon="info", parent=parent, 1115 custom_buttons=[_("_Exit installer")]).getrc() 1116 return rc
1117
1118 - def getLuksPassphrase(self, passphrase = "", preexist = False):
1119 if self.icw: 1120 parent = self.icw.window 1121 else: 1122 parent = None 1123 1124 d = luksPassphraseWindow(passphrase, parent = parent, 1125 preexist = preexist) 1126 rc = d.run() 1127 passphrase = d.getPassphrase() 1128 isglobal = d.getGlobal() 1129 d.destroy() 1130 return (passphrase, isglobal)
1131
1132 - def passphraseEntryWindow(self, device):
1133 if self.icw: 1134 parent = self.icw.window 1135 else: 1136 parent = None 1137 1138 d = PassphraseEntryWindow(device, parent = parent) 1139 rc = d.run() 1140 d.destroy() 1141 return rc
1142
1143 - def beep(self):
1144 gtk.gdk.beep()
1145
1146 - def kickstartErrorWindow(self, text):
1147 s = _("The following error was found while parsing the " 1148 "kickstart configuration file:\n\n%s") %(text,) 1149 return self.messageWindow(_("Error Parsing Kickstart Config"), 1150 s, 1151 type = "custom", 1152 custom_buttons = [_("_Exit installer")], 1153 custom_icon = "error")
1154
1155 - def display_step(self, step):
1156 return self.icw.display_step(step)
1157
1158 - def getBootdisk (self):
1159 return None
1160
1161 - def run(self, anaconda):
1162 self.anaconda = anaconda 1163 1164 if anaconda.keyboard and not flags.livecdInstall: 1165 anaconda.keyboard.activate() 1166 1167 self.icw = InstallControlWindow(self.anaconda) 1168 self.icw.run()
1169
1170 -class InstallControlWindow:
1171 - def setLanguage (self):
1172 if not self.__dict__.has_key('window'): return 1173 self.reloadRcQueued = 1 1174 self.setup_window(True)
1175
1176 - def setLtR(self):
1177 ltrrtl = gettext.dgettext("gtk20", "default:LTR") 1178 if ltrrtl == "default:RTL": 1179 gtk.widget_set_default_direction (gtk.TEXT_DIR_RTL) 1180 elif ltrrtl == "default:LTR": 1181 gtk.widget_set_default_direction (gtk.TEXT_DIR_LTR) 1182 else: 1183 log.error("someone didn't translate the ltr bits right: %s" %(ltrrtl,)) 1184 gtk.widget_set_default_direction (gtk.TEXT_DIR_LTR)
1185
1186 - def prevClicked (self, *args):
1187 try: 1188 self.currentWindow.getPrev () 1189 except StayOnScreen: 1190 return 1191 1192 self.anaconda.dispatch.go_back()
1193
1194 - def nextClicked (self, *args):
1195 try: 1196 rc = self.currentWindow.getNext () 1197 except StayOnScreen: 1198 return 1199 1200 self.anaconda.dispatch.go_forward()
1201
1202 - def debugClicked (self, *args):
1203 try: 1204 # switch to VC1 so we can debug 1205 isys.vtActivate (1) 1206 except SystemError: 1207 pass 1208 import pdb 1209 try: 1210 pdb.set_trace() 1211 except Exception: 1212 sys.exit(-1) 1213 try: 1214 # switch back 1215 isys.vtActivate (6) 1216 except SystemError: 1217 pass
1218
1219 - def handleRenderCallback(self):
1220 self.currentWindow.renderCallback() 1221 if flags.autostep: 1222 if flags.autoscreenshot: 1223 # let things settle down graphically 1224 processEvents() 1225 time.sleep(1) 1226 takeScreenShot() 1227 self.nextClicked() 1228 else: 1229 gobject.source_remove(self.handle)
1230
1231 - def display_step(self, step):
1232 (file, className) = stepToClass[step] 1233 newScreenClass = None 1234 1235 while True: 1236 try: 1237 found = imp.find_module(file, iw.__path__) 1238 moduleName = 'pyanaconda.iw.%s' % file 1239 loaded = imp.load_module(moduleName, *found) 1240 newScreenClass = loaded.__dict__[className] 1241 break 1242 except ImportError as e: 1243 stdout_log.error("loading interface component %s" % className) 1244 stdout_log.error(traceback.format_exc()) 1245 win = MessageWindow(_("Error!"), 1246 _("An error occurred when attempting " 1247 "to load an installer interface " 1248 "component.\n\nclassName = %s") 1249 % (className,), 1250 type="custom", custom_icon="warning", 1251 custom_buttons=[_("_Exit"), 1252 _("_Retry")]) 1253 if not win.getrc(): 1254 msg = _("The system will now reboot.") 1255 buttons = [_("_Reboot")] 1256 1257 MessageWindow(_("Exiting"), 1258 msg, 1259 type="custom", 1260 custom_icon="warning", 1261 custom_buttons=buttons) 1262 sys.exit(0) 1263 1264 ics = InstallControlState (self) 1265 ics.setPrevEnabled(self.anaconda.dispatch.can_go_back()) 1266 self.destroyCurrentWindow() 1267 self.currentWindow = newScreenClass(ics) 1268 1269 new_screen = self.currentWindow.getScreen(self.anaconda) 1270 1271 # If the getScreen method returned None, that means the screen did not 1272 # want to be displayed for some reason and we should skip to the next 1273 # step. However, we do not want to remove the current step from the 1274 # list as later events may cause the screen to be displayed. 1275 if not new_screen: 1276 return DISPATCH_DEFAULT 1277 1278 self.update (ics) 1279 self.installFrame.add(new_screen) 1280 self.installFrame.show_all() 1281 self.currentWindow.focus() 1282 self.handle = gobject.idle_add(self.handleRenderCallback) 1283 if self.reloadRcQueued: 1284 self.window.reset_rc_styles() 1285 self.reloadRcQueued = 0 1286 1287 # the screen is displayed, we wait for the user now 1288 return DISPATCH_WAITING
1289
1290 - def destroyCurrentWindow(self):
1291 children = self.installFrame.get_children () 1292 if children: 1293 child = children[0] 1294 self.installFrame.remove (child) 1295 child.destroy () 1296 self.currentWindow = None
1297
1298 - def update (self, ics):
1299 self.mainxml.get_widget("backButton").set_sensitive(ics.getPrevEnabled()) 1300 self.mainxml.get_widget("nextButton").set_sensitive(ics.getNextEnabled()) 1301 1302 if ics.getGrabNext(): 1303 self.mainxml.get_widget("nextButton").grab_focus() 1304 1305 self.mainxml.get_widget("nextButton").set_flags(gtk.HAS_DEFAULT)
1306
1307 - def __init__ (self, anaconda):
1308 self._main_loop_running = False 1309 self.reloadRcQueued = 0 1310 self.currentWindow = None 1311 self.anaconda = anaconda 1312 self.handle = None 1313 self.window = None
1314
1315 - def keyRelease (self, window, event):
1316 if ((event.keyval == gtk.keysyms.KP_Delete 1317 or event.keyval == gtk.keysyms.Delete) 1318 and (event.state & (gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK))): 1319 self.close() 1320 # XXX hack: remove me when the accelerators work again. 1321 elif (event.keyval == gtk.keysyms.F12 1322 and self.currentWindow.getICS().getNextEnabled()): 1323 self.nextClicked() 1324 elif event.keyval == gtk.keysyms.Print: 1325 takeScreenShot()
1326
1327 - def close(self, *args):
1328 if self._main_loop_running: 1329 gtk.main_quit() 1330 self._main_loop_running = False
1331
1332 - def _doExitConfirm (self, win = None, *args):
1333 win = MessageWindow(_("Exit installer"), 1334 _("Are you sure you wish to exit the installer?"), 1335 type="custom", custom_icon="question", 1336 custom_buttons = [_("Cancel"), _("_Exit installer")], 1337 parent = win) 1338 if win.getrc() == 0: 1339 return True 1340 sys.exit(0)
1341
1342 - def createWidgets (self):
1343 """ Sets up the widgets in the main installler window. """ 1344 self.window.set_title(_("%s Installer") %(productName,)) 1345 1346 i = self.mainxml.get_widget("headerImage") 1347 p = readImageFromFile("anaconda_header.png", 1348 dither = False, image = i) 1349 if p is None: 1350 print(_("Unable to load title bar")) 1351 1352 if flags.livecdInstall: 1353 i.hide() 1354 self.window.set_resizable(True) 1355 self.window.maximize() 1356 elif flags.preexisting_x11: 1357 # Forwarded X11, don't take over their whole screen 1358 i.hide() 1359 self.window.set_resizable(True) 1360 else: 1361 # Normal install, full screen 1362 self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DESKTOP) 1363 if gtk.gdk.screen_height() < 600: 1364 i.hide() 1365 1366 width = None 1367 height = None 1368 xrandr = iutil.execWithCapture("xrandr", ["-q"], stderr="/dev/tty5") 1369 lines = xrandr.splitlines() 1370 xrandr = filter(lambda x: "current" in x, lines) 1371 if xrandr and len(xrandr) == 1: 1372 fields = xrandr[0].split() 1373 pos = fields.index('current') 1374 if len(fields) > pos + 3: 1375 width = int(fields[pos + 1]) 1376 height = int(fields[pos + 3].replace(',', '')) 1377 1378 if width and height: 1379 self.window.set_size_request(min(width, 800), min(height, 600)) 1380 1381 self.window.show() 1382 1383 if flags.debug: 1384 self.mainxml.get_widget("debugButton").show_now() 1385 self.installFrame = self.mainxml.get_widget("installFrame")
1386
1387 - def connectSignals(self):
1388 sigs = { "on_nextButton_clicked": self.nextClicked, 1389 "on_rebootButton_clicked": self.close, 1390 "on_closeButton_clicked": self.close, 1391 "on_backButton_clicked": self.prevClicked, 1392 "on_debugButton_clicked": self.debugClicked, 1393 "on_mainWindow_key_release_event": self.keyRelease, 1394 "on_mainWindow_delete_event": self._doExitConfirm, } 1395 self.mainxml.signal_autoconnect(sigs)
1396
1397 - def loadGlade(self):
1398 self.mainxml = gtk.glade.XML(findGladeFile("anaconda.glade"), 1399 domain="anaconda")
1400
1401 - def setup_window (self, window_reload):
1402 self.setLtR() 1403 1404 if window_reload: 1405 self.window.destroy() 1406 elif flags.livecdInstall: 1407 pixbuf = getPixbuf("anaconda.png") 1408 gtk.window_set_default_icon(pixbuf) 1409 1410 self.loadGlade() 1411 self.window = self.mainxml.get_widget("mainWindow") 1412 1413 self.createWidgets() 1414 self.connectSignals() 1415 # 'Back and 'Next' is disabled by default 1416 icw = InstallControlState(self) 1417 icw.setPrevEnabled(False) 1418 icw.setNextEnabled(False) 1419 self.window.show() 1420 # calling present() will focus the window in the winodw manager so 1421 # the mnemonics work without additional clicking 1422 self.window.present()
1423
1424 - def run (self):
1425 self.setup_window(False) 1426 # start the dispatcher right after the main loop is started: 1427 idle_gtk(self.anaconda.dispatch.dispatch) 1428 self._main_loop_running = True 1429 gtk.main()
1430
1431 -class InstallControlState:
1432 - def __init__ (self, cw):
1433 self.cw = cw 1434 self.prevEnabled = True 1435 self.nextEnabled = True 1436 self.title = _("Install Window") 1437 self.grabNext = True
1438
1439 - def setTitle (self, title):
1440 self.title = title 1441 self.cw.update (self)
1442
1443 - def getTitle (self):
1444 return self.title
1445
1446 - def setPrevEnabled (self, value):
1447 if value == self.prevEnabled: return 1448 self.prevEnabled = value 1449 self.cw.update (self)
1450
1451 - def getPrevEnabled (self):
1452 return self.prevEnabled
1453
1454 - def setNextEnabled (self, value):
1455 if value == self.nextEnabled: return 1456 self.nextEnabled = value 1457 self.cw.update (self)
1458
1459 - def getNextEnabled (self):
1460 return self.nextEnabled
1461
1462 - def setGrabNext (self, value):
1463 self.grabNext = value 1464 self.cw.update (self)
1465
1466 - def getGrabNext (self):
1467 return self.grabNext
1468
1469 - def getICW (self):
1470 return self.cw
1471