#
# partition_ui_helpers_gui.py: convenience functions for partition_gui.py
# and friends.
#
# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty 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, see .
#
# Author(s): Michael Fulbright
#
import gobject
import gtk
import checklist
import datacombo
import iutil
from constants import *
from partIntfHelpers import *
from storage.formats import *
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
FLAG_FORMAT = 1
FLAG_MIGRATE = 2
class WideCheckList(checklist.CheckList):
def toggled_item(self, data, row):
rc = True
if self.clickCB:
rc = self.clickCB(data, row)
if rc:
checklist.CheckList.toggled_item(self, data, row)
def __init__(self, columns, store, clickCB=None, sensitivity=False):
checklist.CheckList.__init__(self, columns=columns,
custom_store=store,
sensitivity=sensitivity)
# make checkbox column wider
column = self.get_column(columns)
self.set_expander_column(column)
column = self.get_column(0)
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
column.set_fixed_width(25)
self.clickCB = clickCB
def createAlignedLabel(text):
label = gtk.Label(text)
label.set_alignment(0.0, 0.5)
label.set_property("use-underline", True)
return label
defaultMountPoints = ['/', '/boot', '/home', '/tmp', '/usr',
'/var', '/usr/local', '/opt']
if iutil.isS390():
# Many s390 have 2G DASDs, we recomment putting /usr/share on its own DASD
defaultMountPoints.insert(5, '/usr/share')
if iutil.isEfi():
defaultMountPoints.insert(2, '/boot/efi')
def createMountPointCombo(request, excludeMountPoints=[]):
mountCombo = gtk.combo_box_entry_new_text()
mntptlist = []
label = getattr(request.format, "label", None)
if request.exists and label and label.startswith("/"):
mntptlist.append(label)
idx = 0
for p in defaultMountPoints:
if p in excludeMountPoints:
continue
if not p in mntptlist and (p[0] == "/"):
mntptlist.append(p)
map(mountCombo.append_text, mntptlist)
if (request.format.type or request.format.migrate) and \
request.format.mountable:
mountpoint = request.format.mountpoint
mountCombo.set_sensitive(1)
if mountpoint:
mountCombo.get_children()[0].set_text(mountpoint)
else:
mountCombo.get_children()[0].set_text("")
else:
mountCombo.get_children()[0].set_text(_(""))
mountCombo.set_sensitive(0)
mountCombo.set_data("saved_mntpt", None)
return mountCombo
def setMntPtComboStateFromType(fmt_class, mountCombo):
prevmountable = mountCombo.get_data("prevmountable")
mountpoint = mountCombo.get_data("saved_mntpt")
format = fmt_class()
if prevmountable and format.mountable:
return
if format.mountable:
mountCombo.set_sensitive(1)
if mountpoint != None:
mountCombo.get_children()[0].set_text(mountpoint)
else:
mountCombo.get_children()[0].set_text("")
else:
if mountCombo.get_children()[0].get_text() != _(""):
mountCombo.set_data("saved_mntpt", mountCombo.get_children()[0].get_text())
mountCombo.get_children()[0].set_text(_(""))
mountCombo.set_sensitive(0)
mountCombo.set_data("prevmountable", format.mountable)
def fstypechangeCB(widget, mountCombo):
fstype = widget.get_active_value()
setMntPtComboStateFromType(fstype, mountCombo)
def createAllowedDrivesStore(disks, reqdrives, drivelist, selectDrives=True,
disallowDrives=[]):
drivelist.clear()
for disk in disks:
selected = 0
if selectDrives:
if reqdrives:
if disk.name in reqdrives:
selected = 1
else:
if disk.name not in disallowDrives:
selected = 1
sizestr = "%8.0f MB" % disk.size
drivelist.append_row((disk.name,
sizestr,
disk.description),
selected)
if len(disks) < 2:
drivelist.set_sensitive(False)
else:
drivelist.set_sensitive(True)
def createAllowedDrivesList(disks, reqdrives, selectDrives=True, disallowDrives=[]):
store = gtk.TreeStore(gobject.TYPE_BOOLEAN,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_BOOLEAN)
drivelist = WideCheckList(3, store, sensitivity=True)
createAllowedDrivesStore(disks, reqdrives, drivelist, selectDrives=selectDrives,
disallowDrives=disallowDrives)
return drivelist
# pass in callback for when fs changes because of python scope issues
def createFSTypeMenu(format, fstypechangeCB, mountCombo,
availablefstypes = None, ignorefs = None):
store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
fstypecombo = datacombo.DataComboBox(store)
if availablefstypes:
names = availablefstypes
else:
names = device_formats.keys()
if format and format.supported and format.formattable:
default = format.type
else:
default = get_default_filesystem_type()
names.sort()
defindex = 0
i = 0
for name in names:
# we could avoid instantiating them all if we made a static class
# method that does what the supported property does
format = device_formats[name]()
if not format.supported:
continue
if ignorefs and name in ignorefs:
continue
if format.formattable:
fstypecombo.append(format.name, device_formats[name])
if default == name:
defindex = i
defismountable = format.mountable
i = i + 1
fstypecombo.set_active(defindex)
if fstypechangeCB and mountCombo:
fstypecombo.connect("changed", fstypechangeCB, mountCombo)
if mountCombo:
mountCombo.set_data("prevmountable",
fstypecombo.get_active_value()().mountable)
mountCombo.connect("changed", mountptchangeCB, fstypecombo)
return fstypecombo
def mountptchangeCB(widget, fstypecombo):
if iutil.isEfi() and widget.get_children()[0].get_text() == "/boot/efi":
fstypecombo.set_active_text(getFormat("efi").name)
if widget.get_children()[0].get_text() == "/boot":
fstypecombo.set_active_text(get_default_filesystem_type(boot=True))
def resizeOptionCB(widget, resizesb):
resizesb.set_sensitive(widget.get_active())
def formatOptionResizeCB(widget, data):
(resizesb, fmt) = data
if widget.get_active():
lower = 1
else:
lower = resizesb.get_data("reqlower")
adj = resizesb.get_adjustment()
adj.lower = lower
resizesb.set_adjustment(adj)
if resizesb.get_value_as_int() < lower:
resizesb.set_value(adj.lower)
def formatMigrateOptionCB(widget, data):
(sensitive,) = widget.get_properties('sensitive')
if not sensitive:
return
(combowidget, mntptcombo, fs, lukscb, othercombo, othercb, flag) = data
combowidget.set_sensitive(widget.get_active())
if othercb is not None:
othercb.set_sensitive(not widget.get_active())
othercb.set_active(False)
if othercombo is not None:
othercombo.set_sensitive(othercb.get_active())
if lukscb is not None:
lukscb.set_data("formatstate", widget.get_active())
if not widget.get_active():
# set "Encrypt" checkbutton to match partition's initial state
lukscb.set_active(lukscb.get_data("encrypted"))
lukscb.set_sensitive(False)
else:
lukscb.set_sensitive(True)
# inject event for fstype menu
if widget.get_active():
fstype = combowidget.get_active_value()
setMntPtComboStateFromType(fstype, mntptcombo)
combowidget.grab_focus()
else:
if isinstance(fs, type(fs)):
fs = type(fs)
setMntPtComboStateFromType(fs, mntptcombo)
def createPreExistFSOptionSection(origrequest, maintable, row, mountCombo,
partitions, ignorefs=[], luksdev=None):
""" createPreExistFSOptionSection: given inputs for a preexisting partition,
create a section that will provide format and migrate options
Returns the value of row after packing into the maintable,
and a dictionary consistenting of:
formatcb - checkbutton for 'format as new fs'
fstype - part of format fstype menu
fstypeMenu - part of format fstype menu
migratecb - checkbutton for migrate fs
migfstypeMenu - menu for migrate fs types
lukscb - checkbutton for 'encrypt using LUKS/dm-crypt'
resizecb - checkbutton for 'resize fs'
resizesb - spinbutton with resize target
"""
rc = {}
if luksdev:
origfs = luksdev.format
else:
origfs = origrequest.format
if origfs.formattable or not origfs.type:
formatcb = gtk.CheckButton(label=_("_Format as:"))
maintable.attach(formatcb, 0, 1, row, row + 1)
formatcb.set_active(origfs.formattable and not origfs.exists)
rc["formatcb"] = formatcb
fstypeCombo = createFSTypeMenu(origfs, fstypechangeCB,
mountCombo, ignorefs=ignorefs)
fstypeCombo.set_sensitive(formatcb.get_active())
maintable.attach(fstypeCombo, 1, 2, row, row + 1)
row += 1
rc["fstypeCombo"] = fstypeCombo
else:
formatcb = None
fstypeCombo = None
if formatcb and not formatcb.get_active() and not origfs.migrate:
mountCombo.set_data("prevmountable", origfs.mountable)
# this gets added to the table a bit later on
lukscb = gtk.CheckButton(_("_Encrypt"))
if origfs.migratable and origfs.exists:
migratecb = gtk.CheckButton(label=_("Mi_grate filesystem to:"))
if formatcb is not None:
migratecb.set_active(origfs.migrate and (not formatcb.get_active()))
else:
migratecb.set_active(origfs.migrate)
migtypes = [origfs.migrationTarget]
maintable.attach(migratecb, 0, 1, row, row + 1)
migfstypeCombo = createFSTypeMenu(origfs,
None, None,
availablefstypes = migtypes)
migfstypeCombo.set_sensitive(migratecb.get_active())
maintable.attach(migfstypeCombo, 1, 2, row, row + 1)
row = row + 1
rc["migratecb"] = migratecb
rc["migfstypeCombo"] = migfstypeCombo
migratecb.connect("toggled", formatMigrateOptionCB,
(migfstypeCombo, mountCombo, origfs, None,
fstypeCombo, formatcb, FLAG_MIGRATE))
else:
migratecb = None
migfstypeCombo = None
if formatcb:
formatcb.connect("toggled", formatMigrateOptionCB,
(fstypeCombo, mountCombo, origfs, lukscb,
migfstypeCombo, migratecb, FLAG_FORMAT))
if origrequest.resizable and origfs.exists:
resizecb = gtk.CheckButton(label=_("_Resize"))
resizecb.set_active(origfs.resizable and \
(origfs.currentSize != origfs.targetSize) and \
(origfs.currentSize != 0))
rc["resizecb"] = resizecb
maintable.attach(resizecb, 0, 1, row, row + 1)
if origrequest.targetSize is not None:
value = origrequest.targetSize
else:
value = origrequest.size
reqlower = 1
requpper = origrequest.maxSize
if origfs.exists:
reqlower = origrequest.minSize
if origrequest.type == "partition":
geomsize = origrequest.partedPartition.geometry.getSize(unit="MB")
if (geomsize != 0) and (requpper > geomsize):
requpper = geomsize
adj = gtk.Adjustment(value = value, lower = reqlower,
upper = requpper, step_incr = 1)
resizesb = gtk.SpinButton(adj, digits = 0)
resizesb.set_property('numeric', True)
resizesb.set_data("requpper", requpper)
resizesb.set_data("reqlower", reqlower)
rc["resizesb"] = resizesb
maintable.attach(resizesb, 1, 2, row, row + 1)
resizecb.connect('toggled', resizeOptionCB, resizesb)
resizeOptionCB(resizecb, resizesb)
row = row + 1
if formatcb:
formatcb.connect("toggled", formatOptionResizeCB, (resizesb, origfs))
if luksdev:
lukscb.set_active(1)
if origrequest.originalFormat.type == "luks":
lukscb.set_data("encrypted", 1)
else:
lukscb.set_data("encrypted", 0)
if formatcb:
lukscb.set_sensitive(formatcb.get_active())
lukscb.set_data("formatstate", formatcb.get_active())
else:
lukscb.set_sensitive(0)
lukscb.set_data("formatstate", 0)
rc["lukscb"] = lukscb
maintable.attach(lukscb, 0, 2, row, row + 1)
row = row + 1
return (row, rc)
# do tests we just want in UI for now, not kickstart
def doUIRAIDLVMChecks(request, storage):
fstype = request.format.name
numdrives = len(storage.partitioned)
## if fstype and fstype.getName() == "physical volume (LVM)":
## if request.grow:
## return (_("Partitions of type '%s' must be of fixed size, and "
## "cannot be marked to fill to use available space.")) % (fstype.getName(),)
if fstype in ["physical volume (LVM)", "software RAID"]:
if numdrives > 1 and (not request.req_disks or len(request.req_disks) > 1):
return (_("Partitions of type '%s' must be constrained to "
"a single drive. To do this, select the "
"drive in the 'Allowable Drives' checklist.")) % (fstype.getName(),)
return None