# # partition_dialog_gui.py: dialog for editting a partition request # # 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 copy import gobject import gtk import gui from storage.devices import PartitionDevice, LUKSDevice from storage.deviceaction import * from partition_ui_helpers_gui import * from constants import * import gettext _ = lambda x: gettext.ldgettext("anaconda", x) class PartitionEditor: def sizespinchangedCB(self, widget, fillmaxszsb): size = widget.get_value_as_int() maxsize = fillmaxszsb.get_value_as_int() if size < 1: widget.set_value(1) size = 1 if size > maxsize: fillmaxszsb.set_value(size) # ugly got to be better way adj = fillmaxszsb.get_adjustment() adj.clamp_page(size, adj.upper) fillmaxszsb.set_adjustment(adj) def fillmaxszCB(self, widget, spin): spin.set_sensitive(widget.get_active()) # pass in CB defined above because of two scope limitation of python! def createSizeOptionsFrame(self, request, fillmaxszCB): frame = gtk.Frame(_("Additional Size Options")) sizeoptiontable = gtk.Table() sizeoptiontable.set_row_spacings(5) sizeoptiontable.set_border_width(4) fixedrb = gtk.RadioButton(label=_("_Fixed size")) fillmaxszrb = gtk.RadioButton(group=fixedrb, label=_("Fill all space _up " "to (MB):")) maxsizeAdj = gtk.Adjustment(value = 1, lower = 1, upper = MAX_PART_SIZE, step_incr = 1) fillmaxszsb = gtk.SpinButton(maxsizeAdj, digits = 0) fillmaxszsb.set_property('numeric', True) fillunlimrb = gtk.RadioButton(group=fixedrb, label=_("Fill to maximum _allowable " "size")) fillmaxszrb.connect("toggled", fillmaxszCB, fillmaxszsb) # default to fixed, turn off max size spinbutton fillmaxszsb.set_sensitive(0) if request.req_grow: if request.req_max_size: fillmaxszrb.set_active(1) fillmaxszsb.set_sensitive(1) fillmaxszsb.set_value(request.req_max_size) else: fillunlimrb.set_active(1) else: fixedrb.set_active(1) sizeoptiontable.attach(fixedrb, 0, 1, 0, 1) sizeoptiontable.attach(fillmaxszrb, 0, 1, 1, 2) sizeoptiontable.attach(fillmaxszsb, 1, 2, 1, 2) sizeoptiontable.attach(fillunlimrb, 0, 1, 2, 3) frame.add(sizeoptiontable) return (frame, fixedrb, fillmaxszrb, fillmaxszsb) def run(self): if self.dialog is None: return [] while 1: rc = self.dialog.run() actions = [] luksdev = None # user hit cancel, do nothing if rc in [2, gtk.RESPONSE_DELETE_EVENT]: self.destroy() return [] mountpoint = self.mountCombo.get_children()[0].get_text() if mountpoint: used = False for (mp, dev) in self.storage.mountpoints.iteritems(): if mp == mountpoint and \ dev.id != self.origrequest.id and \ not (self.origrequest.format.type == "luks" and self.origrequest in dev.parents): used = True break if used: self.intf.messageWindow(_("Mount point in use"), _("The mount point \"%s\" is in " "use. Please pick another.") % (mountpoint,), custom_icon="error") continue if not self.origrequest.exists: # read out UI into a partition specification fmt_class = self.newfstypeCombo.get_active_value() # there's nothing about origrequest we care about #request = copy.copy(self.origrequest) if self.primonlycheckbutton.get_active(): primary = True else: primary = None if self.fixedrb.get_active(): grow = None else: grow = True self.sizespin.update() if self.fillmaxszrb.get_active(): self.fillmaxszsb.update() maxsize = self.fillmaxszsb.get_value_as_int() else: maxsize = None allowdrives = [] model = self.driveview.get_model() iter = model.get_iter_first() while iter: val = model.get_value(iter, 0) drive = model.get_value(iter, 1) if val: allowdrives.append(drive) iter = model.iter_next(iter) if len(allowdrives) == len(self.storage.partitioned): allowdrives = None size = self.sizespin.get_value_as_int() disks = [] if allowdrives: for drive in allowdrives: for disk in self.storage.partitioned: if disk.name == drive: disks.append(disk) format = fmt_class(mountpoint=mountpoint) weight = self.anaconda.platform.weight(mountpoint=mountpoint, fstype=format.type) if self.isNew: request = self.storage.newPartition(size=size, grow=grow, maxsize=maxsize, primary=primary, format=format, parents=disks, weight=weight) else: request = self.origrequest request.weight = weight if self.lukscb and self.lukscb.get_active() and \ request.format.type != "luks": luksformat = format format = getFormat("luks", passphrase=self.storage.encryptionPassphrase) luksdev = LUKSDevice("luks%d" % self.storage.nextID, format=luksformat, parents=request) elif self.lukscb and not self.lukscb.get_active() and \ self.origrequest.format.type == "luks": # destroy the luks format and the mapped device try: luksdev = self.storage.devicetree.getChildren(self.origrequest)[0] except IndexError: pass else: actions.append(ActionDestroyFormat(luksdev)) actions.append(ActionDestroyDevice(luksdev)) luksdev = None actions.append(ActionDestroyFormat(request)) if self.isNew: # we're all set, so create the actions actions.append(ActionCreateDevice(request)) else: request.req_size = size request.req_base_size = size request.req_grow = grow request.req_max_size = maxsize request.req_primary = primary request.req_disks = disks actions.append(ActionCreateFormat(request, format)) if luksdev: actions.append(ActionCreateDevice(luksdev)) actions.append(ActionCreateFormat(luksdev)) else: # preexisting partition request = self.origrequest if request.format.type == "luks": try: usedev = self.storage.devicetree.getChildren(request)[0] except IndexError: usedev = request else: usedev = request origformat = usedev.format devicetree = self.anaconda.storage.devicetree if self.fsoptionsDict.has_key("formatcb"): if self.fsoptionsDict["formatcb"].get_active(): fmt_class = self.fsoptionsDict["fstypeCombo"].get_active_value() # carry over exists, migrate, size, and device # necessary for partition editor UI format = fmt_class(mountpoint=mountpoint, device=usedev.path) luksdev = None if self.fsoptionsDict.has_key("lukscb") and \ self.fsoptionsDict["lukscb"].get_active() and \ (request.format.type != "luks" or (request.format.exists and not request.format.hasKey)): luksdev = LUKSDevice("luks%d" % self.storage.nextID, format=format, parents=request) format = getFormat("luks", device=self.origrequest.path, passphrase=self.storage.encryptionPassphrase) elif self.fsoptionsDict.has_key("lukscb") and \ not self.fsoptionsDict["lukscb"].get_active() and \ request.format.type == "luks": # user elected to format the device w/o encryption try: luksdev = self.storage.devicetree.getChildren(request)[0] except IndexError: pass else: actions.append(ActionDestroyFormat(luksdev)) actions.append(ActionDestroyDevice(luksdev)) luksdev = None actions.append(ActionDestroyFormat(request)) # we set the new format's device while under the # impression that the device was going to be # encrypted, so we need to remedy that now format.device = request.path usedev = request actions.append(ActionCreateFormat(usedev, format)) if luksdev: actions.append(ActionCreateDevice(luksdev)) actions.append(ActionCreateFormat(luksdev)) elif not self.fsoptionsDict["formatcb"].get_active(): creates = devicetree.findActions(type="create", object="format", devid=usedev.id) for action in creates: devicetree.cancelAction(action) if usedev.format.mountable: usedev.format.mountpoint = mountpoint elif self.origrequest.protected and usedev.format.mountable: # users can set a mountpoint for protected partitions usedev.format.mountpoint = mountpoint request.weight = self.anaconda.platform.weight(mountpoint=mountpoint, fstype=request.format.type) if self.fsoptionsDict.has_key("migratecb") and \ self.fsoptionsDict["migratecb"].get_active(): actions.append(ActionMigrateFormat(usedev)) if self.fsoptionsDict.has_key("resizecb") and \ self.fsoptionsDict["resizecb"].get_active(): size = self.fsoptionsDict["resizesb"].get_value_as_int() try: actions.append(ActionResizeDevice(request, size)) if request.format.type and request.format.exists: actions.append(ActionResizeFormat(request, size)) except ValueError: pass if request.format.exists and \ getattr(request, "mountpoint", None) and \ self.storage.formatByDefault(request): if not queryNoFormatPreExisting(self.intf): continue # everything ok, fall out of loop break return actions def destroy(self): if self.dialog: self.dialog.destroy() self.dialog = None def __init__(self, anaconda, parent, origrequest, isNew = 0, restrictfs = None): self.anaconda = anaconda self.storage = self.anaconda.storage self.intf = self.anaconda.intf self.origrequest = origrequest self.isNew = isNew self.parent = parent if isNew: tstr = _("Add Partition") else: tstr = _("Edit Partition: %s") % (origrequest.path,) self.dialog = gtk.Dialog(tstr, self.parent) gui.addFrame(self.dialog) self.dialog.add_button('gtk-cancel', 2) self.dialog.add_button('gtk-ok', 1) self.dialog.set_position(gtk.WIN_POS_CENTER) maintable = gtk.Table() maintable.set_row_spacings(5) maintable.set_col_spacings(5) row = 0 # if this is a luks device we need to grab info from two devices # to make it seem like one device. wee! if self.origrequest.format.type == "luks": try: luksdev = self.storage.devicetree.getChildren(self.origrequest)[0] except IndexError: usereq = self.origrequest luksdev = None else: usereq = luksdev else: luksdev = None usereq = self.origrequest # Mount Point entry lbl = createAlignedLabel(_("_Mount Point:")) maintable.attach(lbl, 0, 1, row, row + 1) self.mountCombo = createMountPointCombo(usereq) lbl.set_mnemonic_widget(self.mountCombo) maintable.attach(self.mountCombo, 1, 2, row, row + 1) row = row + 1 # Partition Type if not self.origrequest.exists: lbl = createAlignedLabel(_("File System _Type:")) maintable.attach(lbl, 0, 1, row, row + 1) self.newfstypeCombo = createFSTypeMenu(usereq.format, fstypechangeCB, self.mountCombo, availablefstypes = restrictfs) lbl.set_mnemonic_widget(self.newfstypeCombo) maintable.attach(self.newfstypeCombo, 1, 2, row, row + 1) else: self.newfstypeCombo = None row = row + 1 # allowable drives if not self.origrequest.exists: lbl = createAlignedLabel(_("Allowable _Drives:")) maintable.attach(lbl, 0, 1, row, row + 1) req_disk_names = [d.name for d in self.origrequest.req_disks] self.driveview = createAllowedDrivesList(self.storage.partitioned, req_disk_names, disallowDrives=[self.anaconda.updateSrc]) lbl.set_mnemonic_widget(self.driveview) sw = gtk.ScrolledWindow() sw.add(self.driveview) sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) sw.set_shadow_type(gtk.SHADOW_IN) maintable.attach(sw, 1, 2, row, row + 1) self.driveview.set_size_request(375, 80) row = row + 1 # original fs label if usereq.format.exists and \ getattr(usereq.format, "label", None): maintable.attach(createAlignedLabel(_("Original File System " "Label:")), 0, 1, row, row + 1) fslabel = gtk.Label(usereq.format.label) maintable.attach(fslabel, 1, 2, row, row + 1) row = row + 1 # size if not self.origrequest.exists: # Size specification lbl = createAlignedLabel(_("_Size (MB):")) maintable.attach(lbl, 0, 1, row, row + 1) sizeAdj = gtk.Adjustment(value = 1, lower = 1, upper = MAX_PART_SIZE, step_incr = 1) self.sizespin = gtk.SpinButton(sizeAdj, digits = 0) self.sizespin.set_property('numeric', True) if self.origrequest.req_size: self.sizespin.set_value(self.origrequest.req_size) lbl.set_mnemonic_widget(self.sizespin) maintable.attach(self.sizespin, 1, 2, row, row + 1) else: self.sizespin = None row = row + 1 # format/migrate options for pre-existing partitions, as long as they # aren't protected (we'd still like to be able to mount them, though) self.fsoptionsDict = {} if self.origrequest.exists and \ not self.origrequest.protected: (row, self.fsoptionsDict) = createPreExistFSOptionSection(self.origrequest, maintable, row, self.mountCombo, self.storage, luksdev=luksdev) # size options if not self.origrequest.exists: (sizeframe, self.fixedrb, self.fillmaxszrb, self.fillmaxszsb) = self.createSizeOptionsFrame(self.origrequest, self.fillmaxszCB) self.sizespin.connect("value-changed", self.sizespinchangedCB, self.fillmaxszsb) maintable.attach(sizeframe, 0, 2, row, row + 1) row = row + 1 else: self.sizeoptiontable = None # create only as primary if not self.origrequest.exists: self.primonlycheckbutton = gtk.CheckButton(_("Force to be a _primary " "partition")) self.primonlycheckbutton.set_active(0) if self.origrequest.req_primary: self.primonlycheckbutton.set_active(1) # only show if we have something other than primary if self.storage.extendedPartitionsSupported(): maintable.attach(self.primonlycheckbutton, 0, 2, row, row+1) row = row + 1 # checkbutton for encryption using dm-crypt/LUKS if not self.origrequest.exists: self.lukscb = gtk.CheckButton(_("_Encrypt")) self.lukscb.set_data("formatstate", 1) if self.origrequest.format.type == "luks": self.lukscb.set_active(1) else: self.lukscb.set_active(0) maintable.attach(self.lukscb, 0, 2, row, row + 1) row = row + 1 # put main table into dialog self.dialog.vbox.pack_start(maintable) self.dialog.show_all()