Linux Archive

Linux Archive (http://www.linux-archive.org/)
-   Fedora Packaging (http://www.linux-archive.org/fedora-packaging/)
-   -   Add storage category, spoke, and builder file. (http://www.linux-archive.org/fedora-packaging/612987-add-storage-category-spoke-builder-file.html)

David Lehman 12-22-2011 07:13 PM

Add storage category, spoke, and builder file.
 
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@redhat.com>
+# David Lehman <dlehman@redhat.com>
+#
+
+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@redhat.com>
+#
+
+"""
+ 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.

You'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
The disks you've selected have the following "
+ "amounts of free space:") % sw_text
+ self.builder.get_object("options2_label1").set_mar kup(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_mar kup(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
You 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_mar kup(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_mar kup(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_chi ldren()
+ 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_labe l(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_chi ldren()
+ 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_chi ldren()
+ 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 &amp; _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 &amp; 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 &amp; _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 &amp; 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="

Chris Lumens 12-22-2011 08:07 PM

Add storage category, spoke, and builder file.
 
> - can't switch other spokes yet (eg: software)

I need to do something about this. It's likely not going to be easy.
This might end up getting slipped to F18, too.

As a general comment, all the print()ing is fine now while we're
developing and testing, but we'll need to remove it all afterwards.
I've been printing stuff out when you click a button that doesn't do
anything yet just so we know the button signal is hooked up, as an
example. I plan to remove them later.

> diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py
> +class SelectedDisksDialog(UIObject):
> + builderObjects = ["selected_disks_dialog", "summary_label",
> + "disk_view", "disk_store", "disk_selection"]
> + mainWidgetName = "selected_disks_dialog"
> + uiFile = "spokes/storage.ui"

I wish I could remember why I added a builderObjects property in the
first place, but I'm positive it was to fix a bug.

Anyway, you only need to add things to that list that appear at the top
level of the .ui file's XML. This is stuff like dialogs, windows,
stores, and sometimes images (like if you need to create a new one for a
button). Everything under those top-level widgets will automatically
get dragged in.

Thus, you do not need to list everything you will later get_object() on.
I need to add a comment about this.

> +class StorageSpoke(NormalSpoke):
> + @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

All other status strings are capitalized at the beginning, I do believe.
We should continue that.

> diff --git a/pyanaconda/ui/gui/spokes/storage.ui b/pyanaconda/ui/gui/spokes/storage.ui

You can't possibly look through a .ui file and make useful contextual
comments, so I pulled it into glade. Here are my comments:

* First, make sure you've pulled the latest stuff on the newui branch
and have installed the latest libAnacondaWidgets.so file. Once you do
that, reopen your storage.ui file and you'll see that storageWindow
now has some more internal children - most notably main_box and
alignment.

* You'll want to move box2 on storageWindow up out of box1 and make it a
child of main_box, outside the alignment. That way the buttons don't
get aligned inside as well. Because the storage stuff is especially
real estate greedy, we may need to tweak alignment variables here.

* You can then get rid of box1 and just make everything in it a child of
main_box.

* I think the Continue button size on options1_dialog is an error in the
mockup. Just about everywhere else, we use Horizontal Alignment:
Center instead of Fill. That should be the case both on this button
and elsewhere.

* The couple checkboxes you use should have use underline.

* The Quit Installer button uses a capital I, but every other button has
only the first word capitalized.

* The "SELECTED DISKS" label ought to be bolded.

That's all I see for now.

- Chris

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@redhat.com
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

David Lehman 01-06-2012 07:15 PM

Add storage category, spoke, and builder file.
 
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 advanced/specialized devices
---
pyanaconda/ui/gui/categories/storage.py | 30 +
pyanaconda/ui/gui/spokes/storage.py | 534 +++++++++++++++++
pyanaconda/ui/gui/spokes/storage.ui | 995 +++++++++++++++++++++++++++++++
3 files changed, 1559 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@redhat.com>
+# David Lehman <dlehman@redhat.com>
+#
+
+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..c961a31
--- /dev/null
+++ b/pyanaconda/ui/gui/spokes/storage.py
@@ -0,0 +1,534 @@
+# 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@redhat.com>
+#
+
+"""
+ 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, serial=None, removable=False):
+ self.name = name
+ self.size = size
+ self.free = free
+ self.partitioned = partitioned
+ self.vendor = vendor
+ self.model = model
+ self.serial = serial
+ self.removable = removable
+
+ @property
+ def description(self):
+ return "%s %s" % (self.vendor, self.model)
+
+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, serial="00001",
+ vendor="Seagate", model="Monster"))
+ disks.append(FakeDisk("sdb", size=300000, free=300000, serial="00002",
+ vendor="Seagate", model="Monster"))
+ disks.append(FakeDisk("sdc", size=8000, free=2100, removable=True,
+ vendor="SanDisk", model="Cruzer", serial="00003"))
+
+ 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", "disk_store"]
+ 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"]
+ 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
+ self.custom_checkbutton = self.builder.get_object("options1_custom_check")
+ self.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.

