Hello list
Been working on a Custom Partitioning workflow. Based on https://fedoraproject.org/wiki/Design/AnacondaStorageUI/MiscMockupIdeas
In this patchset there are two big changes:
1. In the LV edit the user no longer has to go through the intermediary step of the Volume Group.
2. There are only 4 buttons in the main customization window. The new "Create" button replaces the LVM, RAID and New buttons. It will automatically search for the valid options (So the user wont try to create an lvm when there are no PV present.)
For 2. There are also some new information strings. The RAID info is taken from the old messages so no translation would be needed. There is an LVM message. Its long and I would like to see it a little shorter (anyone want to give it a try).
Caveats: 1. LVM Logical Volume does not work yet. We need to relate it to a VG someway, not sure how to do that yet. The LV can still be created through the VG interface.
2. Definitely thinking of changing hasFreeHardDrive for something in storage.__init__.
3. This adds some click to some parts of the install but we add consistency and context info. We also check stuff before errors happen, so we don't need some error messages (Like trying to create partition when there is no free space)
Review appreciated.
regards.
Joel Andres Granados Brno, Czech Republic, Red Hat.
* gui.py (__init__): Split the arguments for __init__ into three lines. Also split the line that creates the pygtk dialog into two. --- gui.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/gui.py b/gui.py index 0a4ca3b..682f1c8 100755 --- a/gui.py +++ b/gui.py @@ -858,7 +858,10 @@ class MessageWindow: pass
class DetailedMessageWindow(MessageWindow): - def __init__(self, title, text, longText=None, type="ok", default=None, custom_buttons=None, custom_icon=None, run=True, parent=None, destroyAfterRun=True): + def __init__(self, title, text, longText=None, type="ok", default=None, + custom_buttons=None, custom_icon=None, run=True, parent=None, + destroyAfterRun=True): + self.title = title
if flags.autostep: @@ -882,7 +885,8 @@ class DetailedMessageWindow(MessageWindow): self.doCustom = True buttons = custom_buttons
- xml = gtk.glade.XML(findGladeFile("detailed-dialog.glade"), domain="anaconda") + xml = gtk.glade.XML(findGladeFile("detailed-dialog.glade"), + domain="anaconda") self.dialog = xml.get_widget("detailedDialog") self.mainVBox = xml.get_widget("mainVBox") self.hbox = xml.get_widget("hbox1")
* iw/partition_gui.py (createCB): New function. All the create requests will pas through this function. It pops up a dialog that presents the different creat options to the user. (_doFindFirstChildOfRoot): Helper function for hasFreeHardDrives. (hasFreeHardDrives, hasFreePhysicalVolumes): New functions to get info for the new create screen. * ui/create-storage.glade: New file. Glade file that describes the new screen. --- iw/partition_gui.py | 262 ++++++++++++++++++++++++++++++++- ui/create-storage.glade | 373 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 626 insertions(+), 9 deletions(-) create mode 100644 ui/create-storage.glade
diff --git a/iw/partition_gui.py b/iw/partition_gui.py index 847ea2c..dc0ff6a 100644 --- a/iw/partition_gui.py +++ b/iw/partition_gui.py @@ -22,6 +22,7 @@
import gobject import gtk +import gtk.glade try: import gnomecanvas except ImportError: @@ -31,7 +32,6 @@ import gui import parted import string import types -from constants import *
import storage from iw_gui import * @@ -505,7 +505,77 @@ class DiskTreeModel(gtk.TreeStore): if selection is not None: selection.unselect_all() gtk.TreeStore.clear(self) - + + def _doFindFirstChildOfRoot(self, rootstr): + """ + _doFindFirstChildOfRoot(string) -> iter + string is used to find the iter related to that string in DiskTreeModel. + The funtion will return the first child (iter) of this root. Returns + None if root was not found or did not have any children + """ + # This is what we are iteriting on: + # "Hard Drives" + # `- Drive "/dev/sda" + # | `- Partition "/dev/sda1" + # | ... + # `- Drive "/dev/sdb" + # `- Partition "/dev/sdb1" + # `- Partition "free" + # ... + # + hd_gp = self.get_iter_root() #hd_gp -> Hard Drive Grand Parent + while True: + # I wonder if implementing an ID field would be better? + if self[hd_gp]["Device"] == rootstr: + break + + if not self.do_iter_next(self, hd_gp): + break + + if not hd_gp: + # Very Strange... + log.error("Could not find the Hard Drive root in DiskTreeModel") + return None + + if not self.iter_has_child(hd_gp): + log.error("No Drives found under the Hard Drive tree in " + "DiskTreeModel") + return None + + return self.iter_children(hd_gp) + + + #FIXME: is there a way to get this info from storage obj? + def hasFreeHardDrives(self): + # We need at least one free partition to activate the partition + # radiobuttons. + found_free = False + + # Find the Partition level + # hd_p -> Hard Drive Parent + hd_p = self._doFindFirstChildOfRoot(_("Hard Drives")) + if not hd_p: + return False + + hd_ch = None #hd_ch -> Hard Drive Child + while True: + if self.iter_has_child(hd_p): + hd_ch = self.iter_children(hd_p) + while True: + if self[hd_ch]["Device"] == _("Free"): + found_free = True + break + + if not self.do_iter_next(self, hd_ch): + break + + if found_free: + break + if not self.do_iter_next(self, hd_p): + break + + return found_free + def __getitem__(self, iter): if type(iter) == gtk.TreeIter: return DiskTreeModelHelper(self, self.titleSlot, iter) @@ -970,7 +1040,7 @@ class PartitionWindow(InstallWindow):
self.diskStripeGraph.selectSlice(device)
- def newCB(self, widget): + def makepartCB(self, widget): device = self.storage.newPartition(fmt_type=self.storage.defaultFSType, size=200) self.editPartition(device, isNew=1) @@ -999,7 +1069,179 @@ class PartitionWindow(InstallWindow): device.vg._removeLogVol(device)
self.refresh(justRedraw=justRedraw) - + + def createCB(self, *args): + # First we must decide what parts of the create_storage_dialog + # we will activate. + + # For the Partition checkboxes. + # If we see that there is free space in the "Hard Drive" list, then we + # must activate all the partition radio buttons (RAID partition, + # LVM partition and Standard partition). We will have only one var to + # control all three activations (Since they all depend on the same + # thing) + activate_create_partition = False + if self.tree.hasFreeHardDrives(): + activate_create_partition = True + + # We activate the create Volume Group radio button if there is a free + # partition with a Physical Volume format. + activate_create_vg = False + if (lvm.has_lvm() + and getFormat("lvmpv").supported + and len(self.storage.unusedPVs()) > 0): + activate_create_vg = True + + # We activate the create RAID dev if there are partitions that have + # raid format and are not related to any raid dev. + activate_create_raid_dev = False + availraidparts = len(self.storage.unusedMDMembers()) + availminors = self.storage.unusedMDMinors + if (len(availminors) > 0 + and getFormat("software RAID").supported + and availraidparts > 1): + activate_create_raid_dev = True + + # FIXME: Why do I need availraidparts to clone? + activate_create_raid_clone = False + if (len(self.storage.disks) > 1 + and availraidparts > 0): + activate_create_raid_clone = True + + # Must check if all the possibilities are False. In this case tell the + # user that he can't create anything and the reasons. + if (not activate_create_partition + and not activate_create_vg + and not activate_create_raid_dev + and not activate_create_raid_clone): + self.intf.messageWindow(_("Cannot perform any creation action"), + _("Follows an explination... "), + custom_icon="warning") + return + + # GTK crap starts here. + create_storage_xml = gtk.glade.XML( + gui.findGladeFile("create-storage.glade"), domain="anaconda") + self.dialog = create_storage_xml.get_widget("create_storage_dialog") + + # Activate the partition radio buttons if needed. + # sp_rb -> standard partition + sp_rb = create_storage_xml.get_widget("create_storage_rb_standard_part") + # lp_rb -> lvm partition (physical volume) + lp_rb = create_storage_xml.get_widget("create_storage_rb_lvm_part") + # rp_rb -> RAID partition + rp_rb = create_storage_xml.get_widget("create_storage_rb_raid_part") + if activate_create_partition: + sp_rb.set_sensitive(True) + lp_rb.set_sensitive(True) + rp_rb.set_sensitive(True) + + # Activate the Volume Group radio buttons if needed. + # vg_rb -> Volume Group + vg_rb = create_storage_xml.get_widget("create_storage_rb_lvm_vg") + if activate_create_vg: + vg_rb.set_sensitive(True) + + # Activate the RAID dev if needed. + # rd_rb -> RAID device + rd_rb = create_storage_xml.get_widget("create_storage_rb_raid_dev") + if activate_create_raid_dev: + rd_rb.set_sensitive(True) + + # Activate RAID clone if needed. + # rc_rb -> RAID clone + rc_rb = create_storage_xml.get_widget("create_storage_rb_raid_clone") + if activate_create_raid_clone: + rc_rb.set_sensitive(True) + + # Before drawing lets select the first radio button that is sensitive: + # How can I get sensitivity from gtk.radiobutton? + if activate_create_partition: + sp_rb.set_active(True) + elif activate_create_vg: + vg_rb.set_active(True) + elif activate_create_raid_dev: + rd_rb.set_active(True) + elif activate_create_raid_clone: + rc_rb.set_active(True) + + gui.addFrame(self.dialog) + self.dialog.show_all() + + # We loop in the self.dialog.run() only for the help screens. + # dialog_rc == 2 -> partition about + # dialog_rc == 3 -> raid about + # dialog_rc == 4 -> lvm about + while True: + dialog_rc = self.dialog.run() + if dialog_rc == 2 or dialog_rc == 3 or dialog_rc == 4: + # FIXME: Code to handle the About messages. + pass + else: + break + + # If Cancel was pressed + if dialog_rc == 0: + self.dialog.destroy() + return + + # If Create was pressed Make sure we do a dialog.destroy before + # calling any other screen. We don't want the create dialog to show + # in the back when we pop up other screens. + if dialog_rc != 1: + log.error("I received a dialog_rc != 1 (%d) witch should not " + "happen" % rc) + self.dialog.destroy() + return + + self.dialog.destroy() + if rp_rb.get_active(): + member = self.storage.newPartition(fmt_type="software RAID", + size=200) + self.editPartition(member, isNew = 1, restrictfs=["mdmember"]) + return + + elif rc_rb.get_active(): + cloneDialog = raid_dialog_gui.RaidCloneDialog(self.storage, + self.intf, + self.parent) + if cloneDialog is None: + self.intf.messageWindow(_("Couldn't Create Drive Clone Editor"), + _("The drive clone editor could not " + "be created for some reason."), + custom_icon="error") + return + + if cloneDialog.run(): + self.refresh() + + cloneDialog.destroy() + return + + elif rd_rb.get_active(): + array = self.storage.newMDArray(fmt_type=self.storage.defaultFSType) + self.editRaidArray(array, isNew=1) + return + + elif lp_rb.get_active(): + member = self.storage.newPartition(fmt_type="physical volume (LVM)", + size=200) + self.editPartition(member, isNew = 1, restrictfs=["lvmpv"]) + return + + elif vg_rb.get_active(): + tempvg = self.storage.newVG() + self.editLVMVolumeGroup(tempvg, isNew = 1) + return + + elif sp_rb.get_active(): + tempformat = self.storage.defaultFSType + device = self.storage.newPartition(fmt_type=tempformat, size=200) + self.editPartition(device, isNew=1) + return + + import pdb ; pdb.set_trace() + def resetCB(self, *args): if not confirmResetPartitionState(self.intf): return @@ -1361,13 +1603,15 @@ class PartitionWindow(InstallWindow): buttonBox = gtk.HButtonBox() buttonBox.set_layout(gtk.BUTTONBOX_SPREAD)
- ops = ((_("Ne_w"), self.newCB), + ops = ((_("_Create"), self.createCB), (_("_Edit"), self.editCB), (_("_Delete"), self.deleteCB), - (_("Re_set"), self.resetCB), - (_("R_AID"), self.makeraidCB), - (_("_LVM"), self.makeLvmCB)) - + (_("Re_set"), self.resetCB)) + +# (_("_Partition"), self.makepartCB), +# (_("R_AID"), self.makeraidCB), +# (_("_LVM"), self.makeLvmCB)) + for label, cb in ops: button = gtk.Button(label) buttonBox.add (button) diff --git a/ui/create-storage.glade b/ui/create-storage.glade new file mode 100644 index 0000000..1ab3bff --- /dev/null +++ b/ui/create-storage.glade @@ -0,0 +1,373 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> +<!--Generated with glade3 3.4.5 on Wed Jul 29 18:27:47 2009 --> +<glade-interface> + <widget class="GtkDialog" id="create_storage_dialog"> + <property name="visible">True</property> + <property name="title" translatable="yes">Add Storage</property> + <property name="modal">True</property> + <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">2</property> + <property name="label" translatable="yes">Create Partition</property> + </widget> + </child> + <child> + <widget class="GtkLinkButton" id="linkbutton1"> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="has_tooltip">True</property> + <property name="label" translatable="yes">gtk-about</property> + <property name="relief">GTK_RELIEF_NONE</property> + <property name="use_stock">True</property> + <property name="xalign">1</property> + <property name="response_id">2</property> + <property name="uri">http://glade.gnome.org</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + </child> + <child> + <widget class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="create_storage_rb_standard_part"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Standard Partition</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">20</property> + <property name="label" translatable="yes"><span size="small" color="gray">Goes to a "Partition Create" window with a file system +selected by default</span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <child> + <widget class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">2</property> + <property name="label" translatable="yes">Create Software RAID</property> + </widget> + </child> + <child> + <widget class="GtkLinkButton" id="linkbutton2"> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="has_tooltip">True</property> + <property name="label" translatable="yes">gtk-about</property> + <property name="relief">GTK_RELIEF_NONE</property> + <property name="use_stock">True</property> + <property name="xalign">1</property> + <property name="response_id">3</property> + <property name="uri">http://glade.gnome.org</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">2</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="create_storage_rb_raid_part"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">RAID Partition</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <property name="group">create_storage_rb_standard_part</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">20</property> + <property name="label" translatable="yes"><span size="small" color="gray"> Goes to a "Partition Create" window with a RAID format +selected by default</span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">3</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="create_storage_rb_raid_dev"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">RAID Device</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <property name="group">create_storage_rb_standard_part</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label6"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">20</property> + <property name="label" translatable="yes"><span size="small" color="gray">Goes to a "RAID Create" window</span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">4</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="vbox5"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="create_storage_rb_raid_clone"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">RAID Clone</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <property name="group">create_storage_rb_standard_part</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label7"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">20</property> + <property name="label" translatable="yes"><span size="small" color="gray">Goes to a "RAID Clone" window</span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">5</property> + </packing> + </child> + <child> + <widget class="GtkHBox" id="hbox3"> + <property name="visible">True</property> + <child> + <widget class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">2</property> + <property name="label" translatable="yes">Create LVM</property> + </widget> + </child> + <child> + <widget class="GtkLinkButton" id="linkbutton3"> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="has_tooltip">True</property> + <property name="label" translatable="yes">gtk-about</property> + <property name="relief">GTK_RELIEF_NONE</property> + <property name="use_stock">True</property> + <property name="xalign">1</property> + <property name="response_id">4</property> + <property name="uri">http://glade.gnome.org</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">6</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="vbox6"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="create_storage_rb_lvm_vg"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">LVM Volume Group</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <property name="group">create_storage_rb_standard_part</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">20</property> + <property name="label" translatable="yes"><span size="small" color="gray">Goes to a "Create LVM Volume Group" window</span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">7</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="vbox7"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="create_storage_rb_lvm_lv"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">LVM Logical Volume</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <property name="group">create_storage_rb_standard_part</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label9"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">20</property> + <property name="label" translatable="yes"><span size="small" color="gray">Goes to a "Create LVM Logical Volume" window</span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">8</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="vbox8"> + <property name="visible">True</property> + <child> + <widget class="GtkRadioButton" id="create_storage_rb_lvm_part"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">LVM Physical Volume</property> + <property name="response_id">0</property> + <property name="draw_indicator">True</property> + <property name="group">create_storage_rb_standard_part</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="label10"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="xpad">20</property> + <property name="label" translatable="yes"><span size="small" color="gray">Goes to a "Partition Create" window with a LVM Physical +Volume format selected by default</span></property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">9</property> + </packing> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <child> + <widget class="GtkButton" id="storage_create_button_cancel"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="label" translatable="yes">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="response_id">0</property> + </widget> + </child> + <child> + <widget class="GtkButton" id="storage_create_button_create"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="label" translatable="yes">Create</property> + <property name="response_id">1</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + </widget> + </child> + </widget> +</glade-interface>
* iw/partition_gui.py (makeLvmCB, makepartCB, makeraidCB): Remove functions. --- iw/partition_gui.py | 196 +++++++++++++------------------------------------- 1 files changed, 51 insertions(+), 145 deletions(-)
diff --git a/iw/partition_gui.py b/iw/partition_gui.py index dc0ff6a..2d25bda 100644 --- a/iw/partition_gui.py +++ b/iw/partition_gui.py @@ -1040,11 +1040,6 @@ class PartitionWindow(InstallWindow):
self.diskStripeGraph.selectSlice(device)
- def makepartCB(self, widget): - device = self.storage.newPartition(fmt_type=self.storage.defaultFSType, - size=200) - self.editPartition(device, isNew=1) - def deleteCB(self, widget): """ Right now we can say that if the device is partitioned we want to delete all of the devices it contains. At some point @@ -1119,6 +1114,57 @@ class PartitionWindow(InstallWindow): custom_icon="warning") return
+# FIXME: Include the error messages somewhere. +# if not getFormat("software RAID").supported: +# self.intf.messageWindow(_("Not supported"), +# _("Software RAID is NOT supported on " +# "this platform."), type="ok", +# custom_icon="error") +# return +# +# availminors = self.storage.unusedMDMinors +# if len(availminors) < 1: +# self.intf.messageWindow(_("No RAID minor device numbers available"), +# _("A software RAID device cannot " +# "be created because all of the " +# "available RAID minor device numbers " +# "have been used."), +# +# type="ok", custom_icon="error") +# numparts = P_("You currently have %d software RAID partition free to use.", +# "You currently have %d software RAID partitions free to use.", +# len(availraidparts)) % len(availraidparts,) +# +# lbltxt = _("Software RAID allows you to combine several disks into " +# "a larger RAID device. A RAID device can be configured " +# "to provide additional speed and reliability compared " +# "to using an individual drive. For more information on " +# "using RAID devices please consult the %s " +# "documentation.") % (productName,) +# +# lbltxt = lbltxt + "\n\n" + numparts + "\n\n" +# +# if len(availraidparts) < 2: +# lbltxt = lbltxt + _("To use RAID you must first " +# "create at least two partitions of type " +# "'software RAID'. Then you can " +# "create a RAID device that can " +# "be formatted and mounted.\n\n") +# +# lbltxt = lbltxt + _("What do you want to do now?") +# +# FIXME: FOR THE LVM +# if not getFormat("lvmpv").supported or not lvm.has_lvm(): +# self.intf.messageWindow(_("Not supported"), +# _("LVM is NOT supported on " +# "this platform."), type="ok", +# custom_icon="error") +# return + + + + + # GTK crap starts here. create_storage_xml = gtk.glade.XML( gui.findGladeFile("create-storage.glade"), domain="anaconda") @@ -1444,142 +1490,6 @@ class PartitionWindow(InstallWindow):
vgeditor.destroy()
- def makeLvmCB(self, widget): - if not getFormat("lvmpv").supported or not lvm.has_lvm(): - self.intf.messageWindow(_("Not supported"), - _("LVM is NOT supported on " - "this platform."), type="ok", - custom_icon="error") - return - - vg = self.storage.newVG() - self.editLVMVolumeGroup(vg, isNew = 1) - return - - def makeraidCB(self, widget): - if not getFormat("software RAID").supported: - self.intf.messageWindow(_("Not supported"), - _("Software RAID is NOT supported on " - "this platform."), type="ok", - custom_icon="error") - return - - availminors = self.storage.unusedMDMinors - if len(availminors) < 1: - self.intf.messageWindow(_("No RAID minor device numbers available"), - _("A software RAID device cannot " - "be created because all of the " - "available RAID minor device numbers " - "have been used."), - type="ok", custom_icon="error") - return - - - # see if we have enough free software RAID partitions first - # if no raid partitions exist, raise an error message and return - availraidparts = self.storage.unusedMDMembers() - - dialog = gtk.Dialog(_("RAID Options"), self.parent) - gui.addFrame(dialog) - dialog.add_button('gtk-cancel', 2) - dialog.add_button('gtk-ok', 1) - dialog.set_position(gtk.WIN_POS_CENTER) - - maintable = gtk.Table() - maintable.set_row_spacings(5) - maintable.set_col_spacings(5) - row = 0 - - numparts = P_("You currently have %d software RAID partition free to use.", - "You currently have %d software RAID partitions free to use.", - len(availraidparts)) % len(availraidparts,) - - lbltxt = _("Software RAID allows you to combine several disks into " - "a larger RAID device. A RAID device can be configured " - "to provide additional speed and reliability compared " - "to using an individual drive. For more information on " - "using RAID devices please consult the %s " - "documentation.") % (productName,) - - lbltxt = lbltxt + "\n\n" + numparts + "\n\n" - - if len(availraidparts) < 2: - lbltxt = lbltxt + _("To use RAID you must first " - "create at least two partitions of type " - "'software RAID'. Then you can " - "create a RAID device that can " - "be formatted and mounted.\n\n") - - lbltxt = lbltxt + _("What do you want to do now?") - - lbl = gui.WrappingLabel(lbltxt) - maintable.attach(lbl, 0, 1, row, row + 1) - row = row + 1 - - newminor = availminors[0] - radioBox = gtk.VBox (False) - - createRAIDpart = gtk.RadioButton(None, _("Create a software RAID _partition.")) - radioBox.pack_start(createRAIDpart, False, False, padding=10) - createRAIDdev = gtk.RadioButton(createRAIDpart, - _("Create a RAID _device [default=/dev/md%s].") % newminor) - radioBox.pack_start(createRAIDdev, False, False, padding=10) - - doRAIDclone = gtk.RadioButton(createRAIDpart, - _("Clone a _drive to create a " - "RAID device [default=/dev/md%s].") % newminor) - radioBox.pack_start(doRAIDclone, False, False, padding=10) - - createRAIDpart.set_active(1) - doRAIDclone.set_sensitive(0) - createRAIDdev.set_sensitive(0) - if len(availraidparts) > 0 and len(self.storage.disks) > 1: - doRAIDclone.set_sensitive(1) - - if len(availraidparts) > 1: - createRAIDdev.set_active(1) - createRAIDdev.set_sensitive(1) - - align = gtk.Alignment(0.5, 0.0) - align.add(radioBox) - maintable.attach(align,0,1,row, row+1) - row = row + 1 - - maintable.show_all() - dialog.vbox.pack_start(maintable) - dialog.show_all() - rc = dialog.run() - dialog.destroy() - if rc == 2: - return - - # see which option they choose - if createRAIDpart.get_active(): - member = self.storage.newPartition(fmt_type="software RAID", - size=200) - rc = self.editPartition(member, - isNew = 1, - restrictfs=["mdmember"]) - elif createRAIDdev.get_active(): - array = self.storage.newMDArray(fmt_type=self.storage.defaultFSType) - self.editRaidArray(array, isNew=1) - else: - cloneDialog = raid_dialog_gui.RaidCloneDialog(self.storage, - self.intf, - self.parent) - if cloneDialog is None: - self.intf.messageWindow(_("Couldn't Create Drive Clone Editor"), - _("The drive clone editor could not " - "be created for some reason."), - custom_icon="error") - return - - if cloneDialog.run(): - self.refresh() - - cloneDialog.destroy() - return - def viewButtonCB(self, widget): self.show_uneditable = not widget.get_active() self.diskStripeGraph.shutDown() @@ -1608,10 +1518,6 @@ class PartitionWindow(InstallWindow): (_("_Delete"), self.deleteCB), (_("Re_set"), self.resetCB))
-# (_("_Partition"), self.makepartCB), -# (_("R_AID"), self.makeraidCB), -# (_("_LVM"), self.makeLvmCB)) - for label, cb in ops: button = gtk.Button(label) buttonBox.add (button)
* iw/partition_gui.py (createCB): Add the messages. Remove the pdb call. * ui/create-storage.glade: Make the buttons visible and sensitive. --- iw/partition_gui.py | 120 +++++++++++++++++++++-------------------------- ui/create-storage.glade | 32 ++++--------- 2 files changed, 64 insertions(+), 88 deletions(-)
diff --git a/iw/partition_gui.py b/iw/partition_gui.py index 2d25bda..c7d2354 100644 --- a/iw/partition_gui.py +++ b/iw/partition_gui.py @@ -1076,15 +1076,17 @@ class PartitionWindow(InstallWindow): # control all three activations (Since they all depend on the same # thing) activate_create_partition = False - if self.tree.hasFreeHardDrives(): + free_part_available = self.tree.hasFreeHardDrives() + if free_part_available: activate_create_partition = True
# We activate the create Volume Group radio button if there is a free # partition with a Physical Volume format. activate_create_vg = False + availpvs = len(self.storage.unusedPVs()) if (lvm.has_lvm() and getFormat("lvmpv").supported - and len(self.storage.unusedPVs()) > 0): + and availpvs > 0): activate_create_vg = True
# We activate the create RAID dev if there are partitions that have @@ -1114,57 +1116,6 @@ class PartitionWindow(InstallWindow): custom_icon="warning") return
-# FIXME: Include the error messages somewhere. -# if not getFormat("software RAID").supported: -# self.intf.messageWindow(_("Not supported"), -# _("Software RAID is NOT supported on " -# "this platform."), type="ok", -# custom_icon="error") -# return -# -# availminors = self.storage.unusedMDMinors -# if len(availminors) < 1: -# self.intf.messageWindow(_("No RAID minor device numbers available"), -# _("A software RAID device cannot " -# "be created because all of the " -# "available RAID minor device numbers " -# "have been used."), -# -# type="ok", custom_icon="error") -# numparts = P_("You currently have %d software RAID partition free to use.", -# "You currently have %d software RAID partitions free to use.", -# len(availraidparts)) % len(availraidparts,) -# -# lbltxt = _("Software RAID allows you to combine several disks into " -# "a larger RAID device. A RAID device can be configured " -# "to provide additional speed and reliability compared " -# "to using an individual drive. For more information on " -# "using RAID devices please consult the %s " -# "documentation.") % (productName,) -# -# lbltxt = lbltxt + "\n\n" + numparts + "\n\n" -# -# if len(availraidparts) < 2: -# lbltxt = lbltxt + _("To use RAID you must first " -# "create at least two partitions of type " -# "'software RAID'. Then you can " -# "create a RAID device that can " -# "be formatted and mounted.\n\n") -# -# lbltxt = lbltxt + _("What do you want to do now?") -# -# FIXME: FOR THE LVM -# if not getFormat("lvmpv").supported or not lvm.has_lvm(): -# self.intf.messageWindow(_("Not supported"), -# _("LVM is NOT supported on " -# "this platform."), type="ok", -# custom_icon="error") -# return - - - - - # GTK crap starts here. create_storage_xml = gtk.glade.XML( gui.findGladeFile("create-storage.glade"), domain="anaconda") @@ -1214,17 +1165,56 @@ class PartitionWindow(InstallWindow): gui.addFrame(self.dialog) self.dialog.show_all()
- # We loop in the self.dialog.run() only for the help screens. - # dialog_rc == 2 -> partition about - # dialog_rc == 3 -> raid about - # dialog_rc == 4 -> lvm about - while True: - dialog_rc = self.dialog.run() - if dialog_rc == 2 or dialog_rc == 3 or dialog_rc == 4: - # FIXME: Code to handle the About messages. - pass - else: - break + # Lets work the information messages with CB + # The RAID info message + rinfo_button = create_storage_xml.get_widget("create_storage_info_raid") + whatis_r = _("Software RAID allows you to combine several disks into " + "a larger RAID device. A RAID device can be configured " + "to provide additional speed and reliability compared " + "to using an individual drive. For more information on " + "using RAID devices please consult the %s " + "documentation.\n") % (productName,) + whatneed_r = _("To use RAID you must first create at least two " + "partitions of type 'software RAID'. Then you can create a " + "RAID device that can be formatted and mounted.\n\n") + whathave_r = P_( + "You currently have %d software RAID partition free to use.", + "You currently have %d software RAID partitions free to use.", + availraidparts) % (availraidparts,) + rinfo_message = "%s\n%s%s" % (whatis_r, whatneed_r, whathave_r) + rinfo_cb = lambda x : self.intf.messageWindow(_("About RAID"), + rinfo_message, custom_icon="information") + rinfo_button.connect("clicked", rinfo_cb) + + # The LVM info message + lvminfo_button = create_storage_xml.get_widget("create_storage_info_lvm") + whatis_lvm = _("LVM is an abbreviation for Logical Volume Manager. It " + "is a 3 tier construct. The fist is made up of any physical hard " + "drive or partition formated with LVM metadata. These are " + "called Physical Volumes (PV). On top of one or more of " + "these PVs, sits the second tier called Volume Group (VG). " + "It collects underlying PVs into one LVM element. Finally, " + "on top of the VG sits the Logical Volume (LV) tier. A VG " + "can have one or more LVs. Also note that the VGs can be an " + "aggregate of PVs from multiple physical disk. Resizing of " + "LVs is also possible. For more information on using LVM " + "please consult the %s documentation\n") % (productName, ) + whatneed_lvm = _("To create a PV you need a partition with " + "free space. To create a VG you need a PV that is not " + "part of any VG. To create a LV you need a VG with free" + "space\n\n") + whathave_lvm = P_("You currently have %d available PV free to use.\n", + "You currently have %d available PVs free to use.\n", + availpvs) % (availpvs, ) + if free_part_available: + whathave_lvm = whathave_lvm + _("You currently have free space to " + "create PVs.") + lvminfo_message = "%s\n%s%s" % (whatis_lvm, whatneed_lvm, whathave_lvm) + lvminfo_cb = lambda x : self.intf.messageWindow(_("About LVM"), + lvminfo_message, custom_icon="information") + lvminfo_button.connect("clicked", lvminfo_cb) + + dialog_rc = self.dialog.run()
# If Cancel was pressed if dialog_rc == 0: @@ -1286,8 +1276,6 @@ class PartitionWindow(InstallWindow): self.editPartition(device, isNew=1) return
- import pdb ; pdb.set_trace() - def resetCB(self, *args): if not confirmResetPartitionState(self.intf): return diff --git a/ui/create-storage.glade b/ui/create-storage.glade index 1ab3bff..5cd5b6b 100644 --- a/ui/create-storage.glade +++ b/ui/create-storage.glade @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> -<!--Generated with glade3 3.4.5 on Wed Jul 29 18:27:47 2009 --> +<!--Generated with glade3 3.4.5 on Thu Jul 30 13:53:49 2009 --> <glade-interface> <widget class="GtkDialog" id="create_storage_dialog"> <property name="visible">True</property> @@ -27,21 +27,7 @@ </widget> </child> <child> - <widget class="GtkLinkButton" id="linkbutton1"> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="has_tooltip">True</property> - <property name="label" translatable="yes">gtk-about</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_stock">True</property> - <property name="xalign">1</property> - <property name="response_id">2</property> - <property name="uri">http://glade.gnome.org</property> - </widget> - <packing> - <property name="position">1</property> - </packing> + <placeholder/> </child> </widget> </child> @@ -88,12 +74,12 @@ selected by default</span></property> </widget> </child> <child> - <widget class="GtkLinkButton" id="linkbutton2"> - <property name="sensitive">False</property> + <widget class="GtkLinkButton" id="create_storage_info_raid"> + <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="has_tooltip">True</property> - <property name="label" translatable="yes">gtk-about</property> + <property name="label" translatable="yes">gtk-info</property> <property name="relief">GTK_RELIEF_NONE</property> <property name="use_stock">True</property> <property name="xalign">1</property> @@ -101,6 +87,7 @@ selected by default</span></property> <property name="uri">http://glade.gnome.org</property> </widget> <packing> + <property name="expand">False</property> <property name="position">1</property> </packing> </child> @@ -215,12 +202,12 @@ selected by default</span></property> </widget> </child> <child> - <widget class="GtkLinkButton" id="linkbutton3"> - <property name="sensitive">False</property> + <widget class="GtkLinkButton" id="create_storage_info_lvm"> + <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="has_tooltip">True</property> - <property name="label" translatable="yes">gtk-about</property> + <property name="label" translatable="yes">gtk-info</property> <property name="relief">GTK_RELIEF_NONE</property> <property name="use_stock">True</property> <property name="xalign">1</property> @@ -228,6 +215,7 @@ selected by default</span></property> <property name="uri">http://glade.gnome.org</property> </widget> <packing> + <property name="expand">False</property> <property name="position">1</property> </packing> </child>
Put the action buttons at the bottom of the screen (on top of the "Ok" and "Cancel") buttons so they similar to what gnome standard uses.
* iw/partition_gui.py (getScreen): Change the order or the main customization screen. --- iw/partition_gui.py | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/iw/partition_gui.py b/iw/partition_gui.py index c7d2354..9d1529b 100644 --- a/iw/partition_gui.py +++ b/iw/partition_gui.py @@ -1499,7 +1499,8 @@ class PartitionWindow(InstallWindow):
# operational buttons buttonBox = gtk.HButtonBox() - buttonBox.set_layout(gtk.BUTTONBOX_SPREAD) + buttonBox.set_spacing(10) + buttonBox.set_layout(gtk.BUTTONBOX_END)
ops = ((_("_Create"), self.createCB), (_("_Edit"), self.editCB), @@ -1537,7 +1538,6 @@ class PartitionWindow(InstallWindow): vpaned.add1(frame)
box = gtk.VBox(False, 5) - box.pack_start(buttonBox, False) sw = gtk.ScrolledWindow() sw.add(self.treeView) sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) @@ -1549,7 +1549,9 @@ class PartitionWindow(InstallWindow): self.toggleViewButton.set_active(not self.show_uneditable) self.toggleViewButton.connect("toggled", self.viewButtonCB) box.pack_start(self.toggleViewButton, False, False) - + box.pack_start(buttonBox, False) + box.pack_start(gtk.HSeparator(), False) + vpaned.add2(box)
# XXX should probably be set according to height
--- iw/partition_gui.py | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/iw/partition_gui.py b/iw/partition_gui.py index 9d1529b..557cd9e 100644 --- a/iw/partition_gui.py +++ b/iw/partition_gui.py @@ -1112,8 +1112,13 @@ class PartitionWindow(InstallWindow): and not activate_create_raid_dev and not activate_create_raid_clone): self.intf.messageWindow(_("Cannot perform any creation action"), - _("Follows an explination... "), - custom_icon="warning") + _("Note that the creation action requires one of the " + "following:\n\n" + "* Free space in one of the Hard Drives.\n" + "* At least two free Software RAID partitions.\n" + "* At least one free physical volume (LVM) partition.\n" + "* At least one Volume Group with free space."), + custom_icon="warning") return
# GTK crap starts here.
For testing I used F11 vmlinuz and initrd and a stage2 image: http://jgranado.fedorapeople.org/anaconda/ui/install.img and an updates image with the changes http://jgranado.fedorapeople.org/anaconda/ui/updates.img
The updates was created from a git repo that is some days old. The stage2 images is also from a rawhide that is somthing like a week old. The patches that are included in this patchset are rebased to current master so I don't think there would be any major problems.
Regards.
On Thu, Jul 30, 2009 at 04:19:12PM +0200, Joel Granados Moreno wrote:
Hello list
Been working on a Custom Partitioning workflow. Based on https://fedoraproject.org/wiki/Design/AnacondaStorageUI/MiscMockupIdeas
In this patchset there are two big changes:
....
Review appreciated.
regards.
Joel Andres Granados Brno, Czech Republic, Red Hat.
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
On Thursday, July 30 2009, Joel Granados Moreno said:
Been working on a Custom Partitioning workflow. Based on https://fedoraproject.org/wiki/Design/AnacondaStorageUI/MiscMockupIdeas
In this patchset there are two big changes:
A few things before I really go through the patches: * We're after feature freeze now which nominally means that we should hold off on these * Screenshots are worth a million lines of patch in UI chnaging stuff :-)
Jeremy
On Thu, Jul 30, 2009 at 11:13:23AM -0400, Jeremy Katz wrote:
On Thursday, July 30 2009, Joel Granados Moreno said:
Been working on a Custom Partitioning workflow. Based on https://fedoraproject.org/wiki/Design/AnacondaStorageUI/MiscMockupIdeas
In this patchset there are two big changes:
A few things before I really go through the patches:
- We're after feature freeze now which nominally means that we should hold off on these
- Screenshots are worth a million lines of patch in UI chnaging stuff :-)
Ack. I'll post them in a bit.
Jeremy
Anaconda-devel-list mailing list Anaconda-devel-list@redhat.com https://www.redhat.com/mailman/listinfo/anaconda-devel-list
anaconda-devel@lists.fedoraproject.org