[PATCH] Split out helper code from the Custom partitioning spoke

Martin Kolman mkolman at redhat.com
Thu Mar 13 09:45:18 UTC 2014


On Fri, 2014-03-07 at 21:59 +0100, Vratislav Podzimek wrote:
> The Custom partitioning spoke has a lot of helper code that can live in a
> separate module decreasing the unmaintainable complexity and length of the
> spoke's module.
> 
> Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
> ---
>  pyanaconda/ui/gui/spokes/custom.glade              |  988 ------------------
>  pyanaconda/ui/gui/spokes/custom.py                 |  665 +-----------
>  .../ui/gui/spokes/lib/custom_storage_helpers.glade | 1059 ++++++++++++++++++++
>  .../ui/gui/spokes/lib/custom_storage_helpers.py    |  658 ++++++++++++
>  4 files changed, 1745 insertions(+), 1625 deletions(-)
>  create mode 100644 pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade
>  create mode 100644 pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py
> 
> diff --git a/pyanaconda/ui/gui/spokes/custom.glade b/pyanaconda/ui/gui/spokes/custom.glade
> index 21fc241..e563d47 100644
> --- a/pyanaconda/ui/gui/spokes/custom.glade
> +++ b/pyanaconda/ui/gui/spokes/custom.glade
> @@ -3,712 +3,6 @@
>  <interface>
>    <!-- interface-requires gtk+ 3.2 -->
>    <!-- interface-requires AnacondaWidgets 1.0 -->
> -  <object class="GtkDialog" id="addDialog">
> -    <property name="can_focus">False</property>
> -    <property name="border_width">6</property>
> -    <property name="type_hint">dialog</property>
> -    <property name="decorated">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">2</property>
> -        <child internal-child="action_area">
> -          <object class="GtkButtonBox" id="dialog-action_area1">
> -            <property name="can_focus">False</property>
> -            <property name="margin_top">24</property>
> -            <property name="layout_style">end</property>
> -            <child>
> -              <object class="GtkButton" id="addCancelButton">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">_Cancel</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="halign">end</property>
> -                <property name="use_underline">True</property>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">0</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkButton" id="addConfirmButton">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">_Add mount point</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="halign">end</property>
> -                <property name="use_underline">True</property>
> -                <signal name="clicked" handler="on_add_confirm_clicked" swapped="no"/>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</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="GtkGrid" id="grid4">
> -            <property name="visible">True</property>
> -            <property name="can_focus">False</property>
> -            <property name="column_spacing">6</property>
> -            <child>
> -              <object class="GtkLabel" id="label7">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="margin_top">6</property>
> -                <property name="xalign">1</property>
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">_Desired Capacity:</property>
> -                <property name="use_underline">True</property>
> -                <property name="mnemonic_widget">addSizeEntry</property>
> -                <attributes>
> -                  <attribute name="weight" value="bold"/>
> -                </attributes>
> -              </object>
> -              <packing>
> -                <property name="left_attach">0</property>
> -                <property name="top_attach">4</property>
> -                <property name="width">1</property>
> -                <property name="height">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkLabel" id="label6">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="xalign">0</property>
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">Mount _Point:</property>
> -                <property name="use_underline">True</property>
> -                <property name="mnemonic_widget">addMountPointEntry</property>
> -                <attributes>
> -                  <attribute name="weight" value="bold"/>
> -                </attributes>
> -              </object>
> -              <packing>
> -                <property name="left_attach">0</property>
> -                <property name="top_attach">2</property>
> -                <property name="width">1</property>
> -                <property name="height">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkLabel" id="label8">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="margin_bottom">12</property>
> -                <property name="xalign">0</property>
> -                <property name="label" translatable="yes">ADD A NEW MOUNT POINT</property>
> -                <attributes>
> -                  <attribute name="weight" value="bold"/>
> -                  <attribute name="scale" value="1.2"/>
> -                </attributes>
> -              </object>
> -              <packing>
> -                <property name="left_attach">0</property>
> -                <property name="top_attach">0</property>
> -                <property name="width">2</property>
> -                <property name="height">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkLabel" id="label12">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="margin_bottom">12</property>
> -                <property name="label" translatable="yes">More customization options are available
> -after creating the mount point below.</property>
> -                <attributes>
> -                  <attribute name="font-desc" value="Cantarell 11"/>
> -                  <attribute name="scale" value="1"/>
> -                </attributes>
> -              </object>
> -              <packing>
> -                <property name="left_attach">0</property>
> -                <property name="top_attach">1</property>
> -                <property name="width">2</property>
> -                <property name="height">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkBox" id="addLabelWarningBox">
> -                <property name="can_focus">False</property>
> -                <property name="valign">start</property>
> -                <property name="spacing">6</property>
> -                <child>
> -                  <object class="GtkImage" id="image1">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="stock">gtk-dialog-warning</property>
> -                    <property name="icon_size">2</property>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">0</property>
> -                  </packing>
> -                </child>
> -                <child>
> -                  <object class="GtkLabel" id="mountPointWarningLabel">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="label" translatable="yes">That mount point is already in
> -use.  Try something else?</property>
> -                    <attributes>
> -                      <attribute name="font-desc" value="Cantarell 10"/>
> -                      <attribute name="scale" value="1"/>
> -                      <attribute name="foreground" value="#ffff00000000"/>
> -                    </attributes>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">1</property>
> -                  </packing>
> -                </child>
> -              </object>
> -              <packing>
> -                <property name="left_attach">1</property>
> -                <property name="top_attach">3</property>
> -                <property name="width">1</property>
> -                <property name="height">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkEntry" id="addSizeEntry">
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="tooltip_text" translatable="yes">eg: "20 GB", "500mb" (minus the quotation marks)</property>
> -                <property name="invisible_char">●</property>
> -              </object>
> -              <packing>
> -                <property name="left_attach">1</property>
> -                <property name="top_attach">4</property>
> -                <property name="width">1</property>
> -                <property name="height">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkComboBoxText" id="addMountPointEntry">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="has_entry">True</property>
> -                <child internal-child="entry">
> -                  <object class="GtkEntry" id="comboboxtext-entry">
> -                    <property name="can_focus">True</property>
> -                    <property name="buffer">mountPointEntryBuffer</property>
> -                    <property name="completion">mountPointCompletion</property>
> -                  </object>
> -                </child>
> -              </object>
> -              <packing>
> -                <property name="left_attach">1</property>
> -                <property name="top_attach">2</property>
> -                <property name="width">1</property>
> -                <property name="height">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <placeholder/>
> -            </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">addCancelButton</action-widget>
> -      <action-widget response="1">addConfirmButton</action-widget>
> -    </action-widgets>
> -  </object>
> -  <object class="GtkDialog" id="confirmDeleteDialog">
> -    <property name="can_focus">False</property>
> -    <property name="border_width">6</property>
> -    <property name="type_hint">dialog</property>
> -    <property name="decorated">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">2</property>
> -        <child>
> -          <object class="GtkLabel" id="confirmLabel">
> -            <property name="visible">True</property>
> -            <property name="can_focus">False</property>
> -            <property name="xalign">0</property>
> -            <property name="yalign">0</property>
> -            <property name="wrap">True</property>
> -            <attributes>
> -              <attribute name="font-desc" value="Cantarell 11"/>
> -            </attributes>
> -          </object>
> -          <packing>
> -            <property name="expand">True</property>
> -            <property name="fill">True</property>
> -            <property name="position">0</property>
> -          </packing>
> -        </child>
> -        <child>
> -          <object class="GtkCheckButton" id="removeAllCheckbox">
> -            <property name="visible">True</property>
> -            <property name="can_focus">True</property>
> -            <property name="receives_default">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="position">1</property>
> -          </packing>
> -        </child>
> -        <child internal-child="action_area">
> -          <object class="GtkButtonBox" id="dialog-action_area2">
> -            <property name="can_focus">False</property>
> -            <property name="layout_style">end</property>
> -            <child>
> -              <object class="GtkButton" id="deleteCancelButton">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Confirm Delete Dialog">_Cancel</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="can_default">True</property>
> -                <property name="has_default">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="use_underline">True</property>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">0</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkButton" id="deleteConfirmButton">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Confirm Delete Dialog">_Delete It</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="use_underline">True</property>
> -                <signal name="clicked" handler="on_delete_confirm_clicked" swapped="no"/>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</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">2</property>
> -          </packing>
> -        </child>
> -      </object>
> -    </child>
> -    <action-widgets>
> -      <action-widget response="0">deleteCancelButton</action-widget>
> -      <action-widget response="1">deleteConfirmButton</action-widget>
> -    </action-widgets>
> -  </object>
> -  <object class="GtkTreeModelFilter" id="containerRaidStoreFiltered">
> -    <property name="child_model">raidLevelStore</property>
> -  </object>
> -  <object class="GtkDialog" id="container_dialog">
> -    <property name="can_focus">False</property>
> -    <property name="border_width">6</property>
> -    <property name="type_hint">dialog</property>
> -    <property name="decorated">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>
> -            <property name="layout_style">end</property>
> -            <child>
> -              <object class="GtkButton" id="container_cancel_button">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">_Cancel</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="use_underline">True</property>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">0</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkButton" id="container_save_button">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">_Save</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="use_underline">True</property>
> -                <signal name="clicked" handler="on_save_clicked" swapped="no"/>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</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="box10">
> -            <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="container_dialog_title_label">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="xalign">0</property>
> -                <property name="label" translatable="yes">CONFIGURE CONTAINER</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="container_dialog_label">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="label" translatable="yes">Please create a name for this container and select at least one disk below.</property>
> -                <property name="wrap">True</property>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkBox" id="box11">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="spacing">6</property>
> -                <child>
> -                  <object class="GtkLabel" id="nameLabel">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">_Name:</property>
> -                    <property name="use_underline">True</property>
> -                    <property name="mnemonic_widget">container_name_entry</property>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">0</property>
> -                  </packing>
> -                </child>
> -                <child>
> -                  <object class="GtkEntry" id="container_name_entry">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">True</property>
> -                    <property name="invisible_char">●</property>
> -                    <accelerator key="n" signal="grab-focus" modifiers="GDK_MOD1_MASK"/>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">1</property>
> -                  </packing>
> -                </child>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">2</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkScrolledWindow" id="scrolledwindow2">
> -                <property name="height_request">150</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="hexpand">True</property>
> -                <property name="vexpand">True</property>
> -                <property name="shadow_type">in</property>
> -                <child>
> -                  <object class="GtkViewport" id="viewport2">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <child>
> -                      <object class="GtkTreeView" id="container_disk_view">
> -                        <property name="visible">True</property>
> -                        <property name="can_focus">True</property>
> -                        <property name="model">disk_store</property>
> -                        <property name="search_column">0</property>
> -                        <child internal-child="selection">
> -                          <object class="GtkTreeSelection" id="treeview-selection3">
> -                            <property name="mode">multiple</property>
> -                          </object>
> -                        </child>
> -                        <child>
> -                          <object class="GtkTreeViewColumn" id="disk_column1">
> -                            <property name="spacing">6</property>
> -                            <property name="title" translatable="yes">Disk</property>
> -                            <property name="clickable">True</property>
> -                            <child>
> -                              <object class="GtkCellRendererText" id="disk_renderer1"/>
> -                              <attributes>
> -                                <attribute name="text">0</attribute>
> -                              </attributes>
> -                            </child>
> -                          </object>
> -                        </child>
> -                        <child>
> -                          <object class="GtkTreeViewColumn" id="capacity_column1">
> -                            <property name="spacing">6</property>
> -                            <property name="title" translatable="yes">Capacity</property>
> -                            <property name="clickable">True</property>
> -                            <child>
> -                              <object class="GtkCellRendererText" id="capacity_renderer1"/>
> -                              <attributes>
> -                                <attribute name="text">1</attribute>
> -                              </attributes>
> -                            </child>
> -                          </object>
> -                        </child>
> -                        <child>
> -                          <object class="GtkTreeViewColumn" id="free_column1">
> -                            <property name="spacing">6</property>
> -                            <property name="title" translatable="yes">Free</property>
> -                            <property name="clickable">True</property>
> -                            <child>
> -                              <object class="GtkCellRendererText" id="free_renderer1"/>
> -                              <attributes>
> -                                <attribute name="text">2</attribute>
> -                              </attributes>
> -                            </child>
> -                          </object>
> -                        </child>
> -                        <child>
> -                          <object class="GtkTreeViewColumn" id="id_column1">
> -                            <property name="spacing">6</property>
> -                            <property name="title" translatable="yes">ID</property>
> -                            <property name="clickable">True</property>
> -                            <child>
> -                              <object class="GtkCellRendererText" id="id_renderer1"/>
> -                              <attributes>
> -                                <attribute name="text">3</attribute>
> -                              </attributes>
> -                            </child>
> -                          </object>
> -                        </child>
> -                      </object>
> -                    </child>
> -                  </object>
> -                </child>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">3</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkBox" id="box3">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="spacing">6</property>
> -                <child>
> -                  <object class="GtkLabel" id="containerRaidLevelLabel">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="xalign">0</property>
> -                    <property name="label" translatable="yes">RAID Level:</property>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">0</property>
> -                  </packing>
> -                </child>
> -                <child>
> -                  <object class="GtkComboBox" id="containerRaidLevelCombo">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="model">containerRaidStoreFiltered</property>
> -                    <child>
> -                      <object class="GtkCellRendererText" id="containerRaidLevelRenderer"/>
> -                      <attributes>
> -                        <attribute name="markup">0</attribute>
> -                      </attributes>
> -                    </child>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">1</property>
> -                  </packing>
> -                </child>
> -                <child>
> -                  <object class="GtkCheckButton" id="containerEncryptedCheckbox">
> -                    <property name="label" translatable="yes">Encrypt</property>
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">True</property>
> -                    <property name="receives_default">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">4</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkBox" id="containerErrorBox">
> -                <property name="can_focus">False</property>
> -                <property name="spacing">6</property>
> -                <child>
> -                  <object class="GtkImage" id="containerErrorImage">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="stock">gtk-dialog-warning</property>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">0</property>
> -                  </packing>
> -                </child>
> -                <child>
> -                  <object class="GtkLabel" id="containerErrorLabel">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="label" translatable="yes">Please enter a valid name.</property>
> -                    <property name="wrap">True</property>
> -                    <attributes>
> -                      <attribute name="font-desc" value="Cantarell 10"/>
> -                      <attribute name="scale" value="1"/>
> -                      <attribute name="foreground" value="#ffff00000000"/>
> -                    </attributes>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">1</property>
> -                  </packing>
> -                </child>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">5</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkBox" id="containerSizeBox">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="spacing">6</property>
> -                <child>
> -                  <object class="GtkLabel" id="containerSizeLabel">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">Si_ze policy:</property>
> -                    <property name="use_underline">True</property>
> -                    <property name="mnemonic_widget">containerSizeCombo</property>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">0</property>
> -                  </packing>
> -                </child>
> -                <child>
> -                  <object class="GtkComboBoxText" id="containerSizeCombo">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <items>
> -                      <item translatable="yes">Automatic</item>
> -                      <item translatable="yes">As large as possible</item>
> -                      <item translatable="yes">Fixed</item>
> -                    </items>
> -                    <signal name="changed" handler="on_size_changed" swapped="no"/>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">1</property>
> -                  </packing>
> -                </child>
> -                <child>
> -                  <object class="GtkEntry" id="containerSizeEntry">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">True</property>
> -                    <property name="invisible_char">●</property>
> -                  </object>
> -                  <packing>
> -                    <property name="expand">False</property>
> -                    <property name="fill">True</property>
> -                    <property name="position">2</property>
> -                  </packing>
> -                </child>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">6</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">container_cancel_button</action-widget>
> -      <action-widget response="1">container_save_button</action-widget>
> -    </action-widgets>
> -  </object>
>    <object class="AnacondaSpokeWindow" id="customStorageWindow">
>      <property name="can_focus">False</property>
>      <property name="events">GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
> @@ -1926,288 +1220,6 @@ until you click on the main menu's 'Begin Installation' button.</property>
>        </object>
>      </child>
>    </object>
> -  <object class="GtkListStore" id="disk_store">
> -    <columns>
> -      <!-- column-name disk_col -->
> -      <column type="gchararray"/>
> -      <!-- column-name capacity_col -->
> -      <column type="gchararray"/>
> -      <!-- column-name free_col -->
> -      <column type="gchararray"/>
> -      <!-- column-name serial_col -->
> -      <column type="gchararray"/>
> -      <!-- column-name id_col -->
> -      <column type="gint"/>
> -    </columns>
> -  </object>
> -  <object class="GtkDialog" id="disks_dialog">
> -    <property name="width_request">400</property>
> -    <property name="height_request">200</property>
> -    <property name="can_focus">False</property>
> -    <property name="border_width">6</property>
> -    <property name="type_hint">dialog</property>
> -    <property name="decorated">False</property>
> -    <child internal-child="vbox">
> -      <object class="GtkBox" id="dialog-vbox4">
> -        <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_area4">
> -            <property name="can_focus">False</property>
> -            <property name="layout_style">end</property>
> -            <child>
> -              <object class="GtkButton" id="cancel_button">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Configure Dialog">_Cancel</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</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="select_button">
> -                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Configure Dialog">_Select</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="use_underline">True</property>
> -                <signal name="clicked" handler="on_select_clicked" swapped="no"/>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</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="box1">
> -            <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="disk_selection_title_label">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="xalign">0</property>
> -                <property name="label" translatable="yes">CONFIGURE MOUNT POINT</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="label11">
> -                <property name="visible">True</property>
> -                <property name="can_focus">False</property>
> -                <property name="label" translatable="yes">Select one or more disks this device may reside on.</property>
> -                <property name="wrap">True</property>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">1</property>
> -              </packing>
> -            </child>
> -            <child>
> -              <object class="GtkScrolledWindow" id="scrolledwindow1">
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="hexpand">True</property>
> -                <property name="vexpand">True</property>
> -                <property name="shadow_type">in</property>
> -                <child>
> -                  <object class="GtkViewport" id="viewport1">
> -                    <property name="visible">True</property>
> -                    <property name="can_focus">False</property>
> -                    <child>
> -                      <object class="GtkTreeView" id="disk_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_view_selection">
> -                            <property name="mode">multiple</property>
> -                          </object>
> -                        </child>
> -                        <child>
> -                          <object class="GtkTreeViewColumn" id="disk_column">
> -                            <property name="spacing">6</property>
> -                            <property name="title" translatable="yes">Disk</property>
> -                            <property name="clickable">True</property>
> -                            <child>
> -                              <object class="GtkCellRendererText" id="disk_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>
> -                            <property name="clickable">True</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>
> -                            <property name="clickable">True</property>
> -                            <child>
> -                              <object class="GtkCellRendererText" id="id_renderer"/>
> -                              <attributes>
> -                                <attribute name="text">3</attribute>
> -                              </attributes>
> -                            </child>
> -                          </object>
> -                        </child>
> -                      </object>
> -                    </child>
> -                  </object>
> -                </child>
> -              </object>
> -              <packing>
> -                <property name="expand">False</property>
> -                <property name="fill">True</property>
> -                <property name="position">2</property>
> -              </packing>
> -            </child>
> -          </object>
> -          <packing>
> -            <property name="expand">False</property>
> -            <property name="fill">True</property>
> -            <property name="position">1</property>
> -          </packing>
> -        </child>
> -      </object>
> -    </child>
> -    <action-widgets>
> -      <action-widget response="0">cancel_button</action-widget>
> -      <action-widget response="1">select_button</action-widget>
> -    </action-widgets>
> -  </object>
> -  <object class="GtkTextBuffer" id="help_text_buffer"/>
> -  <object class="GtkDialog" id="help_dialog">
> -    <property name="width_request">600</property>
> -    <property name="height_request">400</property>
> -    <property name="can_focus">False</property>
> -    <property name="border_width">6</property>
> -    <property name="title" translatable="yes">Help</property>
> -    <property name="modal">True</property>
> -    <property name="window_position">center-on-parent</property>
> -    <property name="type_hint">dialog</property>
> -    <signal name="close" handler="on_close" swapped="no"/>
> -    <child internal-child="vbox">
> -      <object class="GtkBox" id="dialog-vbox6">
> -        <property name="can_focus">False</property>
> -        <property name="orientation">vertical</property>
> -        <property name="spacing">2</property>
> -        <child internal-child="action_area">
> -          <object class="GtkButtonBox" id="dialog-action_area6">
> -            <property name="can_focus">False</property>
> -            <property name="layout_style">end</property>
> -            <child>
> -              <object class="GtkButton" id="help_close_button">
> -                <property name="label">gtk-close</property>
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="receives_default">True</property>
> -                <property name="use_stock">True</property>
> -                <signal name="clicked" handler="on_close" 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="GtkScrolledWindow" id="scrolledwindow3">
> -            <property name="visible">True</property>
> -            <property name="can_focus">True</property>
> -            <property name="shadow_type">in</property>
> -            <child>
> -              <object class="GtkTextView" id="help_text_view">
> -                <property name="visible">True</property>
> -                <property name="can_focus">True</property>
> -                <property name="editable">False</property>
> -                <property name="wrap_mode">word</property>
> -                <property name="cursor_visible">False</property>
> -                <property name="buffer">help_text_buffer</property>
> -              </object>
> -            </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">help_close_button</action-widget>
> -    </action-widgets>
> -  </object>
> -  <object class="GtkEntryBuffer" id="mountPointEntryBuffer"/>
> -  <object class="GtkListStore" id="mountPointStore">
> -    <columns>
> -      <!-- column-name path -->
> -      <column type="gchararray"/>
> -    </columns>
> -  </object>
> -  <object class="GtkEntryCompletion" id="mountPointCompletion">
> -    <property name="model">mountPointStore</property>
> -  </object>
>    <object class="GtkListStore" id="raidLevelStore">
>      <columns>
>        <!-- column-name raidLevel -->
> diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
> index 4cc2a2c..4e12a7c 100644
> --- a/pyanaconda/ui/gui/spokes/custom.py
> +++ b/pyanaconda/ui/gui/spokes/custom.py
> @@ -1,4 +1,4 @@
> -# vim: set fileencoding=utf-8
> +#
>  # Custom partitioning classes.
>  #
>  # Copyright (C) 2012-2014  Red Hat, Inc.
> @@ -29,13 +29,9 @@
>  # - Implement striping and mirroring for LVM.
>  # - Activating reformat should always enable resize for existing devices.
>  
> -from contextlib import contextmanager
> -import re
> -import locale
> -
>  from pykickstart.constants import CLEARPART_TYPE_NONE, AUTOPART_TYPE_PLAIN, AUTOPART_TYPE_BTRFS, AUTOPART_TYPE_LVM, AUTOPART_TYPE_LVM_THINP
>  
> -from pyanaconda.i18n import _, N_, C_, CP_
> +from pyanaconda.i18n import _, N_, CP_
>  from pyanaconda.product import productName, productVersion
>  from pyanaconda.threads import AnacondaThread, threadMgr
>  from pyanaconda.constants import THREAD_EXECUTE_STORAGE, THREAD_STORAGE, THREAD_CUSTOM_STORAGE_INIT
> @@ -46,7 +42,6 @@ from blivet import devicefactory
>  from blivet.formats import device_formats
>  from blivet.formats import getFormat
>  from blivet.formats.fs import FS
> -from blivet.platform import platform
>  from blivet.size import Size
>  from blivet import Root
>  from blivet.devicefactory import DEVICE_TYPE_LVM
> @@ -57,13 +52,11 @@ from blivet.devicefactory import DEVICE_TYPE_DISK
>  from blivet.devicefactory import DEVICE_TYPE_LVM_THINP
>  from blivet.devicefactory import get_raid_level
>  from blivet.devicefactory import SIZE_POLICY_AUTO
> -from blivet.devicefactory import SIZE_POLICY_MAX
>  from blivet import findExistingInstallations
>  from blivet.partitioning import doAutoPartition
>  from blivet.errors import StorageError
>  from blivet.errors import NoDisksError
>  from blivet.errors import NotEnoughFreeSpaceError
> -from blivet.errors import SizeParamsError
>  from blivet.errors import SanityError
>  from blivet.errors import SanityWarning
>  from blivet.errors import LUKSDeviceWithoutKeyError
> @@ -71,7 +64,6 @@ from blivet.devicelibs import mdraid
>  from blivet.devices import LUKSDevice
>  
>  from pyanaconda.ui.communication import hubQ
> -from pyanaconda.ui.gui import GUIObject
>  from pyanaconda.ui.gui.spokes import NormalSpoke
>  from pyanaconda.ui.gui.spokes.storage import StorageChecker
>  from pyanaconda.ui.gui.spokes.lib.cart import SelectedDisksDialog
> @@ -79,6 +71,13 @@ from pyanaconda.ui.gui.spokes.lib.passphrase import PassphraseDialog
>  from pyanaconda.ui.gui.spokes.lib.accordion import selectorFromDevice, Accordion, Page, CreateNewPage, UnknownPage
>  from pyanaconda.ui.gui.spokes.lib.refresh import RefreshDialog
>  from pyanaconda.ui.gui.spokes.lib.summary import ActionSummaryDialog
> +
> +from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import size_from_entry, ui_storage_logger
> +from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import validate_label, validate_mountpoint, selectedRaidLevel
> +from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import container_type_names, translated_new_install_name
> +from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import label_validation_msgs, mountpoint_validation_msgs, raid_level_not_enough_disks_msg, LABEL_OK # will go away soon
> +from pyanaconda.ui.gui.spokes.lib.custom_storage_helpers import AddDialog, ConfirmDeleteDialog, DisksDialog, ContainerDialog, HelpDialog
> +
>  from pyanaconda.ui.gui.utils import setViewportBackground, enlightbox, fancy_set_sensitive, ignoreEscape
>  from pyanaconda.ui.gui.utils import really_hide, really_show, fire_gtk_action
>  from pyanaconda.ui.gui.categories.system import SystemCategory
> @@ -97,57 +96,6 @@ NOTEBOOK_LUKS_PAGE = 2
>  NOTEBOOK_UNEDITABLE_PAGE = 3
>  NOTEBOOK_INCOMPLETE_PAGE = 4
>  
> -new_install_name = N_("New %(name)s %(version)s Installation")
> -new_container_text = N_("Create a new %(container_type)s ...")
> -container_tooltip = N_("Create or select %(container_type)s")
> -container_dialog_title = N_("CONFIGURE %(container_type)s")
> -container_dialog_text = N_("Please create a name for this %(container_type)s "
> -                           "and select at least one disk below.")
> -lvm_container_name = N_("Volume Group")
> -btrfs_container_name = N_("Volume")
> -unrecoverable_error_msg = N_("Storage configuration reset due to unrecoverable "
> -                             "error. Click for details.")
> -device_configuration_error_msg = N_("Device reconfiguration failed. Click for "
> -                                    "details.")
> -
> -label_format_invalid_msg = N_("Unacceptable label format for filesystem.")
> -label_application_unavailable_msg = N_("Can not set label on filesystem.")
> -label_resetting_forbidden_msg = N_("Can not relabel already existing filesystem.")
> -
> -empty_mountpoint_msg = N_("Please enter a valid mountpoint.")
> -invalid_mountpoint_msg = N_("That mount point is invalid. Try something else?")
> -mountpoint_in_use_msg = N_("That mount point is already in use. Try something else?")
> -
> -raid_level_not_enough_disks_msg = N_("The RAID level you have selected (%(level)s) "
> -                                     "requires more disks (%(min)d) than you "
> -                                     "currently have selected (%(count)d).")
> -empty_name_msg = N_("Please enter a valid name.")
> -
> -container_type_names = {DEVICE_TYPE_LVM: lvm_container_name,
> -                        DEVICE_TYPE_LVM_THINP: lvm_container_name,
> -                        DEVICE_TYPE_BTRFS: btrfs_container_name}
> -
> -LABEL_OK = 0
> -LABEL_FORMAT_INVALID = 1
> -LABEL_APPLICATION_UNAVAILABLE = 2
> -LABEL_RESETTING_FORBIDDEN = 3
> -
> -label_validation_msgs = {
> -    LABEL_OK: "",
> -    LABEL_FORMAT_INVALID: label_format_invalid_msg,
> -    LABEL_APPLICATION_UNAVAILABLE: label_application_unavailable_msg,
> -    LABEL_RESETTING_FORBIDDEN: label_resetting_forbidden_msg}
> -
> -
> -MOUNTPOINT_OK = 0
> -MOUNTPOINT_INVALID = 1
> -MOUNTPOINT_IN_USE = 2
> -MOUNTPOINT_EMPTY = 3
> -
> -mountpoint_validation_msgs = {MOUNTPOINT_OK: "",
> -                              MOUNTPOINT_INVALID: invalid_mountpoint_msg,
> -                              MOUNTPOINT_IN_USE: mountpoint_in_use_msg,
> -                              MOUNTPOINT_EMPTY: empty_mountpoint_msg}
>  
>  DEVICE_TEXT_LVM = N_("LVM")
>  DEVICE_TEXT_LVM_THINP = N_("LVM Thin Provisioning")
> @@ -162,508 +110,16 @@ device_text_map = {DEVICE_TYPE_LVM: DEVICE_TEXT_LVM,
>                     DEVICE_TYPE_BTRFS: DEVICE_TEXT_BTRFS,
>                     DEVICE_TYPE_LVM_THINP: DEVICE_TEXT_LVM_THINP}
>  
> -partition_only_format_types = ["efi", "macefi", "prepboot", "biosboot",
> -                               "appleboot"]
> -
> -def size_from_entry(entry):
> -    size_text = entry.get_text().decode("utf-8").strip()
> -
> -    # Nothing to parse
> -    if not size_text:
> -        return None
> -
> -    # if no unit was specified, default to MiB. Assume that a string
> -    # ending with anything other than a digit has a unit suffix
> -    if re.search(r'[\d.%s]$' % locale.nl_langinfo(locale.RADIXCHAR), size_text):
> -        size_text += "MiB"
> -
> -    try:
> -        size = Size(spec=size_text)
> -    except (SizeParamsError, ValueError):
> -        return None
> -    else:
> -        # Minimium size for ui-created partitions is 1MiB.
> -        if size.convertTo(spec="MiB") < 1:
> -            size = Size(spec="1 MiB")
> -
> -    return size
> -
> -class UIStorageFilter(logging.Filter):
> -    def filter(self, record):
> -        record.name = "storage.ui"
> -        return True
> -
> - at contextmanager
> -def ui_storage_logger():
> -    storage_log = logging.getLogger("blivet")
> -    f = UIStorageFilter()
> -    storage_log.addFilter(f)
> -    yield
> -    storage_log.removeFilter(f)
> -
> -def populate_mountpoint_store(store, used_mountpoints):
> -    # sure, add whatever you want to this list. this is just a start.
> -    paths = ["/", "/boot", "/home", "/var"] + \
> -            platform.bootStage1ConstraintDict["mountpoints"]
> -
> -    # Sort the list now so all the real mountpoints go to the front, then
> -    # add all the pseudo mountpoints we have.
> -    paths.sort()
> -    paths += ["swap"]
> -
> -    for fmt in ["appleboot", "biosboot", "prepboot"]:
> -        if getFormat(fmt).supported:
> -            paths += [fmt]
> -
> -    for path in paths:
> -        if path not in used_mountpoints:
> -            store.append([path])
> -
> -def validate_label(label, fmt):
> -    """Returns a code indicating either that the given label can be set for
> -       this filesystem or the reason why it can not.
> -
> -       In the case where the format can not assign a label, the empty string
> -       stands for accept the default, but in the case where the format can
> -       assign a label the empty string represents itself.
> -
> -       :param str label: The label
> -       :param DeviceFormat fmt: The device format to label
> -
> -    """
> -    if fmt.exists:
> -        return LABEL_RESETTING_FORBIDDEN
> -    if not fmt.labeling():
> -        if label == "":
> -            return LABEL_OK
> -        else:
> -            return LABEL_APPLICATION_UNAVAILABLE
> -    if not fmt.labelFormatOK(label):
> -        return LABEL_FORMAT_INVALID
> -    return LABEL_OK
> -
> -def validate_mountpoint(mountpoint, used_mountpoints, strict=True):
> -    if strict:
> -        fake_mountpoints = []
> -    else:
> -        fake_mountpoints = ["swap", "biosboot", "prepboot"]
> -
> -    valid = MOUNTPOINT_OK
> -    if mountpoint in used_mountpoints:
> -        valid = MOUNTPOINT_IN_USE
> -    elif not mountpoint:
> -        valid = MOUNTPOINT_EMPTY
> -    elif mountpoint.startswith("/dev") or mountpoint.startswith("/proc") or \
> -         mountpoint.startswith("/sys"):
> -        valid = MOUNTPOINT_INVALID
> -    elif (lowerASCII(mountpoint) not in fake_mountpoints and
> -          ((len(mountpoint) > 1 and mountpoint.endswith("/")) or
> -           not mountpoint.startswith("/") or
> -           " " in mountpoint or
> -           re.search(r'/\.*/', mountpoint) or
> -           re.search(r'/\.+$', mountpoint))):
> -        # - does not end with '/' unless mountpoint _is_ '/'
> -        # - starts with '/' except for "swap", &c
> -        # - does not contain spaces
> -        # - does not contain pairs of '/' enclosing zero or more '.'
> -        # - does not end with '/' followed by one or more '.'
> -        valid = MOUNTPOINT_INVALID
> -
> -    return valid
> -
> -def selectedRaidLevel(raidLevelCombo):
> -    """Interpret the selection of a RAID level combo box."""
> -    if not raidLevelCombo.get_property("visible"):
> -        # the combo is hidden when raid level isn't applicable
> -        return None
> -
> -    itr = raidLevelCombo.get_active_iter()
> -    store = raidLevelCombo.get_model()
> -
> -    if not itr:
> -        return
> -
> -    selected_level_string = store[itr][0]   # eg: "RAID1 (Redundancy)"
> -    level = selected_level_string.split()[0]    # -> "RAID1"
> -
> -    # The RAID level strings are not translated, but the "None" string in
> -    # the container dialog is. Transformations in relation to "None" need
> -    # to happen within the locale settings, but transformations in
> -    # relation to "RAID* ..." need to happen only within ASCII. For example,
> -    # "RAID1".lower() in Turkish would become "raıd1", which is not what
> -    # we want.
> -    levelLocale = level.lower()
> -    levelASCII = lowerASCII(level)
> -
> -    if levelASCII == "none" or levelLocale == _("None").lower():
> -        return None
> -
> -    return levelASCII
> -
> -class AddDialog(GUIObject):
> -    builderObjects = ["addDialog", "mountPointStore", "mountPointCompletion", "mountPointEntryBuffer"]
> -    mainWidgetName = "addDialog"
> -    uiFile = "spokes/custom.glade"
> -
> -    def __init__(self, *args, **kwargs):
> -        self.mountpoints = kwargs.pop("mountpoints", [])
> -        GUIObject.__init__(self, *args, **kwargs)
> -        self.size = Size(bytes=0)
> -        self.mountpoint = ""
> -        self._error = False
> -
> -        store = self.builder.get_object("mountPointStore")
> -        populate_mountpoint_store(store, self.mountpoints)
> -        self.builder.get_object("addMountPointEntry").set_model(store)
> -
> -        completion = self.builder.get_object("mountPointCompletion")
> -        completion.set_text_column(0)
> -        completion.set_popup_completion(True)
> -
> -        self._warningLabel = self.builder.get_object("mountPointWarningLabel")
> -
> -    def on_add_confirm_clicked(self, button, *args):
> -        self.mountpoint = self.builder.get_object("addMountPointEntry").get_active_text()
> -        self._error = validate_mountpoint(self.mountpoint, self.mountpoints,
> -                                          strict=False)
> -        self._warningLabel.set_text(_(mountpoint_validation_msgs[self._error]))
> -        self.window.show_all()
> -        if self._error:
> -            return
> -
> -        self.size = size_from_entry(self.builder.get_object("addSizeEntry"))
> -        self.window.destroy()
> -
> -    def refresh(self):
> -        GUIObject.refresh(self)
> -        self._warningLabel.set_text("")
> -
> -    def run(self):
> -        while True:
> -            self._error = None
> -            rc = self.window.run()
> -            if not self._error:
> -                return rc
> -
> -class ConfirmDeleteDialog(GUIObject):
> -    builderObjects = ["confirmDeleteDialog"]
> -    mainWidgetName = "confirmDeleteDialog"
> -    uiFile = "spokes/custom.glade"
> -
> -    def __init__(self, *args, **kwargs):
> -        GUIObject.__init__(self, *args, **kwargs)
> -        self._removeAll = self.builder.get_object("removeAllCheckbox")
> -
> -    @property
> -    def deleteAll(self):
> -        return self._removeAll.get_active()
> -
> -    def on_delete_confirm_clicked(self, button, *args):
> -        self.window.destroy()
> -
> -    # pylint: disable=W0221
> -    def refresh(self, mountpoint, device, rootName, subvols=False):
> -        GUIObject.refresh(self)
> -        label = self.builder.get_object("confirmLabel")
> -
> -        if rootName and "_" in rootName:
> -            rootName = rootName.replace("_", "__")
> -        self._removeAll.set_label(
> -                C_("GUI|Custom Partitioning|Confirm Delete Dialog",
> -                    "Delete _all other filesystems in the %s root as well.")
> -                % rootName)
> -        self._removeAll.set_sensitive(rootName is not None)
> -
> -        if mountpoint:
> -            txt = "%s (%s)" % (mountpoint, device)
> -        else:
> -            txt = device
> -
> -        if not subvols:
> -            label_text = _("Are you sure you want to delete all of the data on %s?") % txt
> -        else:
> -            label_text = _("Are you sure you want to delete all of the data on %s, including subvolumes and/or snapshots?") % txt
> -
> -        label.set_text(label_text)
> -
> -    def run(self):
> -        return self.window.run()
> -
> -class DisksDialog(GUIObject):
> -    builderObjects = ["disks_dialog", "disk_store", "disk_view"]
> -    mainWidgetName = "disks_dialog"
> -    uiFile = "spokes/custom.glade"
> -
> -    def __init__(self, *args, **kwargs):
> -        self._disks = kwargs.pop("disks")
> -        free = kwargs.pop("free")
> -        self.selected = kwargs.pop("selected")[:]
> -        GUIObject.__init__(self, *args, **kwargs)
> -        self._store = self.builder.get_object("disk_store")
> -        # populate the store
> -        for disk in self._disks:
> -            self._store.append([disk.description,
> -                                str(disk.size),
> -                                str(free[disk.name][0]),
> -                                disk.serial,
> -                                disk.id])
> -
> -        treeview = self.builder.get_object("disk_view")
> -        model = treeview.get_model()
> -        itr = model.get_iter_first()
> -        selected_ids = [d.id for d in self.selected]
> -        selection = treeview.get_selection()
> -        while itr:
> -            disk_id = model.get_value(itr, 4)
> -            if disk_id in selected_ids:
> -                selection.select_iter(itr)
> -
> -            itr = model.iter_next(itr)
> -
> -    def on_cancel_clicked(self, button):
> -        self.window.destroy()
> -
> -    def _get_disk_by_id(self, disk_id):
> -        for disk in self._disks:
> -            if disk.id == disk_id:
> -                return disk
> -
> -    def on_select_clicked(self, button):
> -        treeview = self.builder.get_object("disk_view")
> -        model, paths = treeview.get_selection().get_selected_rows()
> -        self.selected = []
> -        for path in paths:
> -            itr = model.get_iter(path)
> -            disk_id = model.get_value(itr, 4)
> -            self.selected.append(self._get_disk_by_id(disk_id))
> -
> -        self.window.destroy()
> -
> -    def run(self):
> -        return self.window.run()
> -
> -class ContainerDialog(GUIObject):
> -    builderObjects = ["container_dialog", "disk_store", "container_disk_view",
> -                      "containerRaidStoreFiltered", "containerRaidLevelLabel",
> -                      "containerRaidLevelCombo", "raidLevelStore",
> -                      "containerSizeCombo", "containerSizeEntry",
> -                      "containerSizeLabel", "containerEncryptedCheckbox"]
> -    mainWidgetName = "container_dialog"
> -    uiFile = "spokes/custom.glade"
> -
> -    def __init__(self, *args, **kwargs):
> -        # these are all absolutely required. not getting them is fatal.
> -        self._disks = kwargs.pop("disks")
> -        free = kwargs.pop("free")
> -        self.selected = kwargs.pop("selected")[:]
> -        self.name = kwargs.pop("name") or "" # make sure it's a string
> -        self.device_type = kwargs.pop("device_type")
> -
> -        # these are less critical
> -        self.raid_level = kwargs.pop("raid_level", None) or None # not ""
> -        self.encrypted = kwargs.pop("encrypted", False)
> -        self.exists = kwargs.pop("exists", False)
> -
> -        self.size_policy = kwargs.pop("size_policy", SIZE_POLICY_AUTO)
> -        self.size = kwargs.pop("size", Size(bytes=0))
> -
> -        self._error = None
> -        GUIObject.__init__(self, *args, **kwargs)
> -
> -        self._grabObjects()
> -
> -        # set up the dialog labels with device-type-specific text
> -        if self.device_type in container_type_names:
> -            container_type = _(container_type_names[self.device_type])
> -        else:
> -            container_type = _("container")
> -        title_text = _(container_dialog_title) % {"container_type": container_type.upper()}
> -        self._title_label.set_text(title_text)
> -
> -        dialog_text = _(container_dialog_text) % {"container_type": container_type.lower()}
> -        self._dialog_label.set_text(dialog_text)
> -
> -        # populate the dialog widgets
> -        self._name_entry.set_text(self.name)
> -
> -        # populate the store
> -        for disk in self._disks:
> -            self._store.append([disk.description,
> -                                str(disk.size),
> -                                str(free[disk.name][0]),
> -                                disk.serial,
> -                                disk.id])
> -
> -        model = self._treeview.get_model()
> -        itr = model.get_iter_first()
> -
> -        selected_ids = [d.id for d in self.selected]
> -        selection = self._treeview.get_selection()
> -        while itr:
> -            disk_id = model.get_value(itr, 4)
> -            if disk_id in selected_ids:
> -                selection.select_iter(itr)
> -
> -            itr = model.iter_next(itr)
> -
> -        # XXX how will this be related to the device encryption setting?
> -        self._encryptCheckbutton.set_active(self.encrypted)
> -
> -        # set up the raid level combo
> -        # XXX how will this be related to the device raid level setting?
> -        self._raidStoreFilter.set_visible_func(self._raid_level_visible)
> -        self._raidStoreFilter.refilter()
> -        self._populate_raid()
> -
> -        self._sizeEntry.set_text(self.size.humanReadable(max_places=None))
> -        if self.size_policy == SIZE_POLICY_AUTO:
> -            self._sizeCombo.set_active(0)
> -        elif self.size_policy == SIZE_POLICY_MAX:
> -            self._sizeCombo.set_active(1)
> -        else:
> -            self._sizeCombo.set_active(2)
> -
> -        if self.exists:
> -            fancy_set_sensitive(self._name_entry, False)
> -            self._treeview.set_sensitive(False)
> -            fancy_set_sensitive(self._encryptCheckbutton, False)
> -            fancy_set_sensitive(self._sizeCombo, False)
> -            self._sizeEntry.set_sensitive(False)
> -
> -    def _grabObjects(self):
> -        self._title_label = self.builder.get_object("container_dialog_title_label")
> -        self._dialog_label = self.builder.get_object("container_dialog_label")
> -        self._error_label = self.builder.get_object("containerErrorLabel")
> -
> -        self._name_entry = self.builder.get_object("container_name_entry")
> -
> -        self._encryptCheckbutton = self.builder.get_object("containerEncryptedCheckbox")
> -        self._raidStoreFilter = self.builder.get_object("containerRaidStoreFiltered")
> -
> -        self._store = self.builder.get_object("disk_store")
> -        self._treeview = self.builder.get_object("container_disk_view")
> -
> -        self._sizeCombo = self.builder.get_object("containerSizeCombo")
> -        self._sizeEntry = self.builder.get_object("containerSizeEntry")
> -
> -        self._raidLevelCombo = self.builder.get_object("containerRaidLevelCombo")
> -        self._raidLevelLabel = self.builder.get_object("containerRaidLevelLabel")
> -
> -    def _get_disk_by_id(self, disk_id):
> -        for disk in self._disks:
> -            if disk.id == disk_id:
> -                return disk
> -
> -    def on_save_clicked(self, button):
> -        if self.exists:
> -            self.window.destroy()
> -            return
> -
> -        # If no name was entered, quit the dialog as if they did nothing.
> -        name = self._name_entry.get_text().strip()
> -        if not name:
> -            self._error = _(empty_name_msg)
> -            self._error_label.set_text(self._error)
> -            self.window.show_all()
> -            return
> -
> -        model, paths = self._treeview.get_selection().get_selected_rows()
> -
> -        raid_level = selectedRaidLevel(self._raidLevelCombo)
> -        if raid_level:
> -            md_level = mdraid.getRaidLevel(raid_level)
> -            min_disks = md_level.min_members
> -            if len(paths) < min_disks:
> -                self._error = (_(raid_level_not_enough_disks_msg)
> -                                 % {"level" : md_level,
> -                                     "min" : min_disks,
> -                                     "count" : len(paths)})
> -                self._error_label.set_text(self._error)
> -                self.window.show_all()
> -                return
> -
> -        idx = self._sizeCombo.get_active()
> -        if idx == 0:
> -            size = SIZE_POLICY_AUTO
> -        elif idx == 1:
> -            size = SIZE_POLICY_MAX
> -        elif idx == 2:
> -            size = size_from_entry(self._sizeEntry)
> -            if size is None:
> -                size = SIZE_POLICY_MAX
> -
> -        # now save the changes
> -
> -        self.selected = []
> -        for path in paths:
> -            itr = model.get_iter(path)
> -            disk_id = model.get_value(itr, 4)
> -            self.selected.append(self._get_disk_by_id(disk_id))
> -
> -        self.name = name
> -        self.raid_level = raid_level
> -        self.encrypted = self._encryptCheckbutton.get_active()
> -        self.size_policy = size
> -
> -        self._error_label.set_text("")
> -        self.window.destroy()
> -
> -    def run(self):
> -        while True:
> -            self._error = None
> -            rc = self.window.run()
> -            if not self._error:
> -                return rc
> -
> -    def on_size_changed(self, combo):
> -        active_index = combo.get_active()
> -        if active_index == 0:
> -            self._sizeEntry.set_sensitive(False)
> -        elif active_index == 1:
> -            self._sizeEntry.set_sensitive(False)
> -        else:
> -            self._sizeEntry.set_sensitive(True)
> -
> -    def _raid_level_visible(self, model, itr, user_data):
> -        # This is weird because for lvm's container-wide raid we use md.
> -        if self.device_type in (DEVICE_TYPE_LVM, DEVICE_TYPE_LVM_THINP):
> -            return model[itr][4]
> -        elif self.device_type == DEVICE_TYPE_BTRFS:
> -            return model[itr][3]
> -
> -    def _populate_raid(self):
> -        """ Set up the raid-specific portion of the device details. """
> -        if self.device_type not in [DEVICE_TYPE_LVM, DEVICE_TYPE_BTRFS, DEVICE_TYPE_LVM_THINP]:
> -            map(really_hide, [self._raidLevelLabel, self._raidLevelCombo])
> -            return
> -
> -        raid_level = self.raid_level
> -        if not raid_level or raid_level == "single":
> -            raid_level = _("None")
> -
> -        # Set a default RAID level in the combo.
> -        for (i, row) in enumerate(self._raidLevelCombo.get_model()):
> -            log.debug("container dialog: raid level %s", row[0])
> -            if row[0].upper().startswith(raid_level.upper()):
> -                self._raidLevelCombo.set_active(i)
> -                break
> -
> -        map(really_show, [self._raidLevelLabel, self._raidLevelCombo])
> -        fancy_set_sensitive(self._raidLevelCombo, not self.exists)
> -
> -class HelpDialog(GUIObject):
> -    builderObjects = ["help_dialog", "help_text_view", "help_text_buffer"]
> -    mainWidgetName = "help_dialog"
> -    uiFile = "spokes/custom.glade"
> +new_container_text = N_("Create a new %(container_type)s ...")
> +container_tooltip = N_("Create or select %(container_type)s")
>  
> -    def run(self):
> -        help_text = _(help_text_template) % {"productName": productName}
> -        help_buffer = self.builder.get_object("help_text_buffer")
> -        help_buffer.set_text(_(help_text))
> -        self.window.run()
> +device_configuration_error_msg = N_("Device reconfiguration failed. Click for "
> +                                    "details.")
> +unrecoverable_error_msg = N_("Storage configuration reset due to unrecoverable "
> +                             "error. Click for details.")
>  
> -    def on_close(self, button):
> -        self.window.destroy()
> +partition_only_format_types = ["efi", "macefi", "prepboot", "biosboot",
> +                               "appleboot"]
>  
>  class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>      builderObjects = ["customStorageWindow", "containerStore",
> @@ -917,10 +373,6 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>          self._applyButton.set_sensitive(False)
>  
>      @property
> -    def translated_new_install_name(self):
> -        return _(new_install_name) % {"name" : productName, "version" : productVersion}
> -
> -    @property
>      def _current_page(self):
>          # The current page is really a function of the current selector.
>          # Whatever selector on the LHS is selected, the current page is the
> @@ -995,7 +447,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>          # If we've not yet run autopart, add an instance of CreateNewPage.  This
>          # ensures it's only added once.
>          if not self.new_devices:
> -            page = CreateNewPage(self.translated_new_install_name,
> +            page = CreateNewPage(translated_new_install_name(),
>                                   self.on_create_clicked,
>                                   self._change_autopart_type,
>                                   partitionsToReuse=bool(ui_roots))
> @@ -1014,7 +466,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>                  if device in self.bootLoaderDevices:
>                      mounts[device.format.type] = device
>  
> -            new_root = Root(mounts=mounts, swaps=swaps, name=self.translated_new_install_name)
> +            new_root = Root(mounts=mounts, swaps=swaps, name=translated_new_install_name())
>              ui_roots.insert(0, new_root)
>  
>          # Add in all the existing (or autopart-created) operating systems.
> @@ -1023,7 +475,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>              # Also, only include devices in an old page if the format is intact.
>              if not [d for d in root.swaps + root.mounts.values()
>                          if d in self._devices and d.disks and
> -                           (root.name == self.translated_new_install_name or d.format.exists)]:
> +                           (root.name == translated_new_install_name() or d.format.exists)]:
>                  continue
>  
>              page = Page(root.name)
> @@ -1031,7 +483,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>              for (mountpoint, device) in root.mounts.iteritems():
>                  if device not in self._devices or \
>                     not device.disks or \
> -                   (root.name != self.translated_new_install_name and not device.format.exists):
> +                   (root.name != translated_new_install_name() and not device.format.exists):
>                      continue
>  
>                  selector = page.addSelector(device, self.on_selector_clicked,
> @@ -1040,7 +492,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>  
>              for device in root.swaps:
>                  if device not in self._devices or \
> -                   (root.name != self.translated_new_install_name and not device.format.exists):
> +                   (root.name != translated_new_install_name() and not device.format.exists):
>                      continue
>  
>                  selector = page.addSelector(device, self.on_selector_clicked)
> @@ -1096,14 +548,14 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>  
>      def add_new_selector(self, device):
>          """ Add an entry for device to the new install Page. """
> -        page = self._accordion._find_by_title(self.translated_new_install_name).get_child()
> +        page = self._accordion._find_by_title(translated_new_install_name()).get_child()
>          devices = [device]
>          if not page.members:
>              # remove the CreateNewPage and replace it with a regular Page
> -            expander = self._accordion._find_by_title(self.translated_new_install_name)
> +            expander = self._accordion._find_by_title(translated_new_install_name())
>              expander.remove(expander.get_child())
>  
> -            page = Page(self.translated_new_install_name)
> +            page = Page(translated_new_install_name())
>              expander.add(page)
>  
>              # also pull in biosboot and prepboot that are on our boot disk
> @@ -1117,7 +569,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>      def _update_selectors(self):
>          """ Update all btrfs selectors' size properties. """
>          # we're only updating selectors in the new root. problem?
> -        page = self._accordion._find_by_title(self.translated_new_install_name).get_child()
> +        page = self._accordion._find_by_title(translated_new_install_name()).get_child()
>          for selector in page.members:
>              selectorFromDevice(selector._device, selector=selector)
>  
> @@ -1617,7 +1069,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>                      new_selector = None
>                      for (page, _selector) in self._accordion.allMembers:
>                          if _selector._device in (device, old_device):
> -                            if page.pageTitle == self.translated_new_install_name:
> +                            if page.pageTitle == translated_new_install_name():
>                                  new_selector = _selector
>                                  continue
>  
> @@ -2298,7 +1750,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>  
>          log.debug("removing device '%s' from page %s", device, root_name)
>  
> -        if root_name == self.translated_new_install_name:
> +        if root_name == translated_new_install_name():
>              if device.exists:
>                  # This is an existing device that was added to the new page.
>                  # All we want to do is revert any changes to the device and
> @@ -3012,64 +2464,3 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
>  
>      def on_value_changed(self, *args):
>          self._applyButton.set_sensitive(True)
> -
> -help_text_template = N_("""You have chosen to manually set up the filesystems for your new %(productName)s installation. Before you begin, you might want to take a minute to learn the lay of the land. Quite a bit has changed.
> -
> -The most important change is that creation of new filesystems has been streamlined. You no longer have to build complex devices like LVM logical volumes in stages (physical volume, then volume group, then logical volume) -- now you just create a logical volume and we'll handle the legwork of setting up the physical volumes and volume group to contain it. We'll also handle adjusting the volume group as you add, remove, and resize logical volumes so you don't have to worry about the mundane details.
> -
> -
> -Screen Layout
> -
> -The left-hand side of the screen shows the OS installations we were able to find on this computer. The new %(productName)s installation is at the top of the list. You can click on the names of the installations to see what filesystems they contain.
> -
> -Below the various installations and mountpoints on the left-hand side there are buttons to add a new filesystem, remove the selected filesystem, or configure the selected filesystem.
> -
> -The right-hand side of the screen is where you can customize the currently-selected mountpoint.
> -
> -On the bottom-left you will see a summary of the disks you have chosen to use for the installation. You can click on the blue text to see more detailed information about your selected disks.
> -
> -
> -How to create a new filesystem on a new device
> -
> -1. Click on the + button.
> -2. Enter the mountpoint and size. (Hint: Hover the mouse pointer over either of the text entry areas for help.)
> -3. Select the new mountpoint under "New %(productName)s Installation" on the left-hand side of the screen and customize it to suit your needs.
> -
> -
> -How to reformat a device/filesystem that already exists on your disk
> -
> -1. Select the filesystem from the left-hand side of the screen.
> -2. Click on the "Customize" expander in the mountpoint customization area on the right-hand side of the screen.
> -3. Activate the "Reformat" checkbutton, select a filesystem type and, if applicable, enter a mountpoint above in the "Mountpoint" text entry area.
> -4. Click on "Apply changes"
> -
> -
> -How to set a mountpoint for a filesystem that already exists on your disk
> -
> -1. Select the filesystem from the left-hand side of the screen.
> -2. Enter a mountpoint in the "Mountpoint" text entry area in the mountpoint customization area.
> -3. Click on "Apply changes"
> -
> -
> -How to remove a filesystem that already exists on your disk
> -
> -1. Select the filesystem you wish to remove on the left-hand side of the screen.
> -2. Click the - button.
> -
> -Hint: Removing a device that already exists on your disk from the "New %(productName)s Installation" does not remove it from the disk. It only resets that device to its original state. To remove a device that already exists on your disk, you must select it from under any of the other detected installations (or "Unknown") and hit the - button.
> -
> -
> -Tips and hints
> -
> -You can enter sizes for new filesystems that are greater than the total available free space. The installer will come as close as possible to the size you request.
> -
> -By default, new devices use any/all of your selected disks.
> -
> -You can change which disks a new device may be allocated from by clicking the configure button (the one with a tools graphic) while that device is selected.
> -
> -When adding a new mountpoint by clicking the + button, leave the size entry blank to make the new device use all available free space.
> -
> -When you remove the last device from a container device like an LVM volume group, we will automatically remove that container device to make room for new devices.
> -
> -When the last partition is removed from a disk, that disk may be reinitialized with a new partition table if we think there is a more appropriate type for that disk.
> -""")
> diff --git a/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade
> new file mode 100644
> index 0000000..605bd98
> --- /dev/null
> +++ b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.glade
> @@ -0,0 +1,1059 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!-- Generated with glade 3.16.0 on Thu Oct 17 10:51:34 2013 -->
> +<interface>
> +  <!-- interface-requires gtk+ 3.2 -->
> +  <!-- interface-requires AnacondaWidgets 1.0 -->
> +  <object class="GtkEntryBuffer" id="mountPointEntryBuffer"/>
> +  <object class="GtkListStore" id="mountPointStore">
> +    <columns>
> +      <!-- column-name path -->
> +      <column type="gchararray"/>
> +    </columns>
> +  </object>
> +  <object class="GtkEntryCompletion" id="mountPointCompletion">
> +    <property name="model">mountPointStore</property>
> +  </object>
> +  <object class="GtkListStore" id="raidLevelStore">
> +    <columns>
> +      <!-- column-name raidLevel -->
> +      <column type="gchararray"/>
> +      <!-- column-name validForLVM -->
> +      <column type="gboolean"/>
> +      <!-- column-name validForRAID -->
> +      <column type="gboolean"/>
> +      <!-- column-name validForBTRFS -->
> +      <column type="gboolean"/>
> +      <!-- column-name validForVG -->
> +      <column type="gboolean"/>
> +    </columns>
> +    <data>
> +      <row>
> +        <col id="0" translatable="yes">None</col>
> +        <col id="1">True</col>
> +        <col id="2">False</col>
> +        <col id="3">True</col>
> +        <col id="4">True</col>
> +      </row>
> +      <row>
> +        <col id="0" translatable="yes">RAID0 &lt;span foreground="grey"&gt;(Performance)&lt;/span&gt;</col>
> +        <col id="1">True</col>
> +        <col id="2">True</col>
> +        <col id="3">True</col>
> +        <col id="4">True</col>
> +      </row>
> +      <row>
> +        <col id="0" translatable="yes">RAID1 &lt;span foreground="grey"&gt;(Redundancy)&lt;/span&gt;</col>
> +        <col id="1">True</col>
> +        <col id="2">True</col>
> +        <col id="3">True</col>
> +        <col id="4">True</col>
> +      </row>
> +      <row>
> +        <col id="0" translatable="yes">RAID4 &lt;span foreground="grey"&gt;(Error Checking)&lt;/span&gt;</col>
> +        <col id="1">False</col>
> +        <col id="2">True</col>
> +        <col id="3">False</col>
> +        <col id="4">True</col>
> +      </row>
> +      <row>
> +        <col id="0" translatable="yes">RAID5 &lt;span foreground="grey"&gt;(Distributed Error Checking)&lt;/span&gt;</col>
> +        <col id="1">False</col>
> +        <col id="2">True</col>
> +        <col id="3">False</col>
> +        <col id="4">True</col>
> +      </row>
> +      <row>
> +        <col id="0" translatable="yes">RAID6 &lt;span foreground="grey"&gt;(Redundant Error Checking)&lt;/span&gt;</col>
> +        <col id="1">False</col>
> +        <col id="2">True</col>
> +        <col id="3">False</col>
> +        <col id="4">True</col>
> +      </row>
> +      <row>
> +        <col id="0" translatable="yes">RAID10 &lt;span foreground="grey"&gt;(Performance, Redundancy)&lt;/span&gt;</col>
> +        <col id="1">False</col>
> +        <col id="2">True</col>
> +        <col id="3">True</col>
> +        <col id="4">True</col>
> +      </row>
> +    </data>
> +  </object>
> +  <object class="GtkDialog" id="addDialog">
> +    <property name="can_focus">False</property>
> +    <property name="border_width">6</property>
> +    <property name="type_hint">dialog</property>
> +    <property name="decorated">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">2</property>
> +        <child internal-child="action_area">
> +          <object class="GtkButtonBox" id="dialog-action_area1">
> +            <property name="can_focus">False</property>
> +            <property name="margin_top">24</property>
> +            <property name="layout_style">end</property>
> +            <child>
> +              <object class="GtkButton" id="addCancelButton">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">_Cancel</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="halign">end</property>
> +                <property name="use_underline">True</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">0</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkButton" id="addConfirmButton">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">_Add mount point</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="halign">end</property>
> +                <property name="use_underline">True</property>
> +                <signal name="clicked" handler="on_add_confirm_clicked" swapped="no"/>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</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="GtkGrid" id="grid4">
> +            <property name="visible">True</property>
> +            <property name="can_focus">False</property>
> +            <property name="column_spacing">6</property>
> +            <child>
> +              <object class="GtkLabel" id="label7">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="margin_top">6</property>
> +                <property name="xalign">1</property>
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">_Desired Capacity:</property>
> +                <property name="use_underline">True</property>
> +                <property name="mnemonic_widget">addSizeEntry</property>
> +                <attributes>
> +                  <attribute name="weight" value="bold"/>
> +                </attributes>
> +              </object>
> +              <packing>
> +                <property name="left_attach">0</property>
> +                <property name="top_attach">4</property>
> +                <property name="width">1</property>
> +                <property name="height">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkLabel" id="label6">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="xalign">0</property>
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Add Dialog">Mount _Point:</property>
> +                <property name="use_underline">True</property>
> +                <property name="mnemonic_widget">addMountPointEntry</property>
> +                <attributes>
> +                  <attribute name="weight" value="bold"/>
> +                </attributes>
> +              </object>
> +              <packing>
> +                <property name="left_attach">0</property>
> +                <property name="top_attach">2</property>
> +                <property name="width">1</property>
> +                <property name="height">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkLabel" id="label8">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="margin_bottom">12</property>
> +                <property name="xalign">0</property>
> +                <property name="label" translatable="yes">ADD A NEW MOUNT POINT</property>
> +                <attributes>
> +                  <attribute name="weight" value="bold"/>
> +                  <attribute name="scale" value="1.2"/>
> +                </attributes>
> +              </object>
> +              <packing>
> +                <property name="left_attach">0</property>
> +                <property name="top_attach">0</property>
> +                <property name="width">2</property>
> +                <property name="height">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkLabel" id="label12">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="margin_bottom">12</property>
> +                <property name="label" translatable="yes">More customization options are available
> +after creating the mount point below.</property>
> +                <attributes>
> +                  <attribute name="font-desc" value="Cantarell 11"/>
> +                  <attribute name="scale" value="1"/>
> +                </attributes>
> +              </object>
> +              <packing>
> +                <property name="left_attach">0</property>
> +                <property name="top_attach">1</property>
> +                <property name="width">2</property>
> +                <property name="height">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkBox" id="addLabelWarningBox">
> +                <property name="can_focus">False</property>
> +                <property name="valign">start</property>
> +                <property name="spacing">6</property>
> +                <child>
> +                  <object class="GtkImage" id="image1">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="stock">gtk-dialog-warning</property>
> +                    <property name="icon_size">2</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">0</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkLabel" id="mountPointWarningLabel">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="label" translatable="yes">That mount point is already in
> +use.  Try something else?</property>
> +                    <attributes>
> +                      <attribute name="font-desc" value="Cantarell 10"/>
> +                      <attribute name="scale" value="1"/>
> +                      <attribute name="foreground" value="#ffff00000000"/>
> +                    </attributes>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">1</property>
> +                  </packing>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="left_attach">1</property>
> +                <property name="top_attach">3</property>
> +                <property name="width">1</property>
> +                <property name="height">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkEntry" id="addSizeEntry">
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="tooltip_text" translatable="yes">eg: "20 GB", "500mb" (minus the quotation marks)</property>
> +                <property name="invisible_char">●</property>
> +              </object>
> +              <packing>
> +                <property name="left_attach">1</property>
> +                <property name="top_attach">4</property>
> +                <property name="width">1</property>
> +                <property name="height">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkComboBoxText" id="addMountPointEntry">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="has_entry">True</property>
> +                <child internal-child="entry">
> +                  <object class="GtkEntry" id="comboboxtext-entry">
> +                    <property name="can_focus">True</property>
> +                    <property name="buffer">mountPointEntryBuffer</property>
> +                    <property name="completion">mountPointCompletion</property>
> +                  </object>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="left_attach">1</property>
> +                <property name="top_attach">2</property>
> +                <property name="width">1</property>
> +                <property name="height">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <placeholder/>
> +            </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">addCancelButton</action-widget>
> +      <action-widget response="1">addConfirmButton</action-widget>
> +    </action-widgets>
> +  </object>
> +  <object class="GtkDialog" id="confirmDeleteDialog">
> +    <property name="can_focus">False</property>
> +    <property name="border_width">6</property>
> +    <property name="type_hint">dialog</property>
> +    <property name="decorated">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">2</property>
> +        <child>
> +          <object class="GtkLabel" id="confirmLabel">
> +            <property name="visible">True</property>
> +            <property name="can_focus">False</property>
> +            <property name="xalign">0</property>
> +            <property name="yalign">0</property>
> +            <property name="wrap">True</property>
> +            <attributes>
> +              <attribute name="font-desc" value="Cantarell 11"/>
> +            </attributes>
> +          </object>
> +          <packing>
> +            <property name="expand">True</property>
> +            <property name="fill">True</property>
> +            <property name="position">0</property>
> +          </packing>
> +        </child>
> +        <child>
> +          <object class="GtkCheckButton" id="removeAllCheckbox">
> +            <property name="visible">True</property>
> +            <property name="can_focus">True</property>
> +            <property name="receives_default">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="position">1</property>
> +          </packing>
> +        </child>
> +        <child internal-child="action_area">
> +          <object class="GtkButtonBox" id="dialog-action_area2">
> +            <property name="can_focus">False</property>
> +            <property name="layout_style">end</property>
> +            <child>
> +              <object class="GtkButton" id="deleteCancelButton">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Confirm Delete Dialog">_Cancel</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="can_default">True</property>
> +                <property name="has_default">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_underline">True</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">0</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkButton" id="deleteConfirmButton">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Confirm Delete Dialog">_Delete It</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_underline">True</property>
> +                <signal name="clicked" handler="on_delete_confirm_clicked" swapped="no"/>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</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">2</property>
> +          </packing>
> +        </child>
> +      </object>
> +    </child>
> +    <action-widgets>
> +      <action-widget response="0">deleteCancelButton</action-widget>
> +      <action-widget response="1">deleteConfirmButton</action-widget>
> +    </action-widgets>
> +  </object>
> +  <object class="GtkTreeModelFilter" id="containerRaidStoreFiltered">
> +    <property name="child_model">raidLevelStore</property>
> +  </object>
> +  <object class="GtkDialog" id="container_dialog">
> +    <property name="can_focus">False</property>
> +    <property name="border_width">6</property>
> +    <property name="type_hint">dialog</property>
> +    <property name="decorated">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>
> +            <property name="layout_style">end</property>
> +            <child>
> +              <object class="GtkButton" id="container_cancel_button">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">_Cancel</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_underline">True</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">0</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkButton" id="container_save_button">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">_Save</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_underline">True</property>
> +                <signal name="clicked" handler="on_save_clicked" swapped="no"/>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</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="box10">
> +            <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="container_dialog_title_label">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="xalign">0</property>
> +                <property name="label" translatable="yes">CONFIGURE CONTAINER</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="container_dialog_label">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="label" translatable="yes">Please create a name for this container and select at least one disk below.</property>
> +                <property name="wrap">True</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkBox" id="box11">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="spacing">6</property>
> +                <child>
> +                  <object class="GtkLabel" id="nameLabel">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">_Name:</property>
> +                    <property name="use_underline">True</property>
> +                    <property name="mnemonic_widget">container_name_entry</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">0</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkEntry" id="container_name_entry">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">True</property>
> +                    <property name="invisible_char">●</property>
> +                    <accelerator key="n" signal="grab-focus" modifiers="GDK_MOD1_MASK"/>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">1</property>
> +                  </packing>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">2</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkScrolledWindow" id="scrolledwindow2">
> +                <property name="height_request">150</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="hexpand">True</property>
> +                <property name="vexpand">True</property>
> +                <property name="shadow_type">in</property>
> +                <child>
> +                  <object class="GtkViewport" id="viewport2">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <child>
> +                      <object class="GtkTreeView" id="container_disk_view">
> +                        <property name="visible">True</property>
> +                        <property name="can_focus">True</property>
> +                        <property name="model">disk_store</property>
> +                        <property name="search_column">0</property>
> +                        <child internal-child="selection">
> +                          <object class="GtkTreeSelection" id="treeview-selection3">
> +                            <property name="mode">multiple</property>
> +                          </object>
> +                        </child>
> +                        <child>
> +                          <object class="GtkTreeViewColumn" id="disk_column1">
> +                            <property name="spacing">6</property>
> +                            <property name="title" translatable="yes">Disk</property>
> +                            <property name="clickable">True</property>
> +                            <child>
> +                              <object class="GtkCellRendererText" id="disk_renderer1"/>
> +                              <attributes>
> +                                <attribute name="text">0</attribute>
> +                              </attributes>
> +                            </child>
> +                          </object>
> +                        </child>
> +                        <child>
> +                          <object class="GtkTreeViewColumn" id="capacity_column1">
> +                            <property name="spacing">6</property>
> +                            <property name="title" translatable="yes">Capacity</property>
> +                            <property name="clickable">True</property>
> +                            <child>
> +                              <object class="GtkCellRendererText" id="capacity_renderer1"/>
> +                              <attributes>
> +                                <attribute name="text">1</attribute>
> +                              </attributes>
> +                            </child>
> +                          </object>
> +                        </child>
> +                        <child>
> +                          <object class="GtkTreeViewColumn" id="free_column1">
> +                            <property name="spacing">6</property>
> +                            <property name="title" translatable="yes">Free</property>
> +                            <property name="clickable">True</property>
> +                            <child>
> +                              <object class="GtkCellRendererText" id="free_renderer1"/>
> +                              <attributes>
> +                                <attribute name="text">2</attribute>
> +                              </attributes>
> +                            </child>
> +                          </object>
> +                        </child>
> +                        <child>
> +                          <object class="GtkTreeViewColumn" id="id_column1">
> +                            <property name="spacing">6</property>
> +                            <property name="title" translatable="yes">ID</property>
> +                            <property name="clickable">True</property>
> +                            <child>
> +                              <object class="GtkCellRendererText" id="id_renderer1"/>
> +                              <attributes>
> +                                <attribute name="text">3</attribute>
> +                              </attributes>
> +                            </child>
> +                          </object>
> +                        </child>
> +                      </object>
> +                    </child>
> +                  </object>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">3</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkBox" id="box3">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="spacing">6</property>
> +                <child>
> +                  <object class="GtkLabel" id="containerRaidLevelLabel">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="xalign">0</property>
> +                    <property name="label" translatable="yes">RAID Level:</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">0</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkComboBox" id="containerRaidLevelCombo">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="model">containerRaidStoreFiltered</property>
> +                    <child>
> +                      <object class="GtkCellRendererText" id="containerRaidLevelRenderer"/>
> +                      <attributes>
> +                        <attribute name="markup">0</attribute>
> +                      </attributes>
> +                    </child>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">1</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkCheckButton" id="containerEncryptedCheckbox">
> +                    <property name="label" translatable="yes">Encrypt</property>
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">True</property>
> +                    <property name="receives_default">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">4</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkBox" id="containerErrorBox">
> +                <property name="can_focus">False</property>
> +                <property name="spacing">6</property>
> +                <child>
> +                  <object class="GtkImage" id="containerErrorImage">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="stock">gtk-dialog-warning</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">0</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkLabel" id="containerErrorLabel">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="label" translatable="yes">Please enter a valid name.</property>
> +                    <property name="wrap">True</property>
> +                    <attributes>
> +                      <attribute name="font-desc" value="Cantarell 10"/>
> +                      <attribute name="scale" value="1"/>
> +                      <attribute name="foreground" value="#ffff00000000"/>
> +                    </attributes>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">1</property>
> +                  </packing>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">5</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkBox" id="containerSizeBox">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="spacing">6</property>
> +                <child>
> +                  <object class="GtkLabel" id="containerSizeLabel">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <property name="label" translatable="yes" context="GUI|Custom Partitioning|Container Dialog">Si_ze policy:</property>
> +                    <property name="use_underline">True</property>
> +                    <property name="mnemonic_widget">containerSizeCombo</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">0</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkComboBoxText" id="containerSizeCombo">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <items>
> +                      <item translatable="yes">Automatic</item>
> +                      <item translatable="yes">As large as possible</item>
> +                      <item translatable="yes">Fixed</item>
> +                    </items>
> +                    <signal name="changed" handler="on_size_changed" swapped="no"/>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">1</property>
> +                  </packing>
> +                </child>
> +                <child>
> +                  <object class="GtkEntry" id="containerSizeEntry">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">True</property>
> +                    <property name="invisible_char">●</property>
> +                  </object>
> +                  <packing>
> +                    <property name="expand">False</property>
> +                    <property name="fill">True</property>
> +                    <property name="position">2</property>
> +                  </packing>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">6</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">container_cancel_button</action-widget>
> +      <action-widget response="1">container_save_button</action-widget>
> +    </action-widgets>
> +  </object>
> +  <object class="GtkListStore" id="disk_store">
> +    <columns>
> +      <!-- column-name disk_col -->
> +      <column type="gchararray"/>
> +      <!-- column-name capacity_col -->
> +      <column type="gchararray"/>
> +      <!-- column-name free_col -->
> +      <column type="gchararray"/>
> +      <!-- column-name serial_col -->
> +      <column type="gchararray"/>
> +      <!-- column-name id_col -->
> +      <column type="gint"/>
> +    </columns>
> +  </object>
> +  <object class="GtkDialog" id="disks_dialog">
> +    <property name="width_request">400</property>
> +    <property name="height_request">200</property>
> +    <property name="can_focus">False</property>
> +    <property name="border_width">6</property>
> +    <property name="type_hint">dialog</property>
> +    <property name="decorated">False</property>
> +    <child internal-child="vbox">
> +      <object class="GtkBox" id="dialog-vbox4">
> +        <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_area4">
> +            <property name="can_focus">False</property>
> +            <property name="layout_style">end</property>
> +            <child>
> +              <object class="GtkButton" id="cancel_button">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Configure Dialog">_Cancel</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</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="select_button">
> +                <property name="label" translatable="yes" context="GUI|Custom Partitioning|Configure Dialog">_Select</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_underline">True</property>
> +                <signal name="clicked" handler="on_select_clicked" swapped="no"/>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</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="box1">
> +            <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="disk_selection_title_label">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="xalign">0</property>
> +                <property name="label" translatable="yes">CONFIGURE MOUNT POINT</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="label11">
> +                <property name="visible">True</property>
> +                <property name="can_focus">False</property>
> +                <property name="label" translatable="yes">Select one or more disks this device may reside on.</property>
> +                <property name="wrap">True</property>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">1</property>
> +              </packing>
> +            </child>
> +            <child>
> +              <object class="GtkScrolledWindow" id="scrolledwindow1">
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="hexpand">True</property>
> +                <property name="vexpand">True</property>
> +                <property name="shadow_type">in</property>
> +                <child>
> +                  <object class="GtkViewport" id="viewport1">
> +                    <property name="visible">True</property>
> +                    <property name="can_focus">False</property>
> +                    <child>
> +                      <object class="GtkTreeView" id="disk_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_view_selection">
> +                            <property name="mode">multiple</property>
> +                          </object>
> +                        </child>
> +                        <child>
> +                          <object class="GtkTreeViewColumn" id="disk_column">
> +                            <property name="spacing">6</property>
> +                            <property name="title" translatable="yes">Disk</property>
> +                            <property name="clickable">True</property>
> +                            <child>
> +                              <object class="GtkCellRendererText" id="disk_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>
> +                            <property name="clickable">True</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>
> +                            <property name="clickable">True</property>
> +                            <child>
> +                              <object class="GtkCellRendererText" id="id_renderer"/>
> +                              <attributes>
> +                                <attribute name="text">3</attribute>
> +                              </attributes>
> +                            </child>
> +                          </object>
> +                        </child>
> +                      </object>
> +                    </child>
> +                  </object>
> +                </child>
> +              </object>
> +              <packing>
> +                <property name="expand">False</property>
> +                <property name="fill">True</property>
> +                <property name="position">2</property>
> +              </packing>
> +            </child>
> +          </object>
> +          <packing>
> +            <property name="expand">False</property>
> +            <property name="fill">True</property>
> +            <property name="position">1</property>
> +          </packing>
> +        </child>
> +      </object>
> +    </child>
> +    <action-widgets>
> +      <action-widget response="0">cancel_button</action-widget>
> +      <action-widget response="1">select_button</action-widget>
> +    </action-widgets>
> +  </object>
> +  <object class="GtkTextBuffer" id="help_text_buffer"/>
> +  <object class="GtkDialog" id="help_dialog">
> +    <property name="width_request">600</property>
> +    <property name="height_request">400</property>
> +    <property name="can_focus">False</property>
> +    <property name="border_width">6</property>
> +    <property name="title" translatable="yes">Help</property>
> +    <property name="modal">True</property>
> +    <property name="window_position">center-on-parent</property>
> +    <property name="type_hint">dialog</property>
> +    <signal name="close" handler="on_close" swapped="no"/>
> +    <child internal-child="vbox">
> +      <object class="GtkBox" id="dialog-vbox6">
> +        <property name="can_focus">False</property>
> +        <property name="orientation">vertical</property>
> +        <property name="spacing">2</property>
> +        <child internal-child="action_area">
> +          <object class="GtkButtonBox" id="dialog-action_area6">
> +            <property name="can_focus">False</property>
> +            <property name="layout_style">end</property>
> +            <child>
> +              <object class="GtkButton" id="help_close_button">
> +                <property name="label">gtk-close</property>
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="receives_default">True</property>
> +                <property name="use_stock">True</property>
> +                <signal name="clicked" handler="on_close" 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="GtkScrolledWindow" id="scrolledwindow3">
> +            <property name="visible">True</property>
> +            <property name="can_focus">True</property>
> +            <property name="shadow_type">in</property>
> +            <child>
> +              <object class="GtkTextView" id="help_text_view">
> +                <property name="visible">True</property>
> +                <property name="can_focus">True</property>
> +                <property name="editable">False</property>
> +                <property name="wrap_mode">word</property>
> +                <property name="cursor_visible">False</property>
> +                <property name="buffer">help_text_buffer</property>
> +              </object>
> +            </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">help_close_button</action-widget>
> +    </action-widgets>
> +  </object>
> +</interface>
> diff --git a/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py
> new file mode 100644
> index 0000000..f1886b6
> --- /dev/null
> +++ b/pyanaconda/ui/gui/spokes/lib/custom_storage_helpers.py
> @@ -0,0 +1,658 @@
> +# vim: set fileencoding=utf-8
> +#
> +# Copyright (C) 2012-2014  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 at redhat.com>
> +#                    David Lehman <dlehman at redhat.com>
> +#                    Vratislav Podzimek <vpodzime at redhat.com>
> +#
> +
> +"""Helper functions and classes for custom partitioning."""
> +
> +
> +from contextlib import contextmanager
> +import re
> +import locale
> +
> +from pyanaconda.product import productName, productVersion
> +from pyanaconda.iutil import lowerASCII
> +from pyanaconda.ui.gui import GUIObject
> +from pyanaconda.ui.gui.utils import fancy_set_sensitive, really_hide, really_show
> +from pyanaconda.i18n import _, N_, C_
> +
> +from blivet.size import Size
> +from blivet.errors import SizeParamsError
> +from blivet.platform import platform
> +from blivet.formats import getFormat
> +from blivet.devicefactory import SIZE_POLICY_AUTO
> +from blivet.devicefactory import SIZE_POLICY_MAX
> +from blivet.devicefactory import DEVICE_TYPE_LVM
> +from blivet.devicefactory import DEVICE_TYPE_BTRFS
> +from blivet.devicefactory import DEVICE_TYPE_LVM_THINP
> +from blivet.devicelibs import mdraid
> +
> +import logging
> +log = logging.getLogger("anaconda")
> +
> +label_format_invalid_msg = N_("Unacceptable label format for filesystem.")
> +label_application_unavailable_msg = N_("Can not set label on filesystem.")
> +label_resetting_forbidden_msg = N_("Can not relabel already existing filesystem.")
> +
> +empty_mountpoint_msg = N_("Please enter a valid mountpoint.")
> +invalid_mountpoint_msg = N_("That mount point is invalid. Try something else?")
> +mountpoint_in_use_msg = N_("That mount point is already in use. Try something else?")
> +
> +raid_level_not_enough_disks_msg = N_("The RAID level you have selected (%(level)s) "
> +                                     "requires more disks (%(min)d) than you "
> +                                     "currently have selected (%(count)d).")
> +empty_name_msg = N_("Please enter a valid name.")
> +
> +LABEL_OK = 0
> +LABEL_FORMAT_INVALID = 1
> +LABEL_APPLICATION_UNAVAILABLE = 2
> +LABEL_RESETTING_FORBIDDEN = 3
> +
> +label_validation_msgs = {
> +    LABEL_OK: "",
> +    LABEL_FORMAT_INVALID: label_format_invalid_msg,
> +    LABEL_APPLICATION_UNAVAILABLE: label_application_unavailable_msg,
> +    LABEL_RESETTING_FORBIDDEN: label_resetting_forbidden_msg}
> +
> +MOUNTPOINT_OK = 0
> +MOUNTPOINT_INVALID = 1
> +MOUNTPOINT_IN_USE = 2
> +MOUNTPOINT_EMPTY = 3
> +
> +mountpoint_validation_msgs = {MOUNTPOINT_OK: "",
> +                              MOUNTPOINT_INVALID: invalid_mountpoint_msg,
> +                              MOUNTPOINT_IN_USE: mountpoint_in_use_msg,
> +                              MOUNTPOINT_EMPTY: empty_mountpoint_msg}
> +
> +new_install_name = N_("New %(name)s %(version)s Installation")
> +container_dialog_title = N_("CONFIGURE %(container_type)s")
> +container_dialog_text = N_("Please create a name for this %(container_type)s "
> +                           "and select at least one disk below.")
> +lvm_container_name = N_("Volume Group")
> +btrfs_container_name = N_("Volume")
> +
> +container_type_names = {DEVICE_TYPE_LVM: lvm_container_name,
> +                        DEVICE_TYPE_LVM_THINP: lvm_container_name,
> +                        DEVICE_TYPE_BTRFS: btrfs_container_name}
> +
> +def translated_new_install_name():
> +    return _(new_install_name) % {"name" : productName, "version" : productVersion}
> +
> +def size_from_entry(entry):
> +    size_text = entry.get_text().decode("utf-8").strip()
> +
> +    # Nothing to parse
> +    if not size_text:
> +        return None
> +
> +    # if no unit was specified, default to MiB. Assume that a string
> +    # ending with anything other than a digit has a unit suffix
> +    if re.search(r'[\d.%s]$' % locale.nl_langinfo(locale.RADIXCHAR), size_text):
> +        size_text += "MiB"
> +
> +    try:
> +        size = Size(spec=size_text)
> +    except (SizeParamsError, ValueError):
> +        return None
> +    else:
> +        # Minimium size for ui-created partitions is 1MiB.
> +        if size.convertTo(spec="MiB") < 1:
> +            size = Size(spec="1 MiB")
> +
> +    return size
> +
> +class UIStorageFilter(logging.Filter):
> +    def filter(self, record):
> +        record.name = "storage.ui"
> +        return True
> +
> + at contextmanager
> +def ui_storage_logger():
> +    storage_log = logging.getLogger("blivet")
> +    f = UIStorageFilter()
> +    storage_log.addFilter(f)
> +    yield
> +    storage_log.removeFilter(f)
> +
> +def populate_mountpoint_store(store, used_mountpoints):
> +    # sure, add whatever you want to this list. this is just a start.
> +    paths = ["/", "/boot", "/home", "/var"] + \
> +            platform.bootStage1ConstraintDict["mountpoints"]
> +
> +    # Sort the list now so all the real mountpoints go to the front, then
> +    # add all the pseudo mountpoints we have.
> +    paths.sort()
> +    paths += ["swap"]
> +
> +    for fmt in ["appleboot", "biosboot", "prepboot"]:
> +        if getFormat(fmt).supported:
> +            paths += [fmt]
> +
> +    for path in paths:
> +        if path not in used_mountpoints:
> +            store.append([path])
> +
> +def validate_label(label, fmt):
> +    """Returns a code indicating either that the given label can be set for
> +       this filesystem or the reason why it can not.
> +
> +       In the case where the format can not assign a label, the empty string
> +       stands for accept the default, but in the case where the format can
> +       assign a label the empty string represents itself.
> +
> +       :param str label: The label
> +       :param DeviceFormat fmt: The device format to label
> +
> +    """
> +    if fmt.exists:
> +        return LABEL_RESETTING_FORBIDDEN
> +    if not fmt.labeling():
> +        if label == "":
> +            return LABEL_OK
> +        else:
> +            return LABEL_APPLICATION_UNAVAILABLE
> +    if not fmt.labelFormatOK(label):
> +        return LABEL_INVALID
> +    return LABEL_OK
> +
> +def validate_mountpoint(mountpoint, used_mountpoints, strict=True):
> +    if strict:
> +        fake_mountpoints = []
> +    else:
> +        fake_mountpoints = ["swap", "biosboot", "prepboot"]
> +
> +    valid = MOUNTPOINT_OK
> +    if mountpoint in used_mountpoints:
> +        valid = MOUNTPOINT_IN_USE
> +    elif not mountpoint:
> +        valid = MOUNTPOINT_EMPTY
> +    elif mountpoint.startswith("/dev") or mountpoint.startswith("/proc") or \
> +         mountpoint.startswith("/sys"):
> +        valid = MOUNTPOINT_INVALID
> +    elif (lowerASCII(mountpoint) not in fake_mountpoints and
> +          ((len(mountpoint) > 1 and mountpoint.endswith("/")) or
> +           not mountpoint.startswith("/") or
> +           " " in mountpoint or
> +           re.search(r'/\.*/', mountpoint) or
> +           re.search(r'/\.+$', mountpoint))):
> +        # - does not end with '/' unless mountpoint _is_ '/'
> +        # - starts with '/' except for "swap", &c
> +        # - does not contain spaces
> +        # - does not contain pairs of '/' enclosing zero or more '.'
> +        # - does not end with '/' followed by one or more '.'
> +        valid = MOUNTPOINT_INVALID
> +
> +    return valid
> +
> +def selectedRaidLevel(raidLevelCombo):
> +    """Interpret the selection of a RAID level combo box."""
> +    if not raidLevelCombo.get_property("visible"):
> +        # the combo is hidden when raid level isn't applicable
> +        return None
> +
> +    itr = raidLevelCombo.get_active_iter()
> +    store = raidLevelCombo.get_model()
> +
> +    if not itr:
> +        return
> +
> +    selected_level_string = store[itr][0]   # eg: "RAID1 (Redundancy)"
> +    level = selected_level_string.split()[0]    # -> "RAID1"
> +
> +    # The RAID level strings are not translated, but the "None" string in
> +    # the container dialog is. Transformations in relation to "None" need
> +    # to happen within the locale settings, but transformations in
> +    # relation to "RAID* ..." need to happen only within ASCII. For example,
> +    # "RAID1".lower() in Turkish would become "raıd1", which is not what
> +    # we want.
> +    levelLocale = level.lower()
> +    levelASCII = lowerASCII(level)
> +
> +    if levelASCII == "none" or levelLocale == _("None").lower():
> +        return None
> +
> +    return levelASCII
> +
> +class AddDialog(GUIObject):
> +    builderObjects = ["addDialog", "mountPointStore", "mountPointCompletion", "mountPointEntryBuffer"]
> +    mainWidgetName = "addDialog"
> +    uiFile = "spokes/lib/custom_storage_helpers.glade"
> +
> +    def __init__(self, *args, **kwargs):
> +        self.mountpoints = kwargs.pop("mountpoints", [])
> +        GUIObject.__init__(self, *args, **kwargs)
> +        self.size = Size(bytes=0)
> +        self.mountpoint = ""
> +        self._error = False
> +
> +        store = self.builder.get_object("mountPointStore")
> +        populate_mountpoint_store(store, self.mountpoints)
> +        self.builder.get_object("addMountPointEntry").set_model(store)
> +
> +        completion = self.builder.get_object("mountPointCompletion")
> +        completion.set_text_column(0)
> +        completion.set_popup_completion(True)
> +
> +        self._warningLabel = self.builder.get_object("mountPointWarningLabel")
> +
> +    def on_add_confirm_clicked(self, button, *args):
> +        self.mountpoint = self.builder.get_object("addMountPointEntry").get_active_text()
> +        self._error = validate_mountpoint(self.mountpoint, self.mountpoints,
> +                                          strict=False)
> +        self._warningLabel.set_text(_(mountpoint_validation_msgs[self._error]))
> +        self.window.show_all()
> +        if self._error:
> +            return
> +
> +        self.size = size_from_entry(self.builder.get_object("addSizeEntry"))
> +        self.window.destroy()
> +
> +    def refresh(self):
> +        GUIObject.refresh(self)
> +        self._warningLabel.set_text("")
> +
> +    def run(self):
> +        while True:
> +            self._error = None
> +            rc = self.window.run()
> +            if not self._error:
> +                return rc
> +
> +class ConfirmDeleteDialog(GUIObject):
> +    builderObjects = ["confirmDeleteDialog"]
> +    mainWidgetName = "confirmDeleteDialog"
> +    uiFile = "spokes/lib/custom_storage_helpers.glade"
> +
> +    def __init__(self, *args, **kwargs):
> +        GUIObject.__init__(self, *args, **kwargs)
> +        self._removeAll = self.builder.get_object("removeAllCheckbox")
> +
> +    @property
> +    def deleteAll(self):
> +        return self._removeAll.get_active()
> +
> +    def on_delete_confirm_clicked(self, button, *args):
> +        self.window.destroy()
> +
> +    # pylint: disable=W0221
> +    def refresh(self, mountpoint, device, rootName, subvols=False):
> +        GUIObject.refresh(self)
> +        label = self.builder.get_object("confirmLabel")
> +
> +        if rootName and "_" in rootName:
> +            rootName = rootName.replace("_", "__")
> +        self._removeAll.set_label(
> +                C_("GUI|Custom Partitioning|Confirm Delete Dialog",
> +                    "Delete _all other filesystems in the %s root as well.")
> +                % rootName)
> +        self._removeAll.set_sensitive(rootName is not None)
> +
> +        if mountpoint:
> +            txt = "%s (%s)" % (mountpoint, device)
> +        else:
> +            txt = device
> +
> +        if not subvols:
> +            label_text = _("Are you sure you want to delete all of the data on %s?") % txt
> +        else:
> +            label_text = _("Are you sure you want to delete all of the data on %s, including subvolumes and/or snapshots?") % txt
> +
> +        label.set_text(label_text)
> +
> +    def run(self):
> +        return self.window.run()
> +
> +class DisksDialog(GUIObject):
> +    builderObjects = ["disks_dialog", "disk_store", "disk_view"]
> +    mainWidgetName = "disks_dialog"
> +    uiFile = "spokes/lib/custom_storage_helpers.glade"
> +
> +    def __init__(self, *args, **kwargs):
> +        self._disks = kwargs.pop("disks")
> +        free = kwargs.pop("free")
> +        self.selected = kwargs.pop("selected")[:]
> +        GUIObject.__init__(self, *args, **kwargs)
> +        self._store = self.builder.get_object("disk_store")
> +        # populate the store
> +        for disk in self._disks:
> +            self._store.append([disk.description,
> +                                str(disk.size),
> +                                str(free[disk.name][0]),
> +                                disk.serial,
> +                                disk.id])
> +
> +        treeview = self.builder.get_object("disk_view")
> +        model = treeview.get_model()
> +        itr = model.get_iter_first()
> +        selected_ids = [d.id for d in self.selected]
> +        selection = treeview.get_selection()
> +        while itr:
> +            disk_id = model.get_value(itr, 4)
> +            if disk_id in selected_ids:
> +                selection.select_iter(itr)
> +
> +            itr = model.iter_next(itr)
> +
> +    def on_cancel_clicked(self, button):
> +        self.window.destroy()
> +
> +    def _get_disk_by_id(self, disk_id):
> +        for disk in self._disks:
> +            if disk.id == disk_id:
> +                return disk
> +
> +    def on_select_clicked(self, button):
> +        treeview = self.builder.get_object("disk_view")
> +        model, paths = treeview.get_selection().get_selected_rows()
> +        self.selected = []
> +        for path in paths:
> +            itr = model.get_iter(path)
> +            disk_id = model.get_value(itr, 4)
> +            self.selected.append(self._get_disk_by_id(disk_id))
> +
> +        self.window.destroy()
> +
> +    def run(self):
> +        return self.window.run()
> +
> +class ContainerDialog(GUIObject):
> +    builderObjects = ["container_dialog", "disk_store", "container_disk_view",
> +                      "containerRaidStoreFiltered", "containerRaidLevelLabel",
> +                      "containerRaidLevelCombo", "raidLevelStore",
> +                      "containerSizeCombo", "containerSizeEntry",
> +                      "containerSizeLabel", "containerEncryptedCheckbox"]
> +    mainWidgetName = "container_dialog"
> +    uiFile = "spokes/lib/custom_storage_helpers.glade"
> +
> +    def __init__(self, *args, **kwargs):
> +        # these are all absolutely required. not getting them is fatal.
> +        self._disks = kwargs.pop("disks")
> +        free = kwargs.pop("free")
> +        self.selected = kwargs.pop("selected")[:]
> +        self.name = kwargs.pop("name") or "" # make sure it's a string
> +        self.device_type = kwargs.pop("device_type")
> +
> +        # these are less critical
> +        self.raid_level = kwargs.pop("raid_level", None) or None # not ""
> +        self.encrypted = kwargs.pop("encrypted", False)
> +        self.exists = kwargs.pop("exists", False)
> +
> +        self.size_policy = kwargs.pop("size_policy", SIZE_POLICY_AUTO)
> +        self.size = kwargs.pop("size", Size(bytes=0))
> +
> +        self._error = None
> +        GUIObject.__init__(self, *args, **kwargs)
> +
> +        self._grabObjects()
> +
> +        # set up the dialog labels with device-type-specific text
> +        if self.device_type in container_type_names:
> +            container_type = _(container_type_names[self.device_type])
> +        else:
> +            container_type = _("container")
> +        title_text = _(container_dialog_title) % {"container_type": container_type.upper()}
> +        self._title_label.set_text(title_text)
> +
> +        dialog_text = _(container_dialog_text) % {"container_type": container_type.lower()}
> +        self._dialog_label.set_text(dialog_text)
> +
> +        # populate the dialog widgets
> +        self._name_entry.set_text(self.name)
> +
> +        # populate the store
> +        for disk in self._disks:
> +            self._store.append([disk.description,
> +                                str(disk.size),
> +                                str(free[disk.name][0]),
> +                                disk.serial,
> +                                disk.id])
> +
> +        model = self._treeview.get_model()
> +        itr = model.get_iter_first()
> +
> +        selected_ids = [d.id for d in self.selected]
> +        selection = self._treeview.get_selection()
> +        while itr:
> +            disk_id = model.get_value(itr, 4)
> +            if disk_id in selected_ids:
> +                selection.select_iter(itr)
> +
> +            itr = model.iter_next(itr)
> +
> +        # XXX how will this be related to the device encryption setting?
> +        self._encryptCheckbutton.set_active(self.encrypted)
> +
> +        # set up the raid level combo
> +        # XXX how will this be related to the device raid level setting?
> +        self._raidStoreFilter.set_visible_func(self._raid_level_visible)
> +        self._raidStoreFilter.refilter()
> +        self._populate_raid()
> +
> +        self._sizeEntry.set_text(self.size.humanReadable(max_places=None))
> +        if self.size_policy == SIZE_POLICY_AUTO:
> +            self._sizeCombo.set_active(0)
> +        elif self.size_policy == SIZE_POLICY_MAX:
> +            self._sizeCombo.set_active(1)
> +        else:
> +            self._sizeCombo.set_active(2)
> +
> +        if self.exists:
> +            fancy_set_sensitive(self._name_entry, False)
> +            self._treeview.set_sensitive(False)
> +            fancy_set_sensitive(self._encryptCheckbutton, False)
> +            fancy_set_sensitive(self._sizeCombo, False)
> +            self._sizeEntry.set_sensitive(False)
> +
> +    def _grabObjects(self):
> +        self._title_label = self.builder.get_object("container_dialog_title_label")
> +        self._dialog_label = self.builder.get_object("container_dialog_label")
> +        self._error_label = self.builder.get_object("containerErrorLabel")
> +
> +        self._name_entry = self.builder.get_object("container_name_entry")
> +
> +        self._encryptCheckbutton = self.builder.get_object("containerEncryptedCheckbox")
> +        self._raidStoreFilter = self.builder.get_object("containerRaidStoreFiltered")
> +
> +        self._store = self.builder.get_object("disk_store")
> +        self._treeview = self.builder.get_object("container_disk_view")
> +
> +        self._sizeCombo = self.builder.get_object("containerSizeCombo")
> +        self._sizeEntry = self.builder.get_object("containerSizeEntry")
> +
> +        self._raidLevelCombo = self.builder.get_object("containerRaidLevelCombo")
> +        self._raidLevelLabel = self.builder.get_object("containerRaidLevelLabel")
> +
> +    def _get_disk_by_id(self, disk_id):
> +        for disk in self._disks:
> +            if disk.id == disk_id:
> +                return disk
> +
> +    def on_save_clicked(self, button):
> +        if self.exists:
> +            self.window.destroy()
> +            return
> +
> +        # If no name was entered, quit the dialog as if they did nothing.
> +        name = self._name_entry.get_text().strip()
> +        if not name:
> +            self._error = _(empty_name_msg)
> +            self._error_label.set_text(self._error)
> +            self.window.show_all()
> +            return
> +
> +        model, paths = self._treeview.get_selection().get_selected_rows()
> +
> +        raid_level = selectedRaidLevel(self._raidLevelCombo)
> +        if raid_level:
> +            md_level = mdraid.getRaidLevel(raid_level)
> +            min_disks = md_level.min_members
> +            if len(paths) < min_disks:
> +                self._error = (_(raid_level_not_enough_disks_msg)
> +                                 % {"level" : md_level,
> +                                     "min" : min_disks,
> +                                     "count" : len(paths)})
> +                self._error_label.set_text(self._error)
> +                self.window.show_all()
> +                return
> +
> +        idx = self._sizeCombo.get_active()
> +        if idx == 0:
> +            size = SIZE_POLICY_AUTO
> +        elif idx == 1:
> +            size = SIZE_POLICY_MAX
> +        elif idx == 2:
> +            size = size_from_entry(self._sizeEntry)
> +            if size is None:
> +                size = SIZE_POLICY_MAX
> +
> +        # now save the changes
> +
> +        self.selected = []
> +        for path in paths:
> +            itr = model.get_iter(path)
> +            disk_id = model.get_value(itr, 4)
> +            self.selected.append(self._get_disk_by_id(disk_id))
> +
> +        self.name = name
> +        self.raid_level = raid_level
> +        self.encrypted = self._encryptCheckbutton.get_active()
> +        self.size_policy = size
> +
> +        self._error_label.set_text("")
> +        self.window.destroy()
> +
> +    def run(self):
> +        while True:
> +            self._error = None
> +            rc = self.window.run()
> +            if not self._error:
> +                return rc
> +
> +    def on_size_changed(self, combo):
> +        active_index = combo.get_active()
> +        if active_index == 0:
> +            self._sizeEntry.set_sensitive(False)
> +        elif active_index == 1:
> +            self._sizeEntry.set_sensitive(False)
> +        else:
> +            self._sizeEntry.set_sensitive(True)
> +
> +    def _raid_level_visible(self, model, itr, user_data):
> +        # This is weird because for lvm's container-wide raid we use md.
> +        if self.device_type in (DEVICE_TYPE_LVM, DEVICE_TYPE_LVM_THINP):
> +            return model[itr][4]
> +        elif self.device_type == DEVICE_TYPE_BTRFS:
> +            return model[itr][3]
> +
> +    def _populate_raid(self):
> +        """ Set up the raid-specific portion of the device details. """
> +        if self.device_type not in [DEVICE_TYPE_LVM, DEVICE_TYPE_BTRFS, DEVICE_TYPE_LVM_THINP]:
> +            map(really_hide, [self._raidLevelLabel, self._raidLevelCombo])
> +            return
> +
> +        raid_level = self.raid_level
> +        if not raid_level or raid_level == "single":
> +            raid_level = _("None")
> +
> +        # Set a default RAID level in the combo.
> +        for (i, row) in enumerate(self._raidLevelCombo.get_model()):
> +            log.debug("container dialog: raid level %s", row[0])
> +            if row[0].upper().startswith(raid_level.upper()):
> +                self._raidLevelCombo.set_active(i)
> +                break
> +
> +        map(really_show, [self._raidLevelLabel, self._raidLevelCombo])
> +        fancy_set_sensitive(self._raidLevelCombo, not self.exists)
> +
> +class HelpDialog(GUIObject):
> +    builderObjects = ["help_dialog", "help_text_view", "help_text_buffer"]
> +    mainWidgetName = "help_dialog"
> +    uiFile = "spokes/lib/custom_storage_helpers.glade"
> +
> +    def run(self):
> +        help_text = _(help_text_template) % {"productName": productName}
> +        help_buffer = self.builder.get_object("help_text_buffer")
> +        help_buffer.set_text(_(help_text))
> +        self.window.run()
> +
> +    def on_close(self, button):
> +        self.window.destroy()
> +
> +help_text_template = N_("""You have chosen to manually set up the filesystems for your new %(productName)s installation. Before you begin, you might want to take a minute to learn the lay of the land. Quite a bit has changed.
> +
> +The most important change is that creation of new filesystems has been streamlined. You no longer have to build complex devices like LVM logical volumes in stages (physical volume, then volume group, then logical volume) -- now you just create a logical volume and we'll handle the legwork of setting up the physical volumes and volume group to contain it. We'll also handle adjusting the volume group as you add, remove, and resize logical volumes so you don't have to worry about the mundane details.
> +
> +
> +Screen Layout
> +
> +The left-hand side of the screen shows the OS installations we were able to find on this computer. The new %(productName)s installation is at the top of the list. You can click on the names of the installations to see what filesystems they contain.
> +
> +Below the various installations and mountpoints on the left-hand side there are buttons to add a new filesystem, remove the selected filesystem, or configure the selected filesystem.
> +
> +The right-hand side of the screen is where you can customize the currently-selected mountpoint.
> +
> +On the bottom-left you will see a summary of the disks you have chosen to use for the installation. You can click on the blue text to see more detailed information about your selected disks.
> +
> +
> +How to create a new filesystem on a new device
> +
> +1. Click on the + button.
> +2. Enter the mountpoint and size. (Hint: Hover the mouse pointer over either of the text entry areas for help.)
> +3. Select the new mountpoint under "New %(productName)s Installation" on the left-hand side of the screen and customize it to suit your needs.
> +
> +
> +How to reformat a device/filesystem that already exists on your disk
> +
> +1. Select the filesystem from the left-hand side of the screen.
> +2. Click on the "Customize" expander in the mountpoint customization area on the right-hand side of the screen.
> +3. Activate the "Reformat" checkbutton, select a filesystem type and, if applicable, enter a mountpoint above in the "Mountpoint" text entry area.
> +4. Click on "Apply changes"
> +
> +
> +How to set a mountpoint for a filesystem that already exists on your disk
> +
> +1. Select the filesystem from the left-hand side of the screen.
> +2. Enter a mountpoint in the "Mountpoint" text entry area in the mountpoint customization area.
> +3. Click on "Apply changes"
> +
> +
> +How to remove a filesystem that already exists on your disk
> +
> +1. Select the filesystem you wish to remove on the left-hand side of the screen.
> +2. Click the - button.
> +
> +Hint: Removing a device that already exists on your disk from the "New %(productName)s Installation" does not remove it from the disk. It only resets that device to its original state. To remove a device that already exists on your disk, you must select it from under any of the other detected installations (or "Unknown") and hit the - button.
> +
> +
> +Tips and hints
> +
> +You can enter sizes for new filesystems that are greater than the total available free space. The installer will come as close as possible to the size you request.
> +
> +By default, new devices use any/all of your selected disks.
> +
> +You can change which disks a new device may be allocated from by clicking the configure button (the one with a tools graphic) while that device is selected.
> +
> +When adding a new mountpoint by clicking the + button, leave the size entry blank to make the new device use all available free space.
> +
> +When you remove the last device from a container device like an LVM volume group, we will automatically remove that container device to make room for new devices.
> +
> +When the last partition is removed from a disk, that disk may be reinitialized with a new partition table if we think there is a more appropriate type for that disk.
> +""")
Looks like a step in the right direction, thanks! ACK from me. :)



More information about the anaconda-patches mailing list