Initial implementation of the disk selection part of the storage spoke. some limitations (not an exhaustive list): - uses fake disk data due to non-trivial problems with non-root usage - can't switch other spokes yet (eg: software) - don't know how to get required space for current package set - no real handling of "custom" checkbutton's setting - no advanced/specialized devices --- pyanaconda/ui/gui/categories/storage.py | 30 + pyanaconda/ui/gui/spokes/storage.py | 522 +++++++++++++++++ pyanaconda/ui/gui/spokes/storage.ui | 964 +++++++++++++++++++++++++++++++ 3 files changed, 1516 insertions(+), 0 deletions(-) create mode 100644 pyanaconda/ui/gui/categories/storage.py create mode 100644 pyanaconda/ui/gui/spokes/storage.py create mode 100644 pyanaconda/ui/gui/spokes/storage.ui diff --git a/pyanaconda/ui/gui/categories/storage.py b/pyanaconda/ui/gui/categories/storage.py new file mode 100644 index 0000000..bc94447 --- /dev/null +++ b/pyanaconda/ui/gui/categories/storage.py @@ -0,0 +1,30 @@ +# Storage category classes +# +# Copyright (C) 2011 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# +# Red Hat Author(s): Chris Lumens <clumens@xxxxxxxxxx> +# David Lehman <dlehman@xxxxxxxxxx> +# + +from pyanaconda.ui.gui.categories import SpokeCategory +from pyanaconda.ui.gui.hubs.summary import SummaryHub + +__all__ = ["StorageCategory"] + +class StorageCategory(SpokeCategory): + displayOnHub = SummaryHub + title = "STORAGE" diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py new file mode 100644 index 0000000..ad3d0b8 --- /dev/null +++ b/pyanaconda/ui/gui/spokes/storage.py @@ -0,0 +1,522 @@ +# Storage configuration spoke classes +# +# Copyright (C) 2011 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# +# Red Hat Author(s): David Lehman <dlehman@xxxxxxxxxx> +# + +""" + TODO: + + - add button within sw_needs text in options dialogs 2,3 + - udev data gathering + - udev fwraid, mpath would sure be nice + - status/completed + - what are noteworthy status events? + - disks selected + - exclusiveDisks non-empty + - sufficient space for software selection + - autopart selected + - custom selected + - performing custom configuration + - storage configuration complete + - spacing and border width always 6 + +""" + +from gi.repository import Gtk +from gi.repository import AnacondaWidgets + +from pyanaconda.ui.gui import UIObject +from pyanaconda.ui.gui.spokes import NormalSpoke +from pyanaconda.ui.gui.categories.storage import StorageCategory + +from pyanaconda.storage.size import Size + +# these are all temporary +from pyanaconda.storage.partitioning import getFreeRegions +from pyanaconda.storage.partitioning import sectorsToSize +from pyanaconda.storage.devices import DiskDevice +from pyanaconda.storage.formats import getFormat + +from pyanaconda.product import productName + +import gettext + +_ = lambda x: gettext.ldgettext("anaconda", x) +P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z) + +__all__ = ["StorageSpoke"] + +class FakeDisk(object): + def __init__(self, name, size=0, free=0, partitioned=True, vendor=None, + model=None, removable=False): + self.name = name + self.size = size + self.free = free + self.partitioned = partitioned + self.vendor = vendor + self.model = model + self.removable = removable + +def getDisks(devicetree, fake=False): + if not fake: + disks = [d for d in devicetree.devices if d.isDisk and + not d.format.hidden and + d.partitioned] + else: + disks = [] + disks.append(FakeDisk("sda", size=300000, free=10000, + vendor="Seagate", model="Monster")) + disks.append(FakeDisk("sdb", size=300000, free=300000, + vendor="Seagate", model="Monster")) + disks.append(FakeDisk("sdc", size=8000, free=2100, removable=True, + vendor="SanDisk", model="Cruzer")) + + return disks + +# XXX move these into storage +def fsFreeSpace(device): + free = 0 + if device.format.exists: + current_size = getattr(device.format, "currentSize", None) + min_size = getattr(device.format, "minSize", None) + if current_size and min_size and current_size != min_size: + free = int(current_size - min_size) # truncate + + return free + +def diskFreeSpace(disk): + free = 0 + if disk.partitioned: + parted_disk = disk.format.partedDisk + sector_size = disk.partedDevice.sectorSize + + free_geoms = getFreeRegions([parted_disk]) + free_sizes = [sectorsToSize(f.length, sector_size) for f in free_geoms] + free = sum(free_sizes) + + return free + +def get_free_space_info(disks, devicetree): + disk_free = 0 + fs_free = 0 + for disk in disks: + if hasattr(disk, "free"): + disk_free += disk.free + continue + + disk_free += diskFreeSpace(disk) + for partition in devicetree.getChildren(disk): + fs_free += fsFreeSpace(partition) + + print("disks %s have %d free, plus %s in filesystems" + % ([d.name for d in disks], disk_free, fs_free)) + return (disk_free, fs_free) + + +class SelectedDisksDialog(UIObject): + builderObjects = ["selected_disks_dialog", "summary_label", + "disk_view", "disk_store", "disk_selection"] + mainWidgetName = "selected_disks_dialog" + uiFile = "spokes/storage.ui" + + def populate(self, disks): + for disk in disks: + if disk.name not in self.data.ignoredisk.onlyuse: + continue + + self._store.append(["%s-%s" % (disk.vendor, disk.model), + Size(spec="%s mb" % disk.size).humanReadable().upper(), + Size(spec="%s mb" % disk.free).humanReadable().upper(), + str(disks.index(disk))]) + self.disks = disks[:] + self._update_summary() + + def setup(self, disks): + print "SETUP selected disks dialog" + super(SelectedDisksDialog, self).setup() + + self._view = self.builder.get_object("disk_view") + self._store = self.builder.get_object("disk_store") + self._selection = self.builder.get_object("disk_selection") + self._summary_label = self.builder.get_object("summary_label") + + # clear out the store and repopulate it from the devicetree + self._store.clear() + self.populate(disks) + + def run(self): + rc = self.window.run() + self.window.destroy() + return rc + + def _get_selection_refs(self): + selected_refs = [] + if self._selection.count_selected_rows(): + model, selected_paths = self._selection.get_selected_rows() + selected_refs = [Gtk.TreeRowReference() for p in selected_paths] + + return selected_refs + + def _update_summary(self): + count = 0 + size = 0 + free = 0 + itr = self._store.get_iter_first() + while itr: + count += 1 + size += Size(spec=self._store.get_value(itr, 1)) + free += Size(spec=self._store.get_value(itr, 2)) + itr = self._store.iter_next(itr) + + size = Size(bytes=long(size)).humanReadable().upper() + free = Size(bytes=long(free)).humanReadable().upper() + + text = P_(("%d disk; %s capacity; %s free space " + "(unpartitioned and in filesystems)"), + ("%d disks; %s capacity; %s free space " + "(unpartitioned and in filesystems)"), + count) % (count, size, free) + self._summary_label.set_text(text) + + # signal handlers + def on_remove_clicked(self, button): + print "REMOVE CLICKED"#: %s" % self._selection.get_selected().get_value(3) + # remove the selected disk(s) from the list and update the summary label + #selected_refs = self._get_selection_refs() + #for ref in selected_refs: + # path = ref.get_path() + # itr = model.get_iter_from_string(path) + # self._store.remove(itr) + model, itr = self._selection.get_selected() + if itr: + idx = int(model.get_value(itr, 3)) + name = self.disks[idx].name + print "removing %s" % name + self._store.remove(itr) + self.data.ignoredisk.onlyuse.remove(name) + self._update_summary() + + def on_close_clicked(self, button): + print "CLOSE CLICKED" + + def on_selection_changed(self, *args): + print "SELECTION CHANGED" + model, itr = self._selection.get_selected() + if itr: + print "new selection: %s" % model.get_value(itr, 3) + + +class InstallOptions1Dialog(UIObject): + builderObjects = ["options1_dialog", + "options1_label", "options1_custom_check"] + mainWidgetName = "options1_dialog" + uiFile = "spokes/storage.ui" + + RESPONSE_CANCEL = 0 + RESPONSE_CONTINUE = 1 + RESPONSE_MODIFY_SW = 2 + RESPONSE_RECLAIM = 3 + RESPONSE_QUIT = 4 + + def run(self): + rc = self.window.run() + self.window.destroy() + return rc + + def setup(self, required_space, disk_free, fs_free): + custom = not self.data.autopart.autopart + custom_checkbutton = self.builder.get_object("options1_custom_check") + custom_checkbutton.set_active(custom) + + options_label = self.builder.get_object("options1_label") + + options_text = (_("You have plenty of space to install <b>%s</b>, so " + "we can automatically configure the rest of the " + "installation for you.\n\nYou're all set!") + % productName) + options_label.set_markup(options_text) + + def _set_free_space_labels(self, disk_free, fs_free): + disk_free_text = Size(spec="%dmb" % disk_free).humanReadable().upper() + self.disk_free_label.set_text(disk_free_text) + + fs_free_text = Size(spec="%dmb" % fs_free).humanReadable().upper() + self.fs_free_label.set_text(fs_free_text) + + def _get_sw_needs_text(self, required_space): + required_space_text = Size(spec="%dmb" % required_space).humanReadable().upper() + sw_text = (_("Your current %s software selection requires " + "<b>%s</b> of available space.") + % (productName, required_space_text)) + return sw_text + + # signal handlers + def on_cancel_clicked(self, button): + # return to the spoke without making any changes + print "CANCEL CLICKED" + + def on_quit_clicked(self, button): + print "QUIT CLICKED" + + def on_modify_sw_clicked(self, button): + # switch to the software selection hub + print "MODIFY SOFTWARE CLICKED" + + def on_reclaim_clicked(self, button): + # show reclaim screen/dialog + print "RECLAIM CLICKED" + + def on_continue_clicked(self, button): + # TODO: handle custom checkbutton + print "CONTINUE CLICKED" + +class InstallOptions2Dialog(InstallOptions1Dialog): + builderObjects = ["options2_dialog", + "options2_label1", "options2_label2", + "options2_disk_free_label", "options2_fs_free_label", + "options2_custom_check"] + mainWidgetName = "options2_dialog" + + def setup(self, required_space, disk_free, fs_free): + custom = not self.data.autopart.autopart + custom_checkbutton = self.builder.get_object("options2_custom_check") + custom_checkbutton.set_active(custom) + + sw_text = self._get_sw_needs_text(required_space) + label_text = _("%s\nThe disks you've selected have the following " + "amounts of free space:") % sw_text + self.builder.get_object("options2_label1").set_markup(label_text) + + self.disk_free_label = self.builder.get_object("options2_disk_free_label") + self.fs_free_label = self.builder.get_object("options2_fs_free_label") + self._set_free_space_labels(disk_free, fs_free) + + label_text = (_("You don't have enough space available to install " + "<b>%s</b>, but we can help you reclaim space by " + "shrinking or removing existing partitions.") + % productName) + self.builder.get_object("options2_label2").set_markup(label_text) + +class InstallOptions3Dialog(InstallOptions1Dialog): + builderObjects = ["options3_dialog", + "options3_label1", "options3_label2", + "options3_disk_free_label", "options3_fs_free_label"] + mainWidgetName = "options3_dialog" + + def setup(self, required_space, disk_free, fs_free): + sw_text = self._get_sw_needs_text(required_space) + label_text = _("%s\nYou don't have enough space available to install " + "%s, even if you used all of the free space available " + "on the selected disks.") % (sw_text, productName) + self.builder.get_object("options3_label1").set_markup(label_text) + + self.disk_free_label = self.builder.get_object("options3_disk_free_label") + self.fs_free_label = self.builder.get_object("options3_fs_free_label") + self._set_free_space_labels(disk_free, fs_free) + + label_text = _("You don't have enough space available to install " + "<b>%s</b>, even if you used all of the free space " + "available on the selected disks. You could add more " + "disks for additional space, modify your software " + "selection to install a smaller version of <b>%s</b>, " + "or quit the installer.") % (productName, productName) + self.builder.get_object("options3_label2").set_markup(label_text) + +class StorageSpoke(NormalSpoke): + builderObjects = ["storageWindow", "local_disks_box", "summary_button"] + mainWidgetName = "storageWindow" + uiFile = "spokes/storage.ui" + + category = StorageCategory + + # other candidates: computer-symbolic, folder-symbolic + icon = "drive-harddisk-symbolic" + title = "STORAGE CONFIGURATION" + + def apply(self): + pass + + @property + def completed(self): + return False + + @property + def status(self): + """ A short string describing the current status of storage setup. """ + msg = "no disks selected" + if self.data.ignoredisk.onlyuse: + msg = "%d disks selected" % len(self.data.ignoredisk.onlyuse) + + if self.data.autopart.autopart: + msg = "automatic partitioning selected" + + # if we had a storage instance we could check for a defined root + + return msg + + def _on_disk_clicked(self, overview, *args): + print "DISK CLICKED: %s" % overview.get_property("popup-info") + self._update_disk_list() + self._update_summary() + + def populate(self): + NormalSpoke.populate(self) + + local_disks_box = self.builder.get_object("local_disks_box") + #specialized_disks_box = self.builder.get_object("specialized_disks_box") + + print self.data.ignoredisk.onlyuse + self.disks = getDisks(self.devicetree, fake=True) + + # properties: kind, description, capacity, os, popup-info + for disk in self.disks: + if disk.removable: + kind = "drive-removable" + else: + kind = "drive-harddisk" + + description = "%s %s" % (disk.vendor, disk.model) + size = Size(spec="%dmb" % disk.size).humanReadable().upper() + overview = AnacondaWidgets.DiskOverview(description, + kind, + size, + popup=disk.name) + local_disks_box.add(overview) + + # 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_selected(disk.name in self.data.ignoredisk.onlyuse) + overview.connect("button-press-event", self._on_disk_clicked) + + self._update_summary() + + def setup(self): + # XXX this is called every time we switch to this spoke + NormalSpoke.setup(self) + + def _update_summary(self): + """ Update the summary based on the UI. """ + print "UPDATING SUMMARY" + count = 0 + capacity = 0 + free = 0 + + overviews = self.builder.get_object("local_disks_box").get_children() + for overview in overviews: + name = overview.get_property("popup-info") + selected = overview.get_selected() + if selected: + disk = None + for _disk in self.disks: + if _disk.name == name: + disk = _disk + break + + capacity += disk.size + free += disk.free + count += 1 + + summary = (P_(("%d disk selected; %s capacity; %s free ..."), + ("%d disks selected; %s capacity; %s free ..."), + count) + % (count, + Size(spec="%dmb" % capacity).humanReadable().upper(), + Size(spec="%dmb" % free).humanReadable().upper())) + self.builder.get_object("summary_button").set_label(summary) + + def _update_disk_list(self): + """ Update ignoredisk.onlyuse based on the UI. """ + print "UPDATING DISK LIST" + overviews = self.builder.get_object("local_disks_box").get_children() + for overview in overviews: + name = overview.get_property("popup-info") + selected = overview.get_selected() + if selected and name not in self.data.ignoredisk.onlyuse: + self.data.ignoredisk.onlyuse.append(name) + + if not selected and name in self.data.ignoredisk.onlyuse: + self.data.ignoredisk.onlyuse.remove(name) + + # signal handlers + def on_summary_clicked(self, button): + # show the selected disks dialog + dialog = SelectedDisksDialog(self.data) + dialog.setup(self.disks) + rc = self.run_lightbox_dialog(dialog) + + # update the UI to reflect changes to self.data.ignoredisk.onlyuse + overviews = self.builder.get_object("local_disks_box").get_children() + print "onlyuse is %s" % self.data.ignoredisk.onlyuse + for overview in overviews: + name = overview.get_property("popup-info") + print "looking at DO for %s" % name + overview.set_selected(name in self.data.ignoredisk.onlyuse) + self._update_summary() + + def run_lightbox_dialog(self, dialog): + lightbox = AnacondaWidgets.lb_show_over(self.window) + dialog.window.set_transient_for(lightbox) + rc = dialog.run() + lightbox.destroy() + return rc + + def on_continue_clicked(self, button): + # show the installation options dialog + disks = [d for d in self.disks if d.name in self.data.ignoredisk.onlyuse] + (disk_free, fs_free) = get_free_space_info(disks, self.devicetree) + required_space = 10000 # TODO: find out where to get this + if disk_free >= required_space: + dialog = InstallOptions1Dialog(self.data) + elif disk_free + fs_free >= required_space: + dialog = InstallOptions2Dialog(self.data) + else: + dialog = InstallOptions3Dialog(self.data) + + dialog.setup(required_space, disk_free, fs_free) + rc = self.run_lightbox_dialog(dialog) + if rc == dialog.RESPONSE_CONTINUE: + # depending on custom/autopart, either set up autopart or show + # custom partitioning ui + print "user chose to continue to partitioning" + Gtk.main_quit() + elif rc == dialog.RESPONSE_CANCEL: + # stay on this spoke + print "user chose to continue disk selection" + pass + elif rc == dialog.RESPONSE_MODIFY_SW: + # go to software spoke + print "user chose to modify software selection" + Gtk.main_quit() + pass + elif rc == dialog.RESPONSE_RECLAIM: + # go to tug-of-war + print "user chose to reclaim space" + Gtk.main_quit() + pass + elif rc == dialog.RESPONSE_QUIT: + raise SystemExit("user-selected exit") + + def on_add_disk_clicked(self, button): + print "ADD DISK CLICKED" + + def on_back_clicked(self, window): + self.window.hide() + Gtk.main_quit() diff --git a/pyanaconda/ui/gui/spokes/storage.ui b/pyanaconda/ui/gui/spokes/storage.ui new file mode 100644 index 0000000..b4b6eca --- /dev/null +++ b/pyanaconda/ui/gui/spokes/storage.ui @@ -0,0 +1,964 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 3.0 --> + <!-- interface-requires AnacondaWidgets 1.0 --> + <object class="GtkListStore" id="disk_store"> + <columns> + <!-- column-name Description --> + <column type="gchararray"/> + <!-- column-name capacity --> + <column type="gchararray"/> + <!-- column-name free --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkDialog" id="options1_dialog"> + <property name="width_request">500</property> + <property name="height_request">200</property> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="type">popup</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="destroy_with_parent">True</property> + <property name="type_hint">dialog</property> + <property name="mnemonics_visible">False</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox2"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area2"> + <property name="can_focus">False</property> + <child> + <object class="GtkButton" id="options1_cancel_button"> + <property name="label" translatable="yes">Cancel & _add more disks</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_cancel_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="options_continue_button1"> + <property name="label" translatable="yes">_Continue</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_continue_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="options1_title_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">INSTALLATION OPTIONS</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options1_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Here we'll describe what your options are.</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="options1_custom_check"> + <property name="label" translatable="yes">Let me review & customize the partitioning of the disks anyway.</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_action_appearance">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="0">options1_cancel_button</action-widget> + <action-widget response="1">options_continue_button1</action-widget> + </action-widgets> + </object> + <object class="GtkDialog" id="options2_dialog"> + <property name="width_request">600</property> + <property name="height_request">400</property> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="type">popup</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="destroy_with_parent">True</property> + <property name="type_hint">dialog</property> + <property name="mnemonics_visible">False</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox5"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area5"> + <property name="can_focus">False</property> + <child> + <object class="GtkButton" id="options2_cancel_button"> + <property name="label" translatable="yes">Cancel & _add more disks</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_cancel_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="options2_modify_sw_button"> + <property name="label" translatable="yes">_Modify software selection</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_modify_sw_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="options2_reclaim_button"> + <property name="label" translatable="yes">_Reclaim space</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_reclaim_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box5"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="options2_title_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">INSTALLATION OPTIONS</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="options2_custom_check"> + <property name="label" translatable="yes">I don't need help; let me review & customize disk partitioning to reclaim space.</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_action_appearance">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options2_label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Here we'll describe how much space is needed for the current software selection.</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + <property name="row_homogeneous">True</property> + <child> + <object class="GtkLabel" id="options2_disk_free_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">disk free</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options2_disk_free_desc_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Free space available for use.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options2_fs_free_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">fs free</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options2_fs_free_desc_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Free space unavailable but reclaimable from existing partitions.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options2_label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Here we'll describe what your options are.</property> + <property name="use_markup">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="0">options2_cancel_button</action-widget> + <action-widget response="2">options2_modify_sw_button</action-widget> + <action-widget response="3">options2_reclaim_button</action-widget> + </action-widgets> + </object> + <object class="GtkDialog" id="options3_dialog"> + <property name="width_request">400</property> + <property name="height_request">300</property> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="type">popup</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="destroy_with_parent">True</property> + <property name="type_hint">dialog</property> + <property name="mnemonics_visible">False</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox7"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area7"> + <property name="can_focus">False</property> + <child> + <object class="GtkButton" id="options3_quit_button"> + <property name="label" translatable="yes">_Quit Installer</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_quit_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="options3_modify_sw_button"> + <property name="label" translatable="yes">_Modify software selection</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_modify_sw_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="options3_cancel_button"> + <property name="label" translatable="yes">_Cancel</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="border_width">6</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_cancel_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box6"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="options3_title_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">INSTALLATION OPTIONS</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options3_label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Here we'll describe how much space is needed for the current software selection.</property> + <property name="use_markup">True</property> + <property name="max_width_chars">100</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">6</property> + <property name="row_homogeneous">True</property> + <child> + <object class="GtkLabel" id="options3_disk_free_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">disk free</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options3_disk_free_desc_label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Free space available for use.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options3_fs_free_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">1</property> + <property name="label" translatable="yes">fs free</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options3_fs_free_desc_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Free space unavailable but reclaimable from existing partitions.</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + <property name="width">1</property> + <property name="height">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="options3_label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Here we'll describe what your options are.</property> + <property name="use_markup">True</property> + <property name="max_width_chars">100</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="4">options3_quit_button</action-widget> + <action-widget response="2">options3_modify_sw_button</action-widget> + <action-widget response="0">options3_cancel_button</action-widget> + </action-widgets> + </object> + <object class="GtkDialog" id="selected_disks_dialog"> + <property name="width_request">500</property> + <property name="height_request">400</property> + <property name="can_focus">False</property> + <property name="border_width">5</property> + <property name="type">popup</property> + <property name="title" translatable="yes">SELECTED DISKS</property> + <property name="modal">True</property> + <property name="window_position">center-on-parent</property> + <property name="destroy_with_parent">True</property> + <property name="type_hint">dialog</property> + <property name="mnemonics_visible">False</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="close_button"> + <property name="label">_Close</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_close_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">SELECTED DISKS</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkTreeView" id="disk_tree_view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">disk_store</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="disk_selection"> + <signal name="changed" handler="on_selection_changed" swapped="no"/> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="description_column"> + <property name="spacing">6</property> + <property name="title" translatable="yes">Description</property> + <property name="clickable">True</property> + <child> + <object class="GtkCellRendererText" id="description_renderer"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="capacity_column"> + <property name="spacing">6</property> + <property name="title" translatable="yes">Capacity</property> + <property name="clickable">True</property> + <child> + <object class="GtkCellRendererText" id="capacity_renderer"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="free_column"> + <property name="spacing">6</property> + <property name="title" translatable="yes">Free</property> + <child> + <object class="GtkCellRendererText" id="free_renderer"/> + <attributes> + <attribute name="text">2</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="id_column"> + <property name="spacing">6</property> + <property name="title" translatable="yes">Id</property> + <child> + <object class="GtkCellRendererText" id="id_renderer"/> + <attributes> + <attribute name="text">3</attribute> + </attributes> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButtonBox" id="buttonbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <property name="layout_style">start</property> + <child> + <object class="GtkButton" id="remove_button"> + <property name="label">_Remove</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_remove_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="summary_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Disk summary goes here</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="0">close_button</action-widget> + </action-widgets> + </object> + <object class="GtkListStore" id="specialized_disk_store"> + <columns> + <!-- column-name disk --> + <column type="GObject"/> + </columns> + </object> + <object class="AnacondaSpokeWindow" id="storageWindow"> + <property name="startup_id">filler</property> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="startup_id">filler</property> + <property name="mnemonics_visible">False</property> + <child internal-child="action_area"> + <object class="GtkBox" id="storageWindow-action_area1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">LOCAL STANDARD DISKS</property> + <property name="track_visited_links">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="vscrollbar_policy">never</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkViewport" id="viewport1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkBox" id="local_disks_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <property name="homogeneous">True</property> + <child> + <placeholder/> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <object class="GtkButton" id="summary_button"> + <property name="label" translatable="yes">summary</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + <property name="relief">none</property> + <property name="use_underline">True</property> + <property name="focus_on_click">False</property> + <property name="xalign">0</property> + <signal name="clicked" handler="on_summary_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="continue_button"> + <property name="label" translatable="yes">_Continue</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_action_appearance">False</property> + <property name="use_underline">True</property> + <property name="xalign">1</property> + <signal name="clicked" handler="on_continue_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> -- 1.7.8 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list