You'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 <b>%s</b> software selection requires "
+ "<b>%s</b> of available space.")
+ % (productName, required_space_text))
+ return sw_text
+
+ @property
+ def customize_state(self):
+ if hasattr(self, "custom_checkbutton"):
+ return self.custom_checkbutton.get_active()
+
+ return False
+
+ # 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"]
+ mainWidgetName = "options2_dialog"
+
+ def setup(self, required_space, disk_free, fs_free):
+ custom = not self.data.autopart.autopart
+ self.custom_checkbutton = self.builder.get_object("options2_custom_check")
+ self.custom_checkbutton.set_active(custom)
+
+ sw_text = self._get_sw_needs_text(required_space)
+ label_text = _("%s
The disks you've selected have the following "
+ "amounts of free space:") % sw_text
+ self.builder.get_object("options2_label1").set_mar kup(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 = (_("<b>You don't have enough space available to install "
+ "%s</b>, but we can help you reclaim space by "
+ "shrinking or removing existing partitions.")
+ % productName)
+ self.builder.get_object("options2_label2").set_mar kup(label_text)
+
+ def on_custom_toggled(self, checkbutton):
+ custom = checkbutton.get_active()
+ self.builder.get_object("options2_cancel_button"). set_sensitive(not custom)
+ self.builder.get_object("options2_modify_sw_button ").set_sensitive(not custom)
+
+class InstallOptions3Dialog(InstallOptions1Dialog):
+ builderObjects = ["options3_dialog"]
+ mainWidgetName = "options3_dialog"
+
+ def setup(self, required_space, disk_free, fs_free):
+ sw_text = self._get_sw_needs_text(required_space)
+ label_text = (_("%s
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.")
+ % (sw_text, productName))
+ self.builder.get_object("options3_label1").set_mar kup(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 = _("<b>You don't have enough space available to install "
+ "%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_mar kup(label_text)
+
+class StorageSpoke(NormalSpoke):
+ builderObjects = ["storageWindow"]
+ 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").partition("|")[0].strip()
+
+ 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"
+
+ size = Size(spec="%dmb" % disk.size).humanReadable().upper()
+ popup_info = "%s | %s" % (disk.name, disk.serial)
+ overview = AnacondaWidgets.DiskOverview(disk.description,
+ kind,
+ size,
+ popup=popup_info)
+ 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_chi ldren()
+ for overview in overviews:
+ name = overview.get_property("popup-info").partition("|")[0].strip()
+ 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_labe l(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_chi ldren()
+ for overview in overviews:
+ name = overview.get_property("popup-info").partition("|")[0].strip()
+
+ 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_chi ldren()
+ for overview in overviews:
+ name = overview.get_property("popup-info").partition("|")[0].strip()
+
+ 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 = 12000 # TODO: find out where to get this
+ if disk_free >= required_space:
+ dialog = InstallOptions1Dialog(self.data)
+ elif sum([d.size for d in disks]) >= 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 (custom is %s)" % dialog.customize_state
+ 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..c36124d
--- /dev/null
+++ b/pyanaconda/ui/gui/spokes/storage.ui
@@ -0,0 +1,995 @@
+<?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 &amp; _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="halign">center</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="halign">center</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 &amp; 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="use_underline">True</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 &amp; _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="halign">center</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="halign">center</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="halign">center</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 &amp; 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="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_custom_toggled" 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="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="halign">center</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="halign">center</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="halign">center</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>
+ </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>
+ </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="halign">center</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>
+ <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="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="halign">center</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="main_box">
+ <object class="GtkBox" id="AnacondaSpokeWindow-main_box1">
+ <property name="can_focus">False</property>
+


All times are GMT. The time now is 09:41 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.