def _setup_slider(self, device, value): """Set up the slider for this device, pulling out any previously given shrink value as the default. This also sets up the ticks on the slider and keyboard support. Any devices that are not resizable will not have a slider displayed, so they do not need to be worried with here. """ self._resizeSlider.handler_block_by_func(self.on_resize_value_changed) self._resizeSlider.set_range(device.minSize, device.size) self._resizeSlider.handler_unblock_by_func( self.on_resize_value_changed) self._resizeSlider.set_value(value) # The slider needs to be keyboard-accessible. We'll make small movements change in # 1% increments, and large movements in 5% increments. distance = device.size - device.minSize onePercent = distance * 0.01 fivePercent = distance * 0.05 twentyPercent = distance * 0.2 adjustment = self.builder.get_object("resizeAdjustment") adjustment.configure(value, device.minSize, device.size, onePercent, fivePercent, 0) # And then the slider needs a couple tick marks for easier navigation. self._resizeSlider.clear_marks() for i in range(1, 5): self._resizeSlider.add_mark(device.minSize + i * twentyPercent, Gtk.PositionType.BOTTOM, None) # Finally, add tick marks for the ends. self._resizeSlider.add_mark(device.minSize, Gtk.PositionType.BOTTOM, size_str(device.minSize)) self._resizeSlider.add_mark(device.size, Gtk.PositionType.BOTTOM, size_str(device.size))
def _setup_slider(self, device, value): """Set up the slider for this device, pulling out any previously given shrink value as the default. This also sets up the ticks on the slider and keyboard support. Any devices that are not resizable will not have a slider displayed, so they do not need to be worried with here. """ self._resizeSlider.set_range(device.minSize, device.size) self._resizeSlider.set_value(value) # The slider needs to be keyboard-accessible. We'll make small movements change in # 1% increments, and large movements in 5% increments. distance = device.size - device.minSize onePercent = distance*0.01 fivePercent = distance*0.05 twentyPercent = distance*0.2 adjustment = self.builder.get_object("resizeAdjustment") adjustment.configure(value, device.minSize, device.size, onePercent, fivePercent, 0) # And then the slider needs a couple tick marks for easier navigation. self._resizeSlider.clear_marks() for i in range(1, 5): self._resizeSlider.add_mark(device.minSize + i*twentyPercent, Gtk.PositionType.BOTTOM, None) # Finally, add tick marks for the ends. self._resizeSlider.add_mark(device.minSize, Gtk.PositionType.BOTTOM, size_str(device.minSize)) self._resizeSlider.add_mark(device.size, Gtk.PositionType.BOTTOM, size_str(device.size))
def _update_labels(self, nDisks=None, totalReclaimable=None, selectedReclaimable=None): if nDisks is not None and totalReclaimable is not None: text = P_("<b>%s disk; %s reclaimable space</b> (in filesystems)", "<b>%s disks; %s reclaimable space</b> (in filesystems)", nDisks) % (nDisks, size_str(totalReclaimable)) self._reclaimable_label.set_markup(text) if selectedReclaimable is not None: text = _("Total selected space to reclaim: <b>%s</b>") % size_str(selectedReclaimable) self._selected_label.set_markup(text)
def _update_labels(self, nDisks=None, totalReclaimable=None, selectedReclaimable=None): if nDisks is not None and totalReclaimable is not None: text = P_("<b>%(count)s disk; %(size)s reclaimable space</b> (in filesystems)", "<b>%(count)s disks; %(size)s reclaimable space</b> (in filesystems)", nDisks) % {"count" : escape_markup(str(nDisks)), "size" : escape_markup(size_str(totalReclaimable))} self._reclaimable_label.set_markup(text) if selectedReclaimable is not None: text = _("Total selected space to reclaim: <b>%s</b>") % \ escape_markup(size_str(selectedReclaimable)) self._selected_label.set_markup(text)
def refresh(self, args=None): NormalTUISpoke.refresh(self, args) # Join the initialization thread to block on it # This print is foul. Need a better message display print(_("Probing storage...")) threadMgr.wait(THREAD_STORAGE_WATCHER) # synchronize our local data store with the global ksdata # Commment out because there is no way to select a disk right # now without putting it in ksdata. Seems wrong? #self.selected_disks = self.data.ignoredisk.onlyuse[:] self.autopart = self.data.autopart.autopart message = self._update_summary() # loop through the disks and present them. for disk in self.disks: size = size_str(disk.size) c = CheckboxWidget( title="%i) %s: %s (%s)" % (self.disks.index(disk) + 1, disk.model, size, disk.name), completed=(disk.name in self.selected_disks)) self._window += [c, ""] self._window += [TextWidget(message), ""] return True
def setup(self, store, selectedNames, disks): vendors = [] interconnects = [] for disk in disks: selected = disk.name in selectedNames if hasattr(disk, "node"): port = str(disk.node.port) lun = str(disk.node.tpgt) else: port = "" lun = "" store.append([True, selected, not disk.protected, disk.name, "", disk.model, size_str(disk.size), disk.vendor, disk.bus, disk.serial, self._long_identifier(disk), "", port, getattr(disk, "initiator", ""), lun, ""]) if not disk.vendor in vendors: vendors.append(disk.vendor) if not disk.bus in interconnects: interconnects.append(disk.bus) self._combo.set_active(0) self._combo.emit("changed") self.setupCombo(self._vendorCombo, vendors) self.setupCombo(self._icCombo, interconnects)
def setup(self, store, selectedNames, disks): vendors = [] interconnects = [] for disk in disks: paths = [d.name for d in disk.parents] selected = disk.name in selectedNames store.append([ True, selected, not disk.protected, disk.name, "", disk.model, size_str(disk.size), disk.vendor, disk.bus, disk.serial, disk.wwid, "\n".join(paths), "", "", "", "", "" ]) if not disk.vendor in vendors: vendors.append(disk.vendor) if not disk.bus in interconnects: interconnects.append(disk.bus) self._combo = self.builder.get_object("multipathTypeCombo") self._combo.set_active(0) self._combo.emit("changed") self.setupCombo(self._vendorCombo, vendors) self.setupCombo(self._icCombo, interconnects)
def _format_disk_info(self, disk): """ Some specialized disks are difficult to identify in the storage spoke, so add and return extra identifying information about them. Since this is going to be ugly to do within the confines of the CheckboxWidget, pre-format the display string right here. """ # show this info for all disks format_str = "%s: %s (%s)" % (disk.model, size_str( disk.size), disk.name) disk_attrs = [] # now check for/add info about special disks if (isinstance(disk, MultipathDevice) or isinstance(disk, iScsiDiskDevice) or isinstance(disk, FcoeDiskDevice)): if hasattr(disk, "wwid"): disk_attrs.append(disk.wwid) elif isinstance(disk, DASDDevice): if hasattr(disk, "busid"): disk_attrs.append(disk.busid) elif isinstance(disk, ZFCPDiskDevice): if hasattr(disk, "fcp_lun"): disk_attrs.append(disk.fcp_lun) if hasattr(disk, "wwpn"): disk_attrs.append(disk.wwpn) if hasattr(disk, "hba_id"): disk_attrs.append(disk.hba_id) # now append all additional attributes to our string for attr in disk_attrs: format_str += ", %s" % attr return format_str
def __init__(self, data, storage, payload): GUIObject.__init__(self, data) self.storage = storage self.payload = payload self._initialFreeSpace = Size(0) self._selectedReclaimableSpace = 0 self._actionStore = self.builder.get_object("actionStore") self._diskStore = self.builder.get_object("diskStore") self._selection = self.builder.get_object("diskView-selection") self._view = self.builder.get_object("diskView") self._diskStore = self.builder.get_object("diskStore") self._reclaimable_label = self.builder.get_object( "reclaimableSpaceLabel") self._selected_label = self.builder.get_object("selectedSpaceLabel") self._required_label = self.builder.get_object("requiredSpaceLabel") markup = self._required_label.get_label() self._required_label.set_markup(markup % size_str(self.payload.spaceRequired)) self._reclaimDescLabel = self.builder.get_object("reclaimDescLabel") self._resizeButton = self.builder.get_object("resizeButton") self._preserveButton = self.builder.get_object("preserveButton") self._shrinkButton = self.builder.get_object("shrinkButton") self._deleteButton = self.builder.get_object("deleteButton") self._resizeSlider = self.builder.get_object("resizeSlider")
def refresh(self, args = None): NormalTUISpoke.refresh(self, args) # Join the initialization thread to block on it # This print is foul. Need a better message display print(_("Probing storage...")) threadMgr.wait(THREAD_STORAGE_WATCHER) # synchronize our local data store with the global ksdata # Commment out because there is no way to select a disk right # now without putting it in ksdata. Seems wrong? #self.selected_disks = self.data.ignoredisk.onlyuse[:] self.autopart = self.data.autopart.autopart message = self._update_summary() # loop through the disks and present them. for disk in self.disks: size = size_str(disk.size) c = CheckboxWidget(title="%i) %s: %s (%s)" % (self.disks.index(disk) + 1, disk.model, size, disk.name), completed=(disk.name in self.selected_disks)) self._window += [c, ""] self._window += [TextWidget(message), ""] return True
def setup(self, store, selectedNames, disks): """ Set up our Z-page, but only if we're running on s390x. """ if not self._isS390: return else: ccws = [] wwpns = [] luns = [] self._combo = self.builder.get_object("zTypeCombo") self._combo.set_active(0) self._combo.emit("changed") for disk in disks: paths = [d.name for d in disk.parents] selected = disk.name in selectedNames if getattr(disk, "type") == "zfcp": # remember to store all of the zfcp-related junk so we can # see it in the UI if not disk.fcp_lun in luns: luns.append(disk.fcp_lun) if not disk.wwpn in wwpns: wwpns.append(disk.wwpn) if not disk.hba_id in ccws: ccws.append(disk.hba_id) # now add it to our store store.append([ True, selected, not disk.protected, disk.name, "", disk.model, size_str(disk.size), disk.vendor, disk.bus, disk.serial, "", "\n".join(paths), "", "", disk.fcp_lun, disk.hba_id, disk.wwpn ])
def __init__(self, data, storage, payload): GUIObject.__init__(self, data) self.storage = storage self.payload = payload self._actionStore = self.builder.get_object("actionStore") self._diskStore = self.builder.get_object("diskStore") self._view = self.builder.get_object("diskView") self._diskStore = self.builder.get_object("diskStore") self._reclaimable_label = self.builder.get_object("reclaimableSpaceLabel") self._selected_label = self.builder.get_object("selectedSpaceLabel") self._required_label = self.builder.get_object("requiredSpaceLabel") markup = self._required_label.get_label() self._required_label.set_markup(markup % size_str(self.payload.spaceRequired)) self._reclaimDescLabel = self.builder.get_object("reclaimDescLabel") self._resizeButton = self.builder.get_object("resizeButton") self._preserveButton = self.builder.get_object("preserveButton") self._shrinkButton = self.builder.get_object("shrinkButton") self._deleteButton = self.builder.get_object("deleteButton") self._resizeSlider = self.builder.get_object("resizeSlider")
def setup(self, store, selectedNames, disks): vendors = [] interconnects = [] for disk in disks: paths = [d.name for d in disk.parents] selected = disk.name in selectedNames store.append([True, selected, not disk.protected, disk.name, "", disk.model, size_str(disk.size), disk.vendor, disk.bus, disk.serial, disk.wwid, "\n".join(paths), "", "", "", ""]) if not disk.vendor in vendors: vendors.append(disk.vendor) if not disk.bus in interconnects: interconnects.append(disk.bus) self._combo = self.builder.get_object("multipathTypeCombo") self._combo.set_active(0) self._combo.emit("changed") self.setupCombo(self._vendorCombo, vendors) self.setupCombo(self._icCombo, interconnects)
def _get_sw_needs_text(self, required_space, auto_swap): required_space_text = size_str(required_space) sw_text = (_("Your current <a href=\"\"><b>%(product)s</b> software " "selection</a> requires <b>%(total)s</b> of available " "space, including <b>%(software)s</b> for software and " "<b>%(swap)s</b> for swap space.") % {"product": productName, "total": required_space + auto_swap, "software": required_space, "swap": auto_swap}) return sw_text
def initialize(self, disks, free, showRemove=True, setBoot=True): self._previousID = None for disk in disks: self._store.append([False, "%s (%s)" % (disk.description, disk.serial), size_str(disk.size), size_str(free[disk.name][0]), disk.name, disk.id]) self.disks = disks[:] self._update_summary() if not showRemove: self.builder.get_object("remove_button").hide() if not setBoot: self._set_button.hide() if not disks: return # Don't select a boot device if no boot device is asked for. if self.data.bootloader.location == "none": return # Set up the default boot device. Use what's in the ksdata if anything, # then fall back to the first device. default_id = None if self.data.bootloader.bootDrive: for d in self.disks: if d.name == self.data.bootloader.bootDrive: default_id = d.id if not default_id: default_id = self.disks[0].id # And then select it in the UI. for row in self._store: if row[ID_COL] == default_id: self._previousID = row[ID_COL] row[IS_BOOT_COL] = True break
def _get_sw_needs_text(self, required_space, auto_swap): required_space_text = size_str(required_space) sw_text = (_("Your current <a href=\"\"><b>%(product)s</b> software " "selection</a> requires <b>%(total)s</b> of available " "space, including <b>%(software)s</b> for software and " "<b>%(swap)s</b> for swap space.") % { "product": productName, "total": required_space + auto_swap, "software": required_space, "swap": auto_swap }) return sw_text
def _add_disk_overview(self, disk, box): if disk.removable: kind = "drive-removable-media" else: kind = "drive-harddisk" size = size_str(disk.size) if disk.serial: popup_info = "%s" % disk.serial else: popup_info = None # We don't want to display the whole huge WWID for a multipath device. # That makes the DO way too wide. if isinstance(disk, MultipathDevice): desc = disk.wwid.split(":") description = ":".join(desc[0:3]) + "..." + ":".join(desc[-5:-1]) else: description = disk.description free = self.storage.getFreeSpace(disks=[disk])[disk.name][0] overview = AnacondaWidgets.DiskOverview(description, kind, size, _("%s free") % size_str(free), disk.name, popup=popup_info) box.pack_start(overview, False, False, 0) # FIXME: this will need to get smarter # # maybe a little function that resolves each item in onlyuse using # udev_resolve_devspec and compares that to the DiskDevice? overview.set_chosen(disk.name in self.selected_disks) overview.connect("button-press-event", self._on_disk_clicked) overview.connect("key-release-event", self._on_disk_clicked) overview.connect("focus-in-event", self._on_disk_focus_in) overview.show_all()
def _add_disk_overview(self, disk, box): if disk.removable: kind = "drive-removable-media" else: kind = "drive-harddisk" size = size_str(disk.size) if disk.serial: popup_info = "%s" % disk.serial else: popup_info = None # We don't want to display the whole huge WWID for a multipath device. # That makes the DO way too wide. if isinstance(disk, MultipathDevice): desc = disk.wwid.split(":") description = ":".join(desc[0:3]) + "..." + ":".join(desc[-4:]) else: description = disk.description free = self.storage.getFreeSpace(disks=[disk])[disk.name][0] overview = AnacondaWidgets.DiskOverview(description, kind, size, _("%s free") % size_str(free), disk.name, popup=popup_info) box.pack_start(overview, False, False, 0) # FIXME: this will need to get smarter # # maybe a little function that resolves each item in onlyuse using # udev_resolve_devspec and compares that to the DiskDevice? overview.set_chosen(disk.name in self.selected_disks) overview.connect("button-press-event", self._on_disk_clicked) overview.connect("key-release-event", self._on_disk_clicked) overview.connect("focus-in-event", self._on_disk_focus_in) overview.show_all()
def _set_free_space_labels(self, disk_free, fs_free): disk_free_text = size_str(disk_free) self.disk_free_label.set_text(disk_free_text) fs_free_text = size_str(fs_free) self.fs_free_label.set_text(fs_free_text)
def resize_slider_format(self, scale, value): # This makes the value displayed under the slider prettier than just a # single number. return size_str(value)
def populate(self, disks): totalDisks = 0 totalReclaimableSpace = 0 self._initialFreeSpace = Size(0) self._selectedReclaimableSpace = 0 canShrinkSomething = False free_space = self.storage.getFreeSpace(disks=disks) for disk in disks: # First add the disk itself. editable = not disk.protected if disk.partitioned: fstype = "" diskReclaimableSpace = 0 else: fstype = disk.format.type diskReclaimableSpace = disk.size itr = self._diskStore.append(None, [ disk.id, "%s %s" % (size_str(disk.size), disk.description), fstype, "<span foreground='grey' style='italic'>%s total</span>", _(PRESERVE), editable, self._get_tooltip(disk), disk.size, disk.name ]) if disk.partitioned: # Then add all its partitions. for dev in self.storage.devicetree.getChildren(disk): if dev.isExtended and disk.format.logicalPartitions: continue # Devices that are not resizable are still deletable. if dev.resizable: freeSize = dev.size - dev.minSize resizeString = _("%(freeSize)s of %(devSize)s") \ % {"freeSize": size_str(freeSize), "devSize": size_str(dev.size)} if not dev.protected: canShrinkSomething = True else: freeSize = dev.size resizeString = "<span foreground='grey'>%s</span>" % _( "Not resizeable") self._diskStore.append(itr, [ dev.id, self._description(dev), dev.format.type, resizeString, _(PRESERVE), not dev.protected, self._get_tooltip(dev), dev.size, dev.name ]) diskReclaimableSpace += freeSize # And then add another uneditable line that lists how much space is # already free in the disk. diskFree = free_space[disk.name][0] converted = diskFree.convertTo(spec="mb") if int(converted): self._diskStore.append(itr, [ disk.id, _("""<span foreground='grey' style='italic'>Free space</span>""" ), "", "<span foreground='grey' style='italic'>%s</span>" % size_str(diskFree), _(PRESERVE), False, self._get_tooltip(disk), float(converted), "" ]) self._initialFreeSpace += diskFree # And then go back and fill in the total reclaimable space for the # disk, now that we know what each partition has reclaimable. self._diskStore[itr][RECLAIMABLE_COL] = self._diskStore[itr][ RECLAIMABLE_COL] % size_str(diskReclaimableSpace) totalDisks += 1 totalReclaimableSpace += diskReclaimableSpace self._update_labels(totalDisks, totalReclaimableSpace, 0) description = _( "You can remove existing filesystems you no longer need to free up space " "for this installation. Removing a filesystem will permanently delete all " "of the data it contains.") if canShrinkSomething: description += "\n\n" description += _( "There is also free space available in pre-existing filesystems. " "While it's risky and we recommend you back up your data first, you " "can recover that free disk space and make it available for this " "installation below.") self._reclaimDescLabel.set_text(description)
def populate(self, disks): totalDisks = 0 totalReclaimableSpace = 0 self._initialFreeSpace = Size(0) self._selectedReclaimableSpace = 0 canShrinkSomething = False free_space = self.storage.getFreeSpace(disks=disks) for disk in disks: # First add the disk itself. editable = not disk.protected if disk.partitioned: fstype = "" diskReclaimableSpace = 0 else: fstype = disk.format.type diskReclaimableSpace = disk.size itr = self._diskStore.append(None, [disk.id, "%s %s" % (size_str(disk.size), disk.description), fstype, "<span foreground='grey' style='italic'>%s total</span>", _(PRESERVE), editable, self._get_tooltip(disk), disk.size, disk.name]) if disk.partitioned: # Then add all its partitions. for dev in self.storage.devicetree.getChildren(disk): if dev.isExtended and disk.format.logicalPartitions: continue # Devices that are not resizable are still deletable. if dev.resizable: freeSize = dev.size - dev.minSize resizeString = _("%(freeSize)s of %(devSize)s") \ % {"freeSize": size_str(freeSize), "devSize": size_str(dev.size)} if not dev.protected: canShrinkSomething = True else: freeSize = dev.size resizeString = "<span foreground='grey'>%s</span>" % _("Not resizeable") self._diskStore.append(itr, [dev.id, self._description(dev), dev.format.type, resizeString, _(PRESERVE), not dev.protected, self._get_tooltip(dev), dev.size, dev.name]) diskReclaimableSpace += freeSize # And then add another uneditable line that lists how much space is # already free in the disk. diskFree = free_space[disk.name][0] converted = diskFree.convertTo(spec="mb") if int(converted): self._diskStore.append(itr, [disk.id, _("""<span foreground='grey' style='italic'>Free space</span>"""), "", "<span foreground='grey' style='italic'>%s</span>" % size_str(diskFree), _(PRESERVE), False, self._get_tooltip(disk), float(converted), ""]) self._initialFreeSpace += diskFree # And then go back and fill in the total reclaimable space for the # disk, now that we know what each partition has reclaimable. self._diskStore[itr][RECLAIMABLE_COL] = self._diskStore[itr][RECLAIMABLE_COL] % size_str(diskReclaimableSpace) totalDisks += 1 totalReclaimableSpace += diskReclaimableSpace self._update_labels(totalDisks, totalReclaimableSpace, 0) description = _("You can remove existing filesystems you no longer need to free up space " "for this installation. Removing a filesystem will permanently delete all " "of the data it contains.") if canShrinkSomething: description += "\n\n" description += _("There is also free space available in pre-existing filesystems. " "While it's risky and we recommend you back up your data first, you " "can recover that free disk space and make it available for this " "installation below.") self._reclaimDescLabel.set_text(description)