[gnome-disk-utility] First usable version of the Create RAID Array dialog



commit 121e7e1c81c3e43f7e67d89161069f82ad47fe10
Author: David Zeuthen <davidz redhat com>
Date:   Sat Aug 8 15:06:38 2009 -0400

    First usable version of the Create RAID Array dialog
    
    Still missing
    
     o We only support creating RAID0, RAID1, RAID5 and RAID6 arrays. Notes about
       missing levels
    
       - Linear: People should be using LVM instead. We will support that at some
                 point.
    
       - RAID4: We could add this but people should be using RAID5 instead. Having
                both would be confusing.
    
       - RAID10: It is probably more logical to avoid this. People can obtain
                 the same effect by create a RAID1 of RAID0s.
    
       - multipath: ... sigh
    
       - faulty: This is only for debugging.
    
       - container: Need to research if Fakeraid etc. using md needs to be treated
         separately. It probably does.
    
     o Progress dialog. This will be added in a subsequent commit. The idea is to
       refactor src/format-tool/gdu-format-progress-dialog.c into a generic
       GduProgressDialog class.

 src/gdu-gtk/gdu-create-linux-md-dialog.c    | 1299 +++++++++++++++++++--------
 src/gdu-gtk/gdu-create-linux-md-dialog.h    |   14 +-
 src/gdu-gtk/gdu-gtk-enums.h                 |   28 +-
 src/gdu-gtk/gdu-pool-tree-model.c           |   82 ++-
 src/gdu-gtk/gdu-pool-tree-model.h           |   11 +-
 src/gdu-gtk/gdu-pool-tree-view.c            |   94 ++-
 src/gdu-gtk/gdu-size-widget.c               |    4 +
 src/gdu-gtk/gdu-time-label.c                |   12 +-
 src/gdu/gdu-callbacks.h                     |    5 +
 src/gdu/gdu-device.c                        |    9 +
 src/gdu/gdu-device.h                        |    1 +
 src/gdu/gdu-drive.c                         |  234 +++++-
 src/gdu/gdu-drive.h                         |   10 +
 src/gdu/gdu-linux-md-drive.c                |   92 ++-
 src/gdu/gdu-pool.c                          |   61 ++
 src/gdu/gdu-pool.h                          |    8 +
 src/gdu/gdu-presentable.c                   |   45 +
 src/gdu/gdu-presentable.h                   |    4 +
 src/gdu/gdu-util.c                          |   77 ++-
 src/gdu/gdu-util.h                          |    5 +-
 src/gdu/gdu-volume-hole.c                   |   33 +-
 src/gdu/gdu-volume.c                        |   92 ++-
 src/palimpsest/gdu-section-linux-md-drive.c |    3 +-
 src/palimpsest/gdu-shell.c                  |  262 ++++++-
 24 files changed, 1999 insertions(+), 486 deletions(-)
---
diff --git a/src/gdu-gtk/gdu-create-linux-md-dialog.c b/src/gdu-gtk/gdu-create-linux-md-dialog.c
index 45dbc25..ea90378 100644
--- a/src/gdu-gtk/gdu-create-linux-md-dialog.c
+++ b/src/gdu-gtk/gdu-create-linux-md-dialog.c
@@ -35,29 +35,30 @@ struct GduCreateLinuxMdDialogPrivate
         GduPool *pool;
         GduPoolTreeModel *model;
 
-        /* represents user selected options */
-        gchar *level;
-        guint num_disks;
-        guint64 component_size;
-        guint64 total_size;
+        GtkWidget *level_combo_box;
+        GtkWidget *level_desc_label;
 
-        /* Number of disks with room for components */
-        guint available_num_disks;
+        GtkWidget *name_entry;
 
-        /* The maximum possible size of the array - this is a function of available_num_disks
-         * and num_disks and how each disk is laid out. Is 0 if an array for the given
-         * configuration cannot be created.
-         */
-        guint64 available_total_size;
+        GtkWidget *stripe_size_label;
+        GtkWidget *stripe_size_combo_box;
 
-        GtkWidget *name_entry;
-        GtkWidget *num_disks_spin_button;
-        GtkWidget *size_widget;
         GtkWidget *tree_view;
 
+        GtkWidget *size_label;
+        GtkWidget *size_widget;
+
         GtkWidget *tip_container;
         GtkWidget *tip_image;
         GtkWidget *tip_label;
+
+        /* represents user selected options */
+        gchar *level;
+        guint num_disks_needed;
+        guint stripe_size;
+
+        /* A list of GduDrive objects to create the components on */
+        GList *selected_drives;
 };
 
 enum
@@ -66,6 +67,10 @@ enum
         PROP_POOL,
         PROP_LEVEL,
         PROP_NAME,
+        PROP_SIZE,
+        PROP_COMPONENT_SIZE,
+        PROP_STRIPE_SIZE,
+        PROP_DRIVES,
 };
 
 static void gdu_create_linux_md_dialog_constructed (GObject *object);
@@ -96,6 +101,14 @@ static void on_row_inserted (GtkTreeModel *tree_model,
                              GtkTreeIter  *iter,
                              gpointer      user_data);
 
+static void get_sizes (GduCreateLinuxMdDialog *dialog,
+                       guint                  *out_num_disks,
+                       guint                  *out_num_available_disks,
+                       guint64                *out_component_size,
+                       guint64                *out_array_size,
+                       guint64                *out_max_component_size,
+                       guint64                *out_max_array_size);
+
 G_DEFINE_TYPE (GduCreateLinuxMdDialog, gdu_create_linux_md_dialog, GTK_TYPE_DIALOG)
 
 static void
@@ -114,6 +127,9 @@ gdu_create_linux_md_dialog_finalize (GObject *object)
         g_object_unref (dialog->priv->model);
         g_free (dialog->priv->level);
 
+        g_list_foreach (dialog->priv->selected_drives, (GFunc) g_object_unref, NULL);
+        g_list_free (dialog->priv->selected_drives);
+
         if (G_OBJECT_CLASS (gdu_create_linux_md_dialog_parent_class)->finalize != NULL)
                 G_OBJECT_CLASS (gdu_create_linux_md_dialog_parent_class)->finalize (object);
 }
@@ -125,6 +141,7 @@ gdu_create_linux_md_dialog_get_property (GObject    *object,
                                          GParamSpec *pspec)
 {
         GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (object);
+        GPtrArray *p;
 
         switch (property_id) {
         case PROP_POOL:
@@ -139,6 +156,24 @@ gdu_create_linux_md_dialog_get_property (GObject    *object,
                 g_value_set_string (value, gdu_create_linux_md_dialog_get_name (dialog));
                 break;
 
+        case PROP_SIZE:
+                g_value_set_uint64 (value, gdu_create_linux_md_dialog_get_size (dialog));
+                break;
+
+        case PROP_COMPONENT_SIZE:
+                g_value_set_uint64 (value, gdu_create_linux_md_dialog_get_component_size (dialog));
+                break;
+
+        case PROP_STRIPE_SIZE:
+                g_value_set_uint64 (value, gdu_create_linux_md_dialog_get_stripe_size (dialog));
+                break;
+
+        case PROP_DRIVES:
+                p = gdu_create_linux_md_dialog_get_drives (dialog);
+                g_value_set_boxed (value, p);
+                g_ptr_array_unref (p);
+                break;
+
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
                 break;
@@ -202,14 +237,64 @@ gdu_create_linux_md_dialog_class_init (GduCreateLinuxMdDialogClass *klass)
 
         g_object_class_install_property (object_class,
                                          PROP_NAME,
-                                         g_param_spec_string ("fs-label",
-                                                              _("Filesystem label"),
-                                                              _("The requested filesystem label"),
+                                         g_param_spec_string ("name",
+                                                              _("Name"),
+                                                              _("The requested name for the array"),
                                                               NULL,
                                                               G_PARAM_READABLE |
                                                               G_PARAM_STATIC_NAME |
                                                               G_PARAM_STATIC_NICK |
                                                               G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_SIZE,
+                                         g_param_spec_uint64 ("size",
+                                                              _("Size"),
+                                                              _("The requested size of the array"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_COMPONENT_SIZE,
+                                         g_param_spec_uint64 ("component-size",
+                                                              _("Component Size"),
+                                                              _("The size of each component"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_STRIPE_SIZE,
+                                         g_param_spec_uint64 ("stripe-size",
+                                                              _("Stripe Size"),
+                                                              _("The requested stripe size of the array"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_DRIVES,
+                                         g_param_spec_boxed ("drives",
+                                                             _("Drives"),
+                                                             _("Array of drives to use for the array"),
+                                                             G_TYPE_PTR_ARRAY,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_STATIC_NAME |
+                                                             G_PARAM_STATIC_NICK |
+                                                             G_PARAM_STATIC_BLURB));
 }
 
 static void
@@ -244,53 +329,162 @@ gdu_create_linux_md_dialog_get_name (GduCreateLinuxMdDialog *dialog)
         return g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->priv->name_entry)));
 }
 
+guint64
+gdu_create_linux_md_dialog_get_size (GduCreateLinuxMdDialog  *dialog)
+{
+        guint64 array_size;
+
+        g_return_val_if_fail (GDU_IS_CREATE_LINUX_MD_DIALOG (dialog), 0);
+
+        get_sizes (dialog,
+                   NULL,  /* num_disks */
+                   NULL,  /* num_available_disks */
+                   NULL,  /* component_size */
+                   &array_size,
+                   NULL,  /* max_component_size */
+                   NULL); /* max_array_size */
+
+        return array_size;
+}
+
+guint64
+gdu_create_linux_md_dialog_get_component_size (GduCreateLinuxMdDialog  *dialog)
+{
+        guint64 component_size;
+
+        g_return_val_if_fail (GDU_IS_CREATE_LINUX_MD_DIALOG (dialog), 0);
+
+        get_sizes (dialog,
+                   NULL,  /* num_disks */
+                   NULL,  /* num_available_disks */
+                   &component_size,
+                   NULL,  /* array_size */
+                   NULL,  /* max_component_size */
+                   NULL); /* max_array_size */
+
+        return component_size;
+}
+
+guint64
+gdu_create_linux_md_dialog_get_stripe_size (GduCreateLinuxMdDialog  *dialog)
+{
+        g_return_val_if_fail (GDU_IS_CREATE_LINUX_MD_DIALOG (dialog), 0);
+
+        if (g_strcmp0 (dialog->priv->level, "raid1") == 0)
+                return 0;
+        else
+                return dialog->priv->stripe_size;
+}
+
+GPtrArray *
+gdu_create_linux_md_dialog_get_drives (GduCreateLinuxMdDialog  *dialog)
+{
+        GPtrArray *p;
+        GList *l;
+
+        g_return_val_if_fail (GDU_IS_CREATE_LINUX_MD_DIALOG (dialog), NULL);
+
+        p = g_ptr_array_new_with_free_func (g_object_unref);
+        for (l = dialog->priv->selected_drives; l != NULL; l = l->next) {
+                GduPresentable *drive = GDU_PRESENTABLE (l->data);
+                g_ptr_array_add (p, g_object_ref (drive));
+        }
+        return p;
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-on_combo_box_changed (GtkWidget *combo_box,
-                      gpointer   user_data)
+on_level_combo_box_changed (GtkWidget *combo_box,
+                            gpointer   user_data)
 {
         GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
-        GduKnownFilesystem *kfs;
-        gint max_label_len;
+        gchar *s;
+        gchar *markup;
 
         /* keep in sync with where combo box is constructed in constructed() */
         g_free (dialog->priv->level);
         switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box))) {
         case 0:
-                dialog->priv->level = g_strdup ("linear");
+                dialog->priv->level = g_strdup ("raid0");
+                dialog->priv->num_disks_needed = 2;
                 break;
         case 1:
-                dialog->priv->level = g_strdup ("raid0");
+                dialog->priv->level = g_strdup ("raid1");
+                dialog->priv->num_disks_needed = 2;
                 break;
         case 2:
-                dialog->priv->level = g_strdup ("raid1");
+                dialog->priv->level = g_strdup ("raid5");
+                dialog->priv->num_disks_needed = 3;
                 break;
         case 3:
-                dialog->priv->level = g_strdup ("raid4");
+                dialog->priv->level = g_strdup ("raid6");
+                dialog->priv->num_disks_needed = 4;
+                break;
+        default:
+                g_assert_not_reached ();
+                break;
+        }
+
+        s = gdu_linux_md_get_raid_level_description (dialog->priv->level);
+        markup = g_strconcat ("<small><i>",
+                              s,
+                              "</i></small>",
+                              NULL);
+        g_free (s);
+        gtk_label_set_markup (GTK_LABEL (dialog->priv->level_desc_label), markup);
+        g_free (markup);
+
+        update (dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_stripe_size_combo_box_changed (GtkWidget *combo_box,
+                                  gpointer   user_data)
+{
+        GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
+
+        /* keep in sync with where combo box is constructed in constructed() */
+        switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo_box))) {
+        case 0:
+                dialog->priv->stripe_size = 4 * 1024;
+                break;
+        case 1:
+                dialog->priv->stripe_size = 8 * 1024;
+                break;
+        case 2:
+                dialog->priv->stripe_size = 16 * 1024;
+                break;
+        case 3:
+                dialog->priv->stripe_size = 32 * 1024;
                 break;
         case 4:
-                dialog->priv->level = g_strdup ("raid5");
+                dialog->priv->stripe_size = 64 * 1024;
                 break;
         case 5:
-                dialog->priv->level = g_strdup ("raid6");
+                dialog->priv->stripe_size = 128 * 1024;
                 break;
         case 6:
-                dialog->priv->level = g_strdup ("raid10");
+                dialog->priv->stripe_size = 256 * 1024;
+                break;
+        case 7:
+                dialog->priv->stripe_size = 512 * 1024;
+                break;
+        case 8:
+                dialog->priv->stripe_size = 1024 * 1024;
                 break;
         default:
                 g_assert_not_reached ();
                 break;
         }
 
-        max_label_len = 0;
-        kfs = gdu_pool_get_known_filesystem_by_id (dialog->priv->pool, dialog->priv->level);
-        if (kfs != NULL) {
-                max_label_len = gdu_known_filesystem_get_max_label_len (kfs);
-                g_object_unref (kfs);
-        }
+        update (dialog);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 on_name_entry_activated (GtkWidget *combo_box,
                          gpointer   user_data)
@@ -302,28 +496,373 @@ on_name_entry_activated (GtkWidget *combo_box,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static gboolean
+drive_is_selected (GduCreateLinuxMdDialog *dialog,
+                   GduPresentable         *drive)
+{
+        return g_list_find (dialog->priv->selected_drives, drive) != NULL;
+}
+
+static void
+drive_remove (GduCreateLinuxMdDialog *dialog,
+              GduPresentable         *drive)
+{
+        GList *l;
+
+        l = g_list_find (dialog->priv->selected_drives, drive);
+        if (l != NULL) {
+                g_object_unref (l->data);
+                dialog->priv->selected_drives = g_list_delete_link (dialog->priv->selected_drives,
+                                                                    l);
+        }
+}
+
+static void
+drive_add (GduCreateLinuxMdDialog *dialog,
+           GduPresentable         *drive)
+{
+        g_return_if_fail (!drive_is_selected (dialog, drive));
+
+        dialog->priv->selected_drives = g_list_prepend (dialog->priv->selected_drives,
+                                                        g_object_ref (drive));
+}
+
+
 static void
-on_num_disks_spin_button_value_changed (GtkSpinButton *spin_button,
-                                        gpointer       user_data)
+drive_toggle (GduCreateLinuxMdDialog *dialog,
+              GduPresentable         *drive)
+{
+        if (drive_is_selected (dialog, drive)) {
+                drive_remove (dialog, drive);
+        } else {
+                drive_add (dialog, drive);
+        }
+}
+
+
+static void
+toggle_data_func (GtkCellLayout   *cell_layout,
+                  GtkCellRenderer *renderer,
+                  GtkTreeModel    *tree_model,
+                  GtkTreeIter     *iter,
+                  gpointer         user_data)
+{
+        GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
+        GduPresentable *p;
+        gboolean is_toggled;
+
+        gtk_tree_model_get (tree_model,
+                            iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+                            -1);
+
+        is_toggled = drive_is_selected (dialog, p);
+
+        g_object_set (renderer,
+                      "active", is_toggled,
+                      NULL);
+
+        g_object_unref (p);
+}
+
+static void
+on_disk_toggled (GtkCellRendererToggle *renderer,
+                 const gchar           *path_string,
+                 gpointer               user_data)
 {
         GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
+        GtkTreeIter iter;
+        GtkTreePath *path;
+        GduPresentable *p;
+
+        if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (dialog->priv->model),
+                                                  &iter,
+                                                  path_string))
+                goto out;
+
+        gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->model),
+                            &iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+                            -1);
+
+        drive_toggle (dialog, p);
 
-        dialog->priv->num_disks = (gint) gtk_spin_button_get_value (spin_button);
+        path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->priv->model),
+                                        &iter);
+        gtk_tree_model_row_changed (GTK_TREE_MODEL (dialog->priv->model),
+                                    path,
+                                    &iter);
+        gtk_tree_path_free (path);
+
+        g_object_unref (p);
 
         update (dialog);
+
+ out:
+        ;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
-on_size_widget_changed (GduSizeWidget *widget,
-                        gpointer       user_data)
+disk_name_data_func (GtkCellLayout   *cell_layout,
+                     GtkCellRenderer *renderer,
+                     GtkTreeModel    *tree_model,
+                     GtkTreeIter     *iter,
+                     gpointer         user_data)
+{
+        GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
+        GtkTreeSelection *tree_selection;
+        gchar *name;
+        gchar *vpd_name;
+        gchar *desc;
+        gchar *markup;
+        GtkStyle *style;
+        GdkColor desc_gdk_color = {0};
+        gchar *desc_color;
+        GtkStateType state;
+
+        tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->tree_view));
+
+        gtk_tree_model_get (tree_model,
+                            iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_NAME, &name,
+                            GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME, &vpd_name,
+                            GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION, &desc,
+                            -1);
+
+        /* This color business shouldn't be this hard... */
+        style = gtk_widget_get_style (GTK_WIDGET (dialog->priv->tree_view));
+        if (gtk_tree_selection_iter_is_selected (tree_selection, iter)) {
+                if (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (dialog->priv->tree_view)))
+                        state = GTK_STATE_SELECTED;
+                else
+                        state = GTK_STATE_ACTIVE;
+        } else {
+                state = GTK_STATE_NORMAL;
+        }
+#define BLEND_FACTOR 0.7
+        desc_gdk_color.red   = style->text[state].red   * BLEND_FACTOR +
+                               style->base[state].red   * (1.0 - BLEND_FACTOR);
+        desc_gdk_color.green = style->text[state].green * BLEND_FACTOR +
+                               style->base[state].green * (1.0 - BLEND_FACTOR);
+        desc_gdk_color.blue  = style->text[state].blue  * BLEND_FACTOR +
+                               style->base[state].blue  * (1.0 - BLEND_FACTOR);
+#undef BLEND_FACTOR
+        desc_color = g_strdup_printf ("#%02x%02x%02x",
+                                      (desc_gdk_color.red >> 8),
+                                      (desc_gdk_color.green >> 8),
+                                      (desc_gdk_color.blue >> 8));
+
+        markup = g_strdup_printf ("<b>%s</b>\n"
+                                  "<span fgcolor=\"%s\"><small>%s\n%s</small></span>",
+                                  name,
+                                  desc_color,
+                                  vpd_name,
+                                  desc);
+
+        g_object_set (renderer,
+                      "markup", markup,
+                      NULL);
+
+        g_free (name);
+        g_free (vpd_name);
+        g_free (desc);
+        g_free (markup);
+        g_free (desc_color);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+notes_data_func (GtkCellLayout   *cell_layout,
+                 GtkCellRenderer *renderer,
+                 GtkTreeModel    *tree_model,
+                 GtkTreeIter     *iter,
+                 gpointer         user_data)
 {
         GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
+        GduPresentable *p;
+        gchar *markup;
+        gchar *s;
+        gint width;
+
+        gtk_tree_model_get (tree_model,
+                            iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+                            -1);
+
+        if (GDU_IS_DRIVE (p)) {
+                GduDevice *d;
+                guint64 largest_segment;
+                gboolean whole_disk_is_uninitialized;
+                guint num_partitions;
+                gboolean is_partitioned;
+
+                d = gdu_presentable_get_device (p);
+
+                num_partitions = 0;
+                is_partitioned = FALSE;
+                if (gdu_device_is_partition_table (d)) {
+                        is_partitioned = TRUE;
+                        num_partitions = gdu_device_partition_table_get_count (d);
+                }
+
+                g_warn_if_fail (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
+                                                                 &whole_disk_is_uninitialized,
+                                                                 &largest_segment,
+                                                                 NULL));
+
+
+                if (drive_is_selected (dialog, p)) {
+                        guint num_disks;
+                        guint num_available_disks;
+                        guint64 component_size;
+                        guint64 array_size;
+
+                        get_sizes (dialog,
+                                   &num_disks,
+                                   &num_available_disks,
+                                   &component_size,
+                                   &array_size,
+                                   NULL,  /* max_component_size */
+                                   NULL); /* max_array_size */
+
+
+                        if (array_size > 1000 * 1000) {
+                                gchar *strsize;
+                                strsize = gdu_util_get_size_for_display (component_size, FALSE);
+
+                                if (whole_disk_is_uninitialized) {
+                                        /* Translators: This is shown in the Details column.
+                                         * %s is the component size e.g. '42 GB'.
+                                         */
+                                        markup = g_strdup_printf (_("The disk will be partitioned and a %s partition "
+                                                                    "will be created"),
+                                                                  strsize);
+                                } else {
+                                        /* Translators: This is shown in the Details column.
+                                         * %s is the component size e.g. '42 GB'.
+                                         */
+                                        markup = g_strdup_printf (_("A %s partition will be created"),
+                                                                  strsize);
+                                }
+                                g_free (strsize);
+                        } else {
+                                if (whole_disk_is_uninitialized) {
+                                        /* Translators: This is shown in the Details column. */
+                                        markup = g_strdup (_("The disk will be partitioned and a partition "
+                                                             "will be created"));
+                                } else {
+                                        /* Translators: This is shown in the Details column. */
+                                        markup = g_strdup (_("A partition will be created"));
+                                }
+                        }
+
+                } else {
+                        gchar *strsize;
+
+                        strsize = gdu_util_get_size_for_display (largest_segment, FALSE);
 
-        dialog->priv->total_size = (guint64) gdu_size_widget_get_size (widget);
+                        if (whole_disk_is_uninitialized) {
+                                /* Translators: This is shown in the Details column.
+                                 * %s is the component size e.g. '42 GB'.
+                                 */
+                                markup = g_strdup_printf (_("Whole disk is uninitialized. %s available for use"),
+                                                          strsize);
+                        } else {
+                                if (!is_partitioned) {
+                                        /* Translators: This is shown in the Details column.
+                                         * %s is the component size e.g. '42 GB'.
+                                         */
+                                        markup = g_strdup_printf (_("%s available for use"), strsize);
+                                } else {
+                                        if (num_partitions == 0) {
+                                                /* Translators: This is shown in the Details column.
+                                                 * %s is the component size e.g. '42 GB'.
+                                                 */
+                                                markup = g_strdup_printf (_("The disk has no partitions. "
+                                                                            "%s available for use"),
+                                                                          strsize);
+                                        } else {
+                                                s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+                                                                                "The disk has %d partition",
+                                                                                "The disk has %d partitions",
+                                                                                num_partitions),
+                                                                     num_partitions);
+                                                /* Translators: This is shown in the Details column.
+                                                 * First %s is the dngettext() result of "The disk has %d partitions.".
+                                                 * Second %s is the component size e.g. '42 GB'.
+                                                 */
+                                                markup = g_strdup_printf (_("%s. Largest contiguous free block is %s"),
+                                                                          s,
+                                                                          strsize);
+                                                g_free (s);
+                                        }
+                                }
+                        }
+
+                        g_free (strsize);
+                }
+
+                g_object_unref (d);
+        } else {
+                markup = g_strdup ("");
+        }
+
+
+        width = gtk_tree_view_column_get_fixed_width (GTK_TREE_VIEW_COLUMN (cell_layout));
+        g_warn_if_fail (width > 12);
+        width -= 12;
+
+        s = g_strconcat ("<small>",
+                         markup,
+                         "</small>",
+                         NULL);
+        g_object_set (renderer,
+                      "markup", s,
+                      "wrap-width", width,
+                      NULL);
+        g_free (s);
+
+        g_free (markup);
+        g_object_unref (p);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_size_widget_changed (GduSizeWidget *size_widget,
+                        gpointer       user_data)
+{
+        GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
+        GList *l;
 
         update (dialog);
+
+        /* need to trigger row-changed for the selected disks since
+         * component size is listed in the "Details" column
+         */
+        for (l = dialog->priv->selected_drives; l != NULL; l = l->next) {
+                GduPresentable *p = GDU_PRESENTABLE (l->data);
+                GtkTreePath *path;
+                GtkTreeIter iter;
+
+                gdu_pool_tree_model_get_iter_for_presentable (dialog->priv->model,
+                                                              p,
+                                                              &iter);
+
+                path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->priv->model),
+                                                &iter);
+                gtk_tree_model_row_changed (GTK_TREE_MODEL (dialog->priv->model),
+                                            path,
+                                            &iter);
+                gtk_tree_path_free (path);
+        }
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 gdu_create_linux_md_dialog_constructed (GObject *object)
 {
@@ -338,7 +877,6 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
         GtkWidget *combo_box;
         GtkWidget *vbox;
         GtkWidget *vbox2;
-        GtkWidget *spin_button;
         GtkWidget *size_widget;
         gint row;
         gboolean ret;
@@ -358,16 +896,17 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
 
         gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
         button = gtk_dialog_add_button (GTK_DIALOG (dialog),
-                                        _("Cr_eate"),
+                                        _("C_reate"),
                                         GTK_RESPONSE_OK);
         gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
 
         content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
         gtk_container_set_border_width (GTK_CONTAINER (content_area), 10);
 
-        //vbox = gtk_vbox_new (FALSE, 0);
-        //gtk_container_add (GTK_CONTAINER (content_area), vbox);
         vbox = content_area;
+        gtk_box_set_spacing (GTK_BOX (vbox), 6);
+
+        /* -------------------------------------------------------------------------------- */
 
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
@@ -392,93 +931,127 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
         /*  RAID level  */
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Level:"));
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("RAID _Level:"));
         gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
                           GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
         combo_box = gtk_combo_box_new_text ();
-        /* keep in sync with on_combo_box_changed() */
-        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-                                   _("Concatenated"));
-        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-                                   _("Striped (RAID 0)"));
-        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-                                   _("Mirrored (RAID 1)"));
-        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-                                   _("RAID 4"));
-        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-                                   _("RAID 5"));
-        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-                                   _("RAID 6"));
-        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
-                                   _("RAID 10"));
-        gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 2);
-        dialog->priv->level = g_strdup ("raid1");
+        dialog->priv->level_combo_box = combo_box;
+        /* keep in sync with on_level_combo_box_changed() */
+        s = gdu_linux_md_get_raid_level_for_display ("raid0", TRUE);
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box), s);
+        g_free (s);
+        s = gdu_linux_md_get_raid_level_for_display ("raid1", TRUE);
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box), s);
+        g_free (s);
+        s = gdu_linux_md_get_raid_level_for_display ("raid5", TRUE);
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box), s);
+        g_free (s);
+        s = gdu_linux_md_get_raid_level_for_display ("raid6", TRUE);
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box), s);
+        g_free (s);
+        g_signal_connect (combo_box,
+                          "changed",
+                          G_CALLBACK (on_level_combo_box_changed),
+                          dialog);
+
         gtk_table_attach (GTK_TABLE (table), combo_box, 1, 2, row, row +1,
                           GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
         gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
         row++;
 
-        /*  array name  */
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Name:"));
+        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+        gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row +1,
+                          GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        dialog->priv->level_desc_label = label;
+        row++;
+
+        /*  Array name  */
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("Array _Name:"));
         gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
                           GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
         entry = gtk_entry_new ();
-        /* Translators: Keep length of translation of "New RAID Device" to less than 32 characters */
-        gtk_entry_set_text (GTK_ENTRY (entry), _("New RAID Device"));
+        /* Translators: This is the default name to use for the new array.
+         * Keep length of UTF-8 representation of the translation of "New RAID Array" to less than
+         * 32 bytes since that's the on-disk-format limit.
+         */
+        gtk_entry_set_text (GTK_ENTRY (entry), _("New RAID Array"));
         gtk_entry_set_max_length (GTK_ENTRY (entry), 32); /* on-disk-format restriction */
+        g_signal_connect (entry,
+                          "activate",
+                          G_CALLBACK (on_name_entry_activated),
+                          dialog);
+
         gtk_table_attach (GTK_TABLE (table), entry, 1, 2, row, row + 1,
                           GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
         gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
         dialog->priv->name_entry = entry;
         row++;
 
-        /* Number of components */
+        /*  Stripe Size  */
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("Number of _Disks:"));
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("Stripe S_ize:"));
         gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
                           GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-
-
-        spin_button = gtk_spin_button_new_with_range (2, 10000, 1);
-        dialog->priv->num_disks_spin_button = spin_button;
-        g_signal_connect (spin_button,
-                          "value-changed",
-                          G_CALLBACK (on_num_disks_spin_button_value_changed),
+        /* keep in sync with on_stripe_size_combo_box_changed() */
+        combo_box = gtk_combo_box_new_text ();
+        /* Translators: The following strings (4 KiB, 8 Kib, ..., 1 MiB) are for choosing the RAID stripe size.
+         * Since the rest of gnome-disk-utility use the sane 1k=1000 conventions and RAID needs the 1k=1024
+         * convenention (this is because disk block sizes are powers of two) we resort to the nerdy units.
+         */
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("4 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("8 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("16 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("32 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("64 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("128 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("256 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("512 KiB"));
+        gtk_combo_box_append_text (GTK_COMBO_BOX (combo_box),
+                                   _("1 MiB"));
+        dialog->priv->stripe_size = 64 * 1024;
+        g_signal_connect (combo_box,
+                          "changed",
+                          G_CALLBACK (on_stripe_size_combo_box_changed),
                           dialog);
 
-        align = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
-        gtk_container_add (GTK_CONTAINER (align), spin_button);
-
-        gtk_table_attach (GTK_TABLE (table),
-                          align,
-                          1, 2,
-                          row, row + 1,
-                          GTK_EXPAND | GTK_FILL,
-                          GTK_EXPAND | GTK_FILL, 2, 2);
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
+        gtk_table_attach (GTK_TABLE (table), combo_box, 1, 2, row, row +1,
+                          GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
+        dialog->priv->stripe_size_label = label;
+        dialog->priv->stripe_size_combo_box = combo_box;
         row++;
 
-        /* Size */
+        /*  Array size  */
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
         gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("Array _Size:"));
         gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
                           GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
 
-        size_widget = gdu_size_widget_new (1000 * 1000,
-                                           1000 * 1000,
-                                           10 * 1000 * 1000);
-        dialog->priv->size_widget = size_widget;
+        size_widget = gdu_size_widget_new (0,
+                                           0,
+                                           0);
         g_signal_connect (size_widget,
                           "changed",
                           G_CALLBACK (on_size_widget_changed),
                           dialog);
-
         gtk_table_attach (GTK_TABLE (table), size_widget, 1, 2, row, row + 1,
                           GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        dialog->priv->size_label = label;
+        dialog->priv->size_widget = size_widget;
         gtk_label_set_mnemonic_widget (GTK_LABEL (label), size_widget);
         row++;
 
@@ -487,13 +1060,88 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
         /* Tree view for showing selected volumes */
         GtkWidget *tree_view;
         GtkWidget *scrolled_window;
+        GtkCellRenderer *renderer;
+        GtkTreeViewColumn *column;
 
-        dialog->priv->model = gdu_pool_tree_model_new (dialog->priv->pool);
+        dialog->priv->model = gdu_pool_tree_model_new (dialog->priv->pool,
+                                                       GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES |
+                                                       GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES);
 
-        tree_view = gdu_pool_tree_view_new (dialog->priv->model,
-                                            GDU_POOL_TREE_VIEW_FLAGS_SHOW_TOGGLE);
+        tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (dialog->priv->model));
+        gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
         dialog->priv->tree_view = tree_view;
 
+        column = gtk_tree_view_column_new ();
+        /* Tranlators: this string is used for the column header */
+        gtk_tree_view_column_set_title (column, _("Use"));
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+        renderer = gtk_cell_renderer_toggle_new ();
+        gtk_tree_view_column_pack_start (column,
+                                         renderer,
+                                         FALSE);
+        g_signal_connect (renderer,
+                          "toggled",
+                          G_CALLBACK (on_disk_toggled),
+                          dialog);
+        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+                                            renderer,
+                                            toggle_data_func,
+                                            dialog,
+                                            NULL);
+
+
+        column = gtk_tree_view_column_new ();
+        /* Tranlators: this string is used for the column header */
+        gtk_tree_view_column_set_title (column, _("Disk"));
+        gtk_tree_view_column_set_expand (column, TRUE);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+        renderer = gtk_cell_renderer_pixbuf_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_column_set_attributes (column,
+                                             renderer,
+                                             "gicon", GDU_POOL_TREE_MODEL_COLUMN_ICON,
+                                             NULL);
+        g_object_set (renderer,
+                      "stock-size", GTK_ICON_SIZE_DIALOG,
+                      NULL);
+
+        renderer = gtk_cell_renderer_text_new ();
+        gtk_tree_view_column_pack_start (column, renderer, TRUE);
+        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+                                            renderer,
+                                            disk_name_data_func,
+                                            dialog,
+                                            NULL);
+
+        column = gtk_tree_view_column_new ();
+        /* Tranlators: this string is used for the column header */
+        gtk_tree_view_column_set_title (column, _("Details"));
+        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+        gtk_tree_view_column_set_min_width (column, 170);
+        gtk_tree_view_column_set_max_width (column, 170);
+        gtk_tree_view_column_set_fixed_width (column, 170);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+        renderer = gtk_cell_renderer_text_new ();
+        gtk_tree_view_column_pack_end (column, renderer, FALSE);
+        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+                                            renderer,
+                                            notes_data_func,
+                                            dialog,
+                                            NULL);
+        g_object_set (renderer,
+                      "xalign", 0.0,
+                      "yalign", 0.0,
+                      "wrap-mode", PANGO_WRAP_WORD_CHAR,
+                      NULL);
+
+        gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (tree_view), FALSE);
+        gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (tree_view), 16);
+        gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+
         scrolled_window = gtk_scrolled_window_new (NULL, NULL);
         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
                                         GTK_POLICY_NEVER,
@@ -505,7 +1153,7 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
 
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        s = g_strconcat ("<b>", _("Components"), "</b>", NULL);
+        s = g_strconcat ("<b>", _("Disks"), "</b>", NULL);
         gtk_label_set_markup (GTK_LABEL (label), s);
         g_free (s);
         gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
@@ -520,15 +1168,9 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
 
         /* -------------------------------------------------------------------------------- */
 
-        g_signal_connect (combo_box,
-                          "changed",
-                          G_CALLBACK (on_combo_box_changed),
-                          dialog);
 
-        g_signal_connect (dialog->priv->name_entry,
-                          "activate",
-                          G_CALLBACK (on_name_entry_activated),
-                          dialog);
+
+        /* -------------------------------------------------------------------------------- */
 
         gtk_widget_grab_focus (dialog->priv->name_entry);
         gtk_editable_select_region (GTK_EDITABLE (dialog->priv->name_entry), 0, 1000);
@@ -578,15 +1220,12 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
         dialog->priv->tip_label = label;
         gtk_widget_set_no_show_all (hbox, TRUE);
 
-        /* update the dialog */
-        update (dialog);
-
-        /* and start out with selecting max size */
-        gdu_size_widget_set_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
-                                  dialog->priv->available_total_size);
+        /* Calls on_level_combo_box_changed() which calls update() */
+        gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->level_combo_box), 0);
+        gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->stripe_size_combo_box), 4);
 
         /* select a sane size for the dialog and allow resizing */
-        gtk_widget_set_size_request (GTK_WIDGET (dialog), 400, 450);
+        gtk_widget_set_size_request (GTK_WIDGET (dialog), 500, 550);
         gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
 
         if (G_OBJECT_CLASS (gdu_create_linux_md_dialog_parent_class)->constructed != NULL)
@@ -610,6 +1249,10 @@ on_presentable_removed (GduPool          *pool,
                         gpointer          user_data)
 {
         GduCreateLinuxMdDialog *dialog = GDU_CREATE_LINUX_MD_DIALOG (user_data);
+
+        if (drive_is_selected (dialog, presentable))
+                drive_remove (dialog, presentable);
+
         update (dialog);
 }
 
@@ -653,300 +1296,236 @@ on_row_inserted (GtkTreeModel *tree_model,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static gint
-guint64_compare (gconstpointer a,
-                 gconstpointer b)
-{
-        guint64 va, vb;
-        va = *((guint64 *) a);
-        vb = *((guint64 *) b);
-        if (va > vb)
-                return 1;
-        else if (va < vb)
-                return -1;
-        else
-                return 0;
-}
-
 static gboolean
-get_selected_foreach_func (GtkTreeModel *model,
-                           GtkTreePath  *path,
-                           GtkTreeIter  *iter,
-                           gpointer      user_data)
+count_num_available_disks_func (GtkTreeModel *model,
+                                GtkTreePath  *path,
+                                GtkTreeIter  *iter,
+                                gpointer      data)
 {
-        GList **ret = user_data;
-        gboolean toggled;
-        GduPresentable *presentable;
+        GduPresentable *p;
+        guint *num_available_disks = data;
 
         gtk_tree_model_get (model,
                             iter,
-                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &presentable,
-                            GDU_POOL_TREE_MODEL_COLUMN_TOGGLED, &toggled,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
                             -1);
-        if (presentable != NULL) {
-                if (toggled)
-                        *ret = g_list_prepend (*ret, g_object_ref (presentable));
-                g_object_unref (presentable);
-        }
 
-        return FALSE; /* keep iterating */
-}
+        if (GDU_IS_DRIVE (p))
+                *num_available_disks = *num_available_disks + 1;
 
+        g_object_unref (p);
 
-static GList *
-get_selected_presentables (GduCreateLinuxMdDialog *dialog)
-{
-        GList *ret;
-        ret = NULL;
-        gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->priv->model),
-                                get_selected_foreach_func,
-                                &ret);
-        return ret;
+        return FALSE;
 }
 
 static void
-update (GduCreateLinuxMdDialog *dialog)
+get_sizes (GduCreateLinuxMdDialog *dialog,
+           guint                  *out_num_disks,
+           guint                  *out_num_available_disks,
+           guint64                *out_component_size,
+           guint64                *out_array_size,
+           guint64                *out_max_component_size,
+           guint64                *out_max_array_size)
 {
+        guint num_disks;
+        guint num_available_disks;
+        guint64 component_size;
+        guint64 array_size;
+        guint64 max_component_size;
+        guint64 max_array_size;
+        gdouble factor;
         GList *l;
-        GList *presentables;
-        GHashTable *map_disks_to_biggest_component_size;
-        GList *selected_presentables;
-        GList *drives_for_selected_presentables;
-        gboolean can_create;
-        guint num_toggled;
-        gchar *tip_text;
-        const gchar *tip_stock_icon;
 
-        tip_text = NULL;
-        tip_stock_icon = NULL;
-
-        can_create = FALSE;
+        num_disks = 0;
+        num_available_disks = 0;
+        max_component_size = G_MAXUINT64;
 
-        if (dialog->priv->num_disks < 2)
-                dialog->priv->num_disks = 2;
-
-        presentables = gdu_pool_get_presentables (dialog->priv->pool);
-        selected_presentables = get_selected_presentables (dialog);
-        drives_for_selected_presentables = NULL;
-        for (l = selected_presentables; l != NULL; l = l->next) {
+        for (l = dialog->priv->selected_drives; l != NULL; l = l->next) {
                 GduPresentable *p = GDU_PRESENTABLE (l->data);
-                GduPresentable *drive;
+                guint64 largest_segment;
+                gboolean whole_disk_is_uninitialized;
 
-                drive = gdu_presentable_get_toplevel (p);
-                if (drive == NULL)
-                        continue;
+                g_warn_if_fail (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
+                                                                 &whole_disk_is_uninitialized,
+                                                                 &largest_segment,
+                                                                 NULL));
 
-                g_object_unref (drive); /* don't own the ref */
-                if (!GDU_IS_DRIVE (drive))
-                        continue;
+                if (largest_segment < max_component_size)
+                        max_component_size = largest_segment;
 
-                if (g_list_find (drives_for_selected_presentables, drive) == NULL)
-                        drives_for_selected_presentables = g_list_prepend (drives_for_selected_presentables, drive);
+                num_disks++;
         }
-
-        /* hash from drive to largest free component */
-        map_disks_to_biggest_component_size = g_hash_table_new_full ((GHashFunc) gdu_presentable_hash,
-                                                                     (GEqualFunc) gdu_presentable_equals,
-                                                                     g_object_unref,
-                                                                     g_free);
-        for (l = presentables; l != NULL; l = l->next) {
-                GduPresentable *p = GDU_PRESENTABLE (l->data);
-                GduPresentable *drive;
-                guint64 size;
-                guint64 *existing_size;
-
-                if (gdu_presentable_is_allocated (p))
-                        continue;
-
-                drive = gdu_presentable_get_toplevel (p);
-                if (drive == NULL)
-                        continue;
-
-                g_object_unref (drive); /* don't own the ref */
-                if (!GDU_IS_DRIVE (drive))
-                        continue;
-
-                size = gdu_presentable_get_size (p);
-
-                existing_size = g_hash_table_lookup (map_disks_to_biggest_component_size,
-                                                     drive);
-                if ((existing_size == NULL) || (existing_size != NULL && (*existing_size) > size)) {
-                        g_hash_table_insert (map_disks_to_biggest_component_size,
-                                             g_object_ref (drive),
-                                             g_memdup (&size, sizeof (guint64)));
+        if (max_component_size == G_MAXUINT64)
+                max_component_size = 0;
+
+        factor = 0.0;
+        if (num_disks > 1) {
+                if (g_strcmp0 (dialog->priv->level, "raid0") == 0) {
+                        factor = num_disks;
+                } else if (g_strcmp0 (dialog->priv->level, "raid1") == 0) {
+                        factor = 1.0;
+                } else if (g_strcmp0 (dialog->priv->level, "raid5") == 0) {
+                        if (num_disks > 1)
+                                factor = num_disks - 1;
+                } else if (g_strcmp0 (dialog->priv->level, "raid6") == 0) {
+                        if (num_disks > 2)
+                                factor = num_disks - 2;
+                } else {
+                        g_assert_not_reached ();
                 }
         }
+        max_array_size = max_component_size * factor;
+        array_size = gdu_size_widget_get_size (GDU_SIZE_WIDGET (dialog->priv->size_widget));
+        if (max_array_size > 0)
+                component_size = max_component_size * ( ((gdouble) array_size) / ((gdouble) max_array_size) );
+        else
+                component_size = 0;
 
-        dialog->priv->available_num_disks = g_hash_table_size (map_disks_to_biggest_component_size);
-
-        if (dialog->priv->num_disks > dialog->priv->available_num_disks) {
-                dialog->priv->available_total_size = 0;
-        } else {
-                GList *sizes;
-
-                sizes = g_hash_table_get_values (map_disks_to_biggest_component_size);
-                sizes = g_list_sort (sizes, guint64_compare);
-                sizes = g_list_reverse (sizes);
-                /* biggest is now first */
-
-                dialog->priv->available_total_size = dialog->priv->num_disks *
-                        (*((guint64 *) g_list_nth_data (sizes, dialog->priv->num_disks - 1)));
-
-                g_list_free (sizes);
-        }
-
-        /* clamp total_size and num_disks to what is available */
-        if (dialog->priv->total_size > dialog->priv->available_total_size)
-                dialog->priv->total_size = dialog->priv->available_total_size;
-        if (dialog->priv->num_disks > dialog->priv->available_num_disks)
-                dialog->priv->num_disks = dialog->priv->available_num_disks;
-
-        //if (dialog->priv->total_size == 0)
-        //        dialog->priv->total_size = dialog->priv->available_total_size;
-
-        g_debug ("==========");
-        g_debug ("available_num_disks = %d", dialog->priv->available_num_disks);
-        g_debug ("available_total_size = %" G_GUINT64_FORMAT, dialog->priv->available_total_size);
-        g_debug ("num_disks = %d", dialog->priv->num_disks);
-        g_debug ("total_size = %" G_GUINT64_FORMAT, dialog->priv->total_size);
-
-        if (dialog->priv->available_total_size == 0) {
-                gtk_widget_set_sensitive (dialog->priv->size_widget, FALSE);
-                gtk_widget_set_sensitive (dialog->priv->tree_view, FALSE);
-                tip_text = g_strdup (_("Not enough disks with available space. "
-                                       "Plug in more disks or make space available."));
-                tip_stock_icon = GTK_STOCK_DIALOG_ERROR;
-        } else {
-                gtk_widget_set_sensitive (dialog->priv->size_widget, TRUE);
-                gtk_widget_set_sensitive (dialog->priv->tree_view, TRUE);
-        }
+        gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->priv->model),
+                                count_num_available_disks_func,
+                                &num_available_disks);
 
-        /* set range for num_disks_spin_button according to what we've found out */
-        gtk_spin_button_set_range (GTK_SPIN_BUTTON (dialog->priv->num_disks_spin_button),
-                                   2.0,
-                                   dialog->priv->available_num_disks);
-        if (gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->num_disks_spin_button)) != dialog->priv->num_disks)
-                gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->num_disks_spin_button),
-                                           dialog->priv->num_disks);
-
-        /* ditto for the size widget */
-        gdu_size_widget_set_max_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
-                                      dialog->priv->available_total_size);
-        if (gdu_size_widget_get_size (GDU_SIZE_WIDGET (dialog->priv->size_widget)) != dialog->priv->total_size)
-                gdu_size_widget_set_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
-                                          dialog->priv->total_size);
+        if (out_num_disks != NULL)
+                *out_num_disks = num_disks;
 
-        /* --- */
+        if (out_num_available_disks != NULL)
+                *out_num_available_disks = num_available_disks;
 
-        /* now update the tree model toggles to make free space objects selectable */
-        num_toggled = 0;
-        for (l = presentables; l != NULL; l = l->next) {
-                GduPresentable *p = GDU_PRESENTABLE (l->data);
-                GduPresentable *drive;
-                guint64 size;
-                gboolean can_be_toggled;
-                GtkTreeIter iter;
-                gboolean cur_can_be_toggled;
-                gboolean cur_toggled;
+        if (out_component_size != NULL)
+                *out_component_size = component_size;
 
-                can_be_toggled = FALSE;
+        if (out_array_size != NULL)
+                *out_array_size = array_size;
 
-                if (gdu_presentable_is_allocated (p))
-                        goto determined;
+        if (out_max_component_size != NULL)
+                *out_max_component_size = max_component_size;
 
-                drive = gdu_presentable_get_toplevel (p);
-                if (drive == NULL)
-                        goto determined;
+        if (out_max_array_size != NULL)
+                *out_max_array_size = max_array_size;
+}
 
-                g_object_unref (drive); /* don't own the ref */
-                if (!GDU_IS_DRIVE (drive))
-                        goto determined;
+static void
+update (GduCreateLinuxMdDialog *dialog)
+{
+        gchar *tip_text;
+        const gchar *tip_stock_icon;
+        guint num_disks;
+        guint num_available_disks;
+        guint64 max_component_size;
+        guint64 max_array_size;
+        gboolean can_create;
+        gchar *level_str;
+        gboolean size_widget_was_sensitive;
+        guint64 array_size;
 
-                size = gdu_presentable_get_size (p);
+        tip_text = NULL;
+        tip_stock_icon = NULL;
+        can_create = FALSE;
 
-                if (size < dialog->priv->total_size / dialog->priv->num_disks)
-                        goto determined;
+        get_sizes (dialog,
+                   &num_disks,
+                   &num_available_disks,
+                   NULL,  /* component_size */
+                   &array_size,
+                   &max_component_size,
+                   &max_array_size);
 
-                /* don't allow selecting two volumes on the same drive */
-                if (g_list_find (drives_for_selected_presentables, drive) != NULL &&
-                    g_list_find (selected_presentables, p) == NULL)
-                        goto determined;
+        level_str = gdu_linux_md_get_raid_level_for_display (dialog->priv->level, FALSE);
 
-                can_be_toggled = TRUE;
+        size_widget_was_sensitive = gtk_widget_get_sensitive (dialog->priv->size_widget);
 
-        determined:
-                if (!gdu_pool_tree_model_get_iter_for_presentable (dialog->priv->model,
-                                                                   p,
-                                                                   &iter)) {
-                        g_warning ("Cannot find tree iter for presentable");
-                        continue;
-                }
+        if (num_available_disks < dialog->priv->num_disks_needed) {
+                gtk_widget_set_sensitive (dialog->priv->size_label, FALSE);
+                gtk_widget_set_sensitive (dialog->priv->size_widget, FALSE);
+                gdu_size_widget_set_max_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                              2000 * 1000);
+                gdu_size_widget_set_min_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                              1000 * 1000);
+                gdu_size_widget_set_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                          1000 * 1000);
 
-                /* only update if there's a change - otherwise we'll cause loops */
-                gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->model),
-                                    &iter,
-                                    GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED, &cur_can_be_toggled,
-                                    GDU_POOL_TREE_MODEL_COLUMN_TOGGLED, &cur_toggled,
-                                    -1);
-
-                if (cur_can_be_toggled != can_be_toggled) {
-                        gtk_tree_store_set (GTK_TREE_STORE (dialog->priv->model),
-                                            &iter,
-                                            GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED, can_be_toggled,
-                                            -1);
-                }
-                if (!can_be_toggled) {
-                        if (cur_toggled) {
-                                gtk_tree_store_set (GTK_TREE_STORE (dialog->priv->model),
-                                                    &iter,
-                                                    GDU_POOL_TREE_MODEL_COLUMN_TOGGLED, FALSE,
-                                                    -1);
-                                cur_toggled = FALSE;
-                        }
+                if (tip_text == NULL) {
+                        /* Translators: This is for the tip text shown in the dialog.
+                         * First %s is the short localized name for the RAID level, e.g. "RAID-1".
+                         */
+                        tip_text = g_strdup_printf (_("Insufficient number disks to create a %s array."),
+                                                    level_str);
+                        tip_stock_icon = GTK_STOCK_DIALOG_ERROR;
                 }
 
-                if (cur_toggled)
-                        num_toggled++;
-        }
+        } else if (num_disks < dialog->priv->num_disks_needed) {
 
-        /* --- */
+                gtk_widget_set_sensitive (dialog->priv->size_label, FALSE);
+                gtk_widget_set_sensitive (dialog->priv->size_widget, FALSE);
+                gdu_size_widget_set_max_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                              2000 * 1000);
+                gdu_size_widget_set_min_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                              1000 * 1000);
+                gdu_size_widget_set_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                          1000 * 1000);
 
-        if (num_toggled == dialog->priv->num_disks) {
-                can_create = TRUE;
                 if (tip_text == NULL) {
-                        if (dialog->priv->total_size < 1000 * 1000) {
-                                tip_text = g_strdup (_("Increase the size of the array."));
-                                tip_stock_icon = GTK_STOCK_DIALOG_INFO;
-                                can_create = FALSE;
+                        if (num_disks == 0) {
+                                tip_text = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+                                                                       "To create a %s array, select %d disks.",
+                                                                       "To create a %s array, select %d disks.",
+                                                                       dialog->priv->num_disks_needed - num_disks),
+                                                            level_str,
+                                                            dialog->priv->num_disks_needed - num_disks);
                         } else {
-                                tip_text = g_strdup (_("Array is ready to be created."));
-                                tip_stock_icon = GTK_STOCK_DIALOG_INFO;
+                                tip_text = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+                                                                       "To create a %s array, select %d more disks.",
+                                                                       "To create a %s array, select %d more disks.",
+                                                                       dialog->priv->num_disks_needed - num_disks),
+                                                            level_str,
+                                                            dialog->priv->num_disks_needed - num_disks);
                         }
-                }
-        } else if (num_toggled < dialog->priv->num_disks) {
-                if (tip_text == NULL) {
-                        tip_text = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
-                                                                 N_("Select one more component."),
-                                                                 N_("Select %d more components."),
-                                                                 dialog->priv->num_disks - num_toggled),
-                                                    dialog->priv->num_disks - num_toggled);
                         tip_stock_icon = GTK_STOCK_DIALOG_INFO;
                 }
+
         } else {
-                /* num_toggled > dialog->priv->num_disks */
+
+                gtk_widget_set_sensitive (dialog->priv->size_label, TRUE);
+                gtk_widget_set_sensitive (dialog->priv->size_widget, TRUE);
+                gdu_size_widget_set_max_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                              max_array_size);
+                gdu_size_widget_set_min_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                              1000 * 1000);
+                if (!size_widget_was_sensitive)
+                        gdu_size_widget_set_size (GDU_SIZE_WIDGET (dialog->priv->size_widget),
+                                                  max_array_size);
+
                 if (tip_text == NULL) {
-                        tip_text = g_strdup_printf (g_dngettext (GETTEXT_PACKAGE,
-                                                                 N_("Deselect one more component."),
-                                                                 N_("Deselect %d more components."),
-                                                                 dialog->priv->num_disks - num_toggled),
-                                                    dialog->priv->num_disks - num_toggled);
+                        gchar *strsize;
+
+                        strsize = gdu_util_get_size_for_display (array_size, FALSE);
+                        /* Translators: This is for the tip text shown in the dialog.
+                         * First %s is the size e.g. '42 GB'.
+                         * Second %s is the short localized name for the RAID level, e.g. "RAID-1".
+                         * Third parameter is the number of disks to use (always greater than 1).
+                         */
+                        tip_text = g_strdup_printf (_("To create a %s %s array on %d disks, press \"Create\""),
+                                                    strsize,
+                                                    level_str,
+                                                    num_disks);
                         tip_stock_icon = GTK_STOCK_DIALOG_INFO;
+
+                        can_create = TRUE;
+
+                        g_free (strsize);
                 }
         }
 
-        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
-                                           GTK_RESPONSE_OK,
-                                           can_create);
+        if (g_strcmp0 (dialog->priv->level, "raid0") == 0 ||
+            g_strcmp0 (dialog->priv->level, "raid5") == 0 ||
+            g_strcmp0 (dialog->priv->level, "raid6") == 0) {
+                gtk_widget_set_sensitive (dialog->priv->stripe_size_label, TRUE);
+                gtk_widget_set_sensitive (dialog->priv->stripe_size_combo_box, TRUE);
+        } else {
+                gtk_widget_set_sensitive (dialog->priv->stripe_size_label, FALSE);
+                gtk_widget_set_sensitive (dialog->priv->stripe_size_combo_box, FALSE);
+        }
+
 
         if (tip_text != NULL) {
                 gchar *s;
@@ -968,15 +1547,9 @@ update (GduCreateLinuxMdDialog *dialog)
                 gtk_widget_hide (dialog->priv->tip_label);
         }
 
-        /* --- */
+        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
+                                           GTK_RESPONSE_OK,
+                                           can_create);
 
-        g_list_foreach (presentables, (GFunc) g_object_unref, NULL);
-        g_list_free (presentables);
-        g_list_foreach (selected_presentables, (GFunc) g_object_unref, NULL);
-        g_list_free (selected_presentables);
-        g_list_free (drives_for_selected_presentables);
-        g_hash_table_unref (map_disks_to_biggest_component_size);
-        g_free (tip_text);
+        g_free (level_str);
 }
-
-/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu-gtk/gdu-create-linux-md-dialog.h b/src/gdu-gtk/gdu-create-linux-md-dialog.h
index 51420e6..367a928 100644
--- a/src/gdu-gtk/gdu-create-linux-md-dialog.h
+++ b/src/gdu-gtk/gdu-create-linux-md-dialog.h
@@ -50,11 +50,15 @@ struct GduCreateLinuxMdDialogClass
         GtkDialogClass parent_class;
 };
 
-GType       gdu_create_linux_md_dialog_get_type  (void) G_GNUC_CONST;
-GtkWidget*  gdu_create_linux_md_dialog_new       (GtkWindow               *parent,
-                                                  GduPool                 *pool);
-gchar      *gdu_create_linux_md_dialog_get_level (GduCreateLinuxMdDialog  *dialog);
-gchar      *gdu_create_linux_md_dialog_get_name  (GduCreateLinuxMdDialog  *dialog);
+GType       gdu_create_linux_md_dialog_get_type           (void) G_GNUC_CONST;
+GtkWidget*  gdu_create_linux_md_dialog_new                (GtkWindow               *parent,
+                                                           GduPool                 *pool);
+gchar      *gdu_create_linux_md_dialog_get_level          (GduCreateLinuxMdDialog  *dialog);
+gchar      *gdu_create_linux_md_dialog_get_name           (GduCreateLinuxMdDialog  *dialog);
+guint64     gdu_create_linux_md_dialog_get_size           (GduCreateLinuxMdDialog  *dialog);
+guint64     gdu_create_linux_md_dialog_get_component_size (GduCreateLinuxMdDialog  *dialog);
+guint64     gdu_create_linux_md_dialog_get_stripe_size    (GduCreateLinuxMdDialog  *dialog);
+GPtrArray  *gdu_create_linux_md_dialog_get_drives         (GduCreateLinuxMdDialog  *dialog);
 
 G_END_DECLS
 
diff --git a/src/gdu-gtk/gdu-gtk-enums.h b/src/gdu-gtk/gdu-gtk-enums.h
index 9f2cc66..938f36c 100644
--- a/src/gdu-gtk/gdu-gtk-enums.h
+++ b/src/gdu-gtk/gdu-gtk-enums.h
@@ -30,25 +30,27 @@
 
 /**
  * GduPoolTreeModelColumn:
- * @GDU_POOL_TREE_MODEL_COLUMN_ICON: The icon for the presentable.
- * @GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME: Name for the presentable derived from Vital Product Data,
- * e.g. "ATA INTEL SSDSA2MH080G1GC".
+ * @GDU_POOL_TREE_MODEL_COLUMN_ICON: The #GIcon for the presentable.
  * @GDU_POOL_TREE_MODEL_COLUMN_NAME: Human readable name of the presentable, e.g. "80 GB Solid-state Disk" or
  * "Fedora (Rawhide)".
+ * @GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME: Name for the presentable derived from Vital Product Data,
+ * e.g. "ATA INTEL SSDSA2MH080G1GC".
  * @GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION: Human readable description of the presentable, e.g. "MBR Partition Table"
  * or "32GB Linux ext3".
  * @GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE: The #GduPresentable object.
- * @GDU_POOL_TREE_MODEL_COLUMN_TOGGLED: Whether the item can be toggled.
- * @GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED: Whether the item is toggled.
+ * @GDU_POOL_TREE_MODEL_COLUMN_VISIBLE: Whether the item is visible.
+ * @GDU_POOL_TREE_MODEL_COLUMN_TOGGLED: Whether the item is toggled.
+ * @GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED: Whether the item can be toggled.
  *
  * Columns used in #GduPoolTreeModel.
  */
 typedef enum {
         GDU_POOL_TREE_MODEL_COLUMN_ICON,
-        GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME,
         GDU_POOL_TREE_MODEL_COLUMN_NAME,
+        GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME,
         GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION,
         GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE,
+        GDU_POOL_TREE_MODEL_COLUMN_VISIBLE,
         GDU_POOL_TREE_MODEL_COLUMN_TOGGLED,
         GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED,
 } GduPoolTreeModelColumn;
@@ -58,4 +60,18 @@ typedef enum {
         GDU_POOL_TREE_VIEW_FLAGS_SHOW_TOGGLE = (1<<0),
 } GduPoolTreeViewFlags;
 
+/**
+ * GduPoolTreeModelFlags:
+ * @GDU_POOL_TREE_MODEL_FLAGS_NONE: No flags set.
+ * @GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES: Don't include presentables representing volumes or holes.
+ * @GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES: Don't include drives that cannot be allocated to e.g. a RAID array.
+ *
+ * Flags used when creating a #GduPoolTreeModel.
+ */
+typedef enum {
+        GDU_POOL_TREE_MODEL_FLAGS_NONE                      = 0,
+        GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES                = (1<<0),
+        GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES   = (1<<2),
+} GduPoolTreeModelFlags;
+
 #endif /* GDU_GTK_ENUMS_H */
diff --git a/src/gdu-gtk/gdu-pool-tree-model.c b/src/gdu-gtk/gdu-pool-tree-model.c
index 56368fa..a53d0e4 100644
--- a/src/gdu-gtk/gdu-pool-tree-model.c
+++ b/src/gdu-gtk/gdu-pool-tree-model.c
@@ -30,6 +30,7 @@
 struct GduPoolTreeModelPrivate
 {
         GduPool *pool;
+        GduPoolTreeModelFlags flags;
 };
 
 G_DEFINE_TYPE (GduPoolTreeModel, gdu_pool_tree_model, GTK_TYPE_TREE_STORE)
@@ -38,6 +39,7 @@ enum
 {
         PROP_0,
         PROP_POOL,
+        PROP_FLAGS,
 };
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -70,6 +72,10 @@ gdu_pool_tree_model_set_property (GObject      *object,
                 model->priv->pool = g_value_dup_object (value);
                 break;
 
+        case PROP_FLAGS:
+                model->priv->flags = g_value_get_flags (value);
+                break;
+
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -89,6 +95,10 @@ gdu_pool_tree_model_get_property (GObject     *object,
                 g_value_set_object (value, model->priv->pool);
                 break;
 
+        case PROP_FLAGS:
+                g_value_set_flags (value, model->priv->flags);
+                break;
+
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -142,17 +152,18 @@ static void
 gdu_pool_tree_model_constructed (GObject *object)
 {
         GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (object);
-        GType column_types[7];
+        GType column_types[8];
         GList *presentables;
         GList *l;
 
-        column_types[0] = GDK_TYPE_PIXBUF;
+        column_types[0] = G_TYPE_ICON;
         column_types[1] = G_TYPE_STRING;
         column_types[2] = G_TYPE_STRING;
         column_types[3] = G_TYPE_STRING;
         column_types[4] = GDU_TYPE_PRESENTABLE;
         column_types[5] = G_TYPE_BOOLEAN;
         column_types[6] = G_TYPE_BOOLEAN;
+        column_types[7] = G_TYPE_BOOLEAN;
 
         gtk_tree_store_set_column_types (GTK_TREE_STORE (object),
                                          G_N_ELEMENTS (column_types),
@@ -222,6 +233,22 @@ gdu_pool_tree_model_class_init (GduPoolTreeModelClass *klass)
                                                               G_PARAM_WRITABLE |
                                                               G_PARAM_READABLE |
                                                               G_PARAM_CONSTRUCT_ONLY));
+
+        /**
+         * GduPoolTreeModel:flags:
+         *
+         * The flags for the model.
+         */
+        g_object_class_install_property (gobject_class,
+                                         PROP_FLAGS,
+                                         g_param_spec_flags ("flags",
+                                                             NULL,
+                                                             NULL,
+                                                             GDU_TYPE_POOL_TREE_MODEL_FLAGS,
+                                                             GDU_POOL_TREE_MODEL_FLAGS_NONE,
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
@@ -231,10 +258,12 @@ gdu_pool_tree_model_init (GduPoolTreeModel *model)
 }
 
 GduPoolTreeModel *
-gdu_pool_tree_model_new (GduPool *pool)
+gdu_pool_tree_model_new (GduPool               *pool,
+                         GduPoolTreeModelFlags  flags)
 {
         return GDU_POOL_TREE_MODEL (g_object_new (GDU_TYPE_POOL_TREE_MODEL,
                                                   "pool", pool,
+                                                  "flags", flags,
                                                   NULL));
 }
 
@@ -305,7 +334,7 @@ set_data_for_presentable (GduPoolTreeModel *model,
                           GduPresentable   *presentable)
 {
         GduDevice *device;
-        GdkPixbuf *pixbuf;
+        GIcon *icon;
         gchar *vpd_name;
         gchar *name;
         gchar *desc;
@@ -314,27 +343,24 @@ set_data_for_presentable (GduPoolTreeModel *model,
 
         name = gdu_presentable_get_name (presentable);
         desc = gdu_presentable_get_description (presentable);
+        vpd_name = gdu_presentable_get_vpd_name (presentable);
 
-        // TODO:
-        //vpd_name = gdu_presentable_get_vpd_name (presentable);
-        vpd_name = g_strdup ("foo");
-
-        pixbuf = gdu_util_get_pixbuf_for_presentable (presentable, GTK_ICON_SIZE_SMALL_TOOLBAR);
+        icon = gdu_presentable_get_icon (presentable);
 
         /* TODO: insert NAME */
         gtk_tree_store_set (GTK_TREE_STORE (model),
                             iter,
-                            GDU_POOL_TREE_MODEL_COLUMN_ICON, pixbuf,
+                            GDU_POOL_TREE_MODEL_COLUMN_ICON, icon,
                             GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME, vpd_name,
                             GDU_POOL_TREE_MODEL_COLUMN_NAME, name,
                             GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION, desc,
                             GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, presentable,
+                            GDU_POOL_TREE_MODEL_COLUMN_VISIBLE, TRUE,
                             GDU_POOL_TREE_MODEL_COLUMN_TOGGLED, FALSE,
                             GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED, FALSE,
                             -1);
 
-        if (pixbuf != NULL)
-                g_object_unref (pixbuf);
+        g_object_unref (icon);
         g_free (vpd_name);
         g_free (name);
         g_free (desc);
@@ -342,6 +368,32 @@ set_data_for_presentable (GduPoolTreeModel *model,
                 g_object_unref (device);
 }
 
+static gboolean
+should_include_presentable (GduPoolTreeModel *model,
+                            GduPresentable   *presentable)
+{
+        gboolean ret;
+
+        ret = FALSE;
+
+        /* see if it should be ignored because it is a volume */
+        if ((model->priv->flags & GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES) &&
+            (GDU_IS_VOLUME (presentable) || GDU_IS_VOLUME_HOLE (presentable)))
+                goto out;
+
+        if (GDU_IS_DRIVE (presentable)) {
+                if ((model->priv->flags & GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES) &&
+                    (!gdu_drive_has_unallocated_space (GDU_DRIVE (presentable), NULL, NULL, NULL)))
+                        goto out;
+        }
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
+
 static void
 add_presentable (GduPoolTreeModel *model,
                  GduPresentable   *presentable,
@@ -356,6 +408,9 @@ add_presentable (GduPoolTreeModel *model,
         if (gdu_pool_tree_model_get_iter_for_presentable (model, presentable, NULL))
                 goto out;
 
+        if (!should_include_presentable (model, presentable))
+                goto out;
+
         /* set up parent relationship */
         parent_iter = NULL;
         enclosing_presentable = gdu_presentable_get_enclosing_presentable (presentable);
@@ -421,6 +476,9 @@ on_presentable_changed (GduPool          *pool,
         GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (user_data);
         GtkTreeIter iter;
 
+        /* will do NOP if presentable has already been added */
+        add_presentable (model, presentable, NULL);
+
         /* update name and icon */
         if (gdu_pool_tree_model_get_iter_for_presentable (model, presentable, &iter)) {
 
diff --git a/src/gdu-gtk/gdu-pool-tree-model.h b/src/gdu-gtk/gdu-pool-tree-model.h
index 2e911de..970fa5c 100644
--- a/src/gdu-gtk/gdu-pool-tree-model.h
+++ b/src/gdu-gtk/gdu-pool-tree-model.h
@@ -53,10 +53,11 @@ struct GduPoolTreeModelClass
 };
 
 
-GType             gdu_pool_tree_model_get_type                 (void);
-GduPoolTreeModel *gdu_pool_tree_model_new                      (GduPool *pool);
-gboolean          gdu_pool_tree_model_get_iter_for_presentable (GduPoolTreeModel *model,
-                                                                GduPresentable   *presentable,
-                                                                GtkTreeIter      *out_iter);
+GType             gdu_pool_tree_model_get_type                 (void) G_GNUC_CONST;
+GduPoolTreeModel *gdu_pool_tree_model_new                      (GduPool               *pool,
+                                                                GduPoolTreeModelFlags  flags);
+gboolean          gdu_pool_tree_model_get_iter_for_presentable (GduPoolTreeModel      *model,
+                                                                GduPresentable        *presentable,
+                                                                GtkTreeIter           *out_iter);
 
 #endif /* GDU_POOL_TREE_MODEL_H */
diff --git a/src/gdu-gtk/gdu-pool-tree-view.c b/src/gdu-gtk/gdu-pool-tree-view.c
index ccb1264..1cab240 100644
--- a/src/gdu-gtk/gdu-pool-tree-view.c
+++ b/src/gdu-gtk/gdu-pool-tree-view.c
@@ -147,7 +147,9 @@ format_markup (GtkCellLayout   *cell_layout,
         GduPoolTreeView *view = GDU_POOL_TREE_VIEW (user_data);
         GtkTreeSelection *tree_selection;
         gchar *name;
+        gchar *vpd_name;
         gchar *desc;
+        GduPresentable *p;
         gchar *markup;
         GtkStyle *style;
         GdkColor desc_gdk_color = {0};
@@ -158,7 +160,9 @@ format_markup (GtkCellLayout   *cell_layout,
 
         gtk_tree_model_get (tree_model,
                             iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
                             GDU_POOL_TREE_MODEL_COLUMN_NAME, &name,
+                            GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME, &vpd_name,
                             GDU_POOL_TREE_MODEL_COLUMN_DESCRIPTION, &desc,
                             -1);
 
@@ -185,11 +189,23 @@ format_markup (GtkCellLayout   *cell_layout,
                                       (desc_gdk_color.green >> 8),
                                       (desc_gdk_color.blue >> 8));
 
-        markup = g_strdup_printf ("<b>%s</b>\n"
-                                  "<span fgcolor=\"%s\"><small>%s</small></span>",
-                                  name,
-                                  desc_color,
-                                  desc);
+        /* Only include VPD name for drives */
+        if (GDU_IS_DRIVE (p)) {
+                markup = g_strdup_printf ("<b>%s</b>\n"
+                                          "<span fgcolor=\"%s\"><small>%s\n%s</small></span>",
+                                          name,
+                                          desc_color,
+                                          vpd_name,
+                                          desc);
+        } else {
+                markup = g_strdup_printf ("<small>"
+                                          "<b>%s</b>\n"
+                                          "<span fgcolor=\"%s\">%s</span>"
+                                          "</small>",
+                                          name,
+                                          desc_color,
+                                          desc);
+        }
 
         g_object_set (renderer,
                       "markup", markup,
@@ -197,8 +213,65 @@ format_markup (GtkCellLayout   *cell_layout,
 
         g_free (name);
         g_free (desc);
+        g_free (vpd_name);
         g_free (markup);
         g_free (desc_color);
+        g_object_unref (p);
+}
+
+static void
+pixbuf_data_func (GtkCellLayout   *cell_layout,
+                  GtkCellRenderer *renderer,
+                  GtkTreeModel    *tree_model,
+                  GtkTreeIter     *iter,
+                  gpointer         user_data)
+{
+        GduPoolTreeView *view = GDU_POOL_TREE_VIEW (user_data);
+        GduPresentable *p;
+        GIcon *icon;
+
+        gtk_tree_model_get (tree_model,
+                            iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+                            GDU_POOL_TREE_MODEL_COLUMN_ICON, &icon,
+                            -1);
+
+#if 0
+        gint width, height;
+        GdkPixbuf *pixbuf;
+
+        gtk_tree_view_column_cell_get_size  (GTK_TREE_VIEW_COLUMN (cell_layout),
+                                             NULL,
+                                             NULL,
+                                             NULL,
+                                             &width,
+                                             &height);
+        //g_debug ("w=%d h=%d", width, height);
+
+        pixbuf = gdu_util_get_pixbuf_for_presentable_at_pixel_size (p,
+                                                                    height * 5 / 6);
+        g_object_set (renderer,
+                      "pixbuf", pixbuf,
+                      "width", 48,
+                      "height", 0,
+                      NULL);
+        g_object_unref (pixbuf);
+#else
+
+        GtkIconSize size;
+        size = GTK_ICON_SIZE_SMALL_TOOLBAR;
+        if (GDU_IS_VOLUME (p) || GDU_IS_VOLUME_HOLE (p)) {
+                size = GTK_ICON_SIZE_MENU;
+        }
+
+        g_object_set (renderer,
+                      "gicon", icon,
+                      "stock-size", size,
+                      NULL);
+#endif
+
+        g_object_unref (p);
+        g_object_unref (icon);
 }
 
 static void
@@ -219,7 +292,6 @@ gdu_pool_tree_view_constructed (GObject *object)
                                                  FALSE);
                 gtk_tree_view_column_set_attributes (column,
                                                      renderer,
-                                                     "visible", GDU_POOL_TREE_MODEL_COLUMN_CAN_BE_TOGGLED,
                                                      "active", GDU_POOL_TREE_MODEL_COLUMN_TOGGLED,
                                                      NULL);
                 g_signal_connect (renderer,
@@ -230,10 +302,11 @@ gdu_pool_tree_view_constructed (GObject *object)
 
         renderer = gtk_cell_renderer_pixbuf_new ();
         gtk_tree_view_column_pack_start (column, renderer, FALSE);
-        gtk_tree_view_column_set_attributes (column,
-                                             renderer,
-                                             "pixbuf", GDU_POOL_TREE_MODEL_COLUMN_ICON,
-                                             NULL);
+        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+                                            renderer,
+                                            pixbuf_data_func,
+                                            view,
+                                            NULL);
         if (view->priv->flags & GDU_POOL_TREE_VIEW_FLAGS_SHOW_TOGGLE) {
                 gtk_tree_view_column_add_attribute (column,
                                                     renderer,
@@ -262,6 +335,7 @@ gdu_pool_tree_view_constructed (GObject *object)
         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
 
         gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (view), FALSE);
+        gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (view), TRUE);
         gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (view), 16);
         gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
 
diff --git a/src/gdu-gtk/gdu-size-widget.c b/src/gdu-gtk/gdu-size-widget.c
index a5f9c17..6ed770a 100644
--- a/src/gdu-gtk/gdu-size-widget.c
+++ b/src/gdu-gtk/gdu-size-widget.c
@@ -55,6 +55,8 @@ guint signals[LAST_SIGNAL] = {0,};
 
 G_DEFINE_TYPE (GduSizeWidget, gdu_size_widget, GTK_TYPE_HBOX)
 
+static void update_stepping (GduSizeWidget *widget);
+
 static void
 gdu_size_widget_finalize (GObject *object)
 {
@@ -216,6 +218,8 @@ gdu_size_widget_constructed (GObject *object)
                           G_CALLBACK (on_query_tooltip),
                           widget);
 
+        update_stepping (widget);
+
         if (G_OBJECT_CLASS (gdu_size_widget_parent_class)->constructed != NULL)
                 G_OBJECT_CLASS (gdu_size_widget_parent_class)->constructed (object);
 }
diff --git a/src/gdu-gtk/gdu-time-label.c b/src/gdu-gtk/gdu-time-label.c
index a43d3fe..ffc055a 100644
--- a/src/gdu-gtk/gdu-time-label.c
+++ b/src/gdu-gtk/gdu-time-label.c
@@ -70,10 +70,18 @@ do_update (GduTimeLabel *time_label)
                 s = g_strdup_printf (_("Less than a minute ago"));
                 next_update = 60 - age;
         } else if (age < 60 * 60) {
-                s = g_strdup_printf (ngettext ("%d minute ago", "%d minutes ago", age / 60), age / 60);
+                s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+                                                "%d minute ago",
+                                                "%d minutes ago",
+                                                age / 60),
+                                     age / 60);
                 next_update = 60*(age/60 + 1) - age;
         } else {
-                s = g_strdup_printf (ngettext ("%d hour ago", "%d hours ago", age / 60 / 60), age / 60 / 60);
+                s = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+                                                "%d hour ago",
+                                                "%d hours ago",
+                                                age / 60 / 60),
+                                     age / 60 / 60);
                 next_update = 60*60*(age/(60*60) + 1) - age;
         }
         gtk_label_set_text (GTK_LABEL (time_label), s);
diff --git a/src/gdu/gdu-callbacks.h b/src/gdu/gdu-callbacks.h
index 59f3217..8f8057e 100644
--- a/src/gdu/gdu-callbacks.h
+++ b/src/gdu/gdu-callbacks.h
@@ -153,6 +153,11 @@ typedef void (*GduPoolLinuxMdStartCompletedFunc) (GduPool    *pool,
                                                   GError     *error,
                                                   gpointer    user_data);
 
+typedef void (*GduPoolLinuxMdCreateCompletedFunc) (GduPool    *pool,
+                                                   char       *array_object_path,
+                                                   GError     *error,
+                                                   gpointer    user_data);
+
 /* ---------------------------------------------------------------------------------------------------- */
 /* GduDrive */
 
diff --git a/src/gdu/gdu-device.c b/src/gdu/gdu-device.c
index 82eeec0..744484c 100644
--- a/src/gdu/gdu-device.c
+++ b/src/gdu/gdu-device.c
@@ -119,6 +119,7 @@ typedef struct
         gboolean drive_is_media_ejectable;
         gboolean drive_can_detach;
         gboolean drive_can_spindown;
+        gboolean drive_is_rotational;
 
         gboolean optical_disc_is_blank;
         gboolean optical_disc_is_appendable;
@@ -318,6 +319,8 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
                 props->drive_can_detach = g_value_get_boolean (value);
         else if (strcmp (key, "drive-can-spindown") == 0)
                 props->drive_can_spindown = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-is-rotational") == 0)
+                props->drive_is_rotational = g_value_get_boolean (value);
 
         else if (strcmp (key, "optical-disc-is-blank") == 0)
                 props->optical_disc_is_blank = g_value_get_boolean (value);
@@ -1116,6 +1119,12 @@ gdu_device_drive_get_can_spindown (GduDevice *device)
 }
 
 gboolean
+gdu_device_drive_get_is_rotational (GduDevice *device)
+{
+        return device->priv->props->drive_is_rotational;
+}
+
+gboolean
 gdu_device_optical_disc_get_is_blank (GduDevice *device)
 {
         return device->priv->props->optical_disc_is_blank;
diff --git a/src/gdu/gdu-device.h b/src/gdu/gdu-device.h
index b430243..11e53a1 100644
--- a/src/gdu/gdu-device.h
+++ b/src/gdu/gdu-device.h
@@ -139,6 +139,7 @@ gboolean gdu_device_drive_get_is_media_ejectable (GduDevice *device);
 gboolean gdu_device_drive_get_requires_eject (GduDevice *device);
 gboolean gdu_device_drive_get_can_detach (GduDevice *device);
 gboolean gdu_device_drive_get_can_spindown (GduDevice *device);
+gboolean gdu_device_drive_get_is_rotational (GduDevice *device);
 
 gboolean gdu_device_optical_disc_get_is_blank (GduDevice *device);
 gboolean gdu_device_optical_disc_get_is_appendable (GduDevice *device);
diff --git a/src/gdu/gdu-drive.c b/src/gdu/gdu-drive.c
index 81b638a..0852ac2 100644
--- a/src/gdu/gdu-drive.c
+++ b/src/gdu/gdu-drive.c
@@ -20,6 +20,7 @@
  */
 
 #include <config.h>
+#include <stdlib.h>
 #include <string.h>
 #include <glib/gi18n.h>
 #include <dbus/dbus-glib.h>
@@ -31,6 +32,8 @@
 #include "gdu-presentable.h"
 #include "gdu-device.h"
 #include "gdu-error.h"
+#include "gdu-volume.h"
+#include "gdu-volume-hole.h"
 
 /**
  * SECTION:gdu-drive
@@ -63,6 +66,11 @@ G_DEFINE_TYPE_WITH_CODE (GduDrive, gdu_drive, G_TYPE_OBJECT,
 static void device_job_changed (GduDevice *device, gpointer user_data);
 static void device_changed (GduDevice *device, gpointer user_data);
 
+static gboolean gdu_drive_has_unallocated_space_real (GduDrive        *drive,
+                                                      gboolean        *out_whole_disk_is_unitialized,
+                                                      guint64         *out_largest_segment,
+                                                      GduPresentable **out_presentable);
+
 static void
 gdu_drive_finalize (GduDrive *drive)
 {
@@ -92,6 +100,8 @@ gdu_drive_class_init (GduDriveClass *klass)
 
         obj_class->finalize = (GObjectFinalizeFunc) gdu_drive_finalize;
 
+        klass->has_unallocated_space = gdu_drive_has_unallocated_space_real;
+
         g_type_class_add_private (klass, sizeof (GduDrivePrivate));
 }
 
@@ -183,6 +193,178 @@ gdu_drive_deactivate (GduDrive                *drive,
         }
 }
 
+/**
+ * gdu_drive_has_unallocated_space:
+ * @drive: A #GduDrive.
+ * @out_whole_disk_is_unitialized: Return location for whether @drive is uninitialized or %NULL.
+ * @out_largest_segment: Return location biggest contigious free block of @drive or %NULL.
+ * @out_presentable: Return location for the presentable that represents free space or %NULL. Free
+ * with g_object_unref().
+ *
+ * This method computes the largest contigious free block of
+ * unallocated space on @drive.
+ *
+ * If @drive uses removable media and there is no media inserted,
+ * %FALSE is returned.
+ *
+ * If @drive appears to be completely uninitialized (such as a hard
+ * disk full of zeros), @out_whole_disk_is_unitialized is set to
+ * %TRUE, the size of the media/disk is returned in
+ * @out_largest_segment and %TRUE is returned. Note that this can
+ * also happen if @drive contains signatures unknown to the operating system
+ * so be careful.
+ *
+ * If the disk is partitioned and unallocated space exists but no more
+ * partitions can be created (due to e.g. four primary partitions on a
+ * MBR partitioned disk), this method returns %FALSE but
+ * @out_largest_segment will be set to a non-zero value.
+ *
+ * Additionally, @out_presentable will be set to either a
+ * #GduVolumeHole (if the disk is partitioned and has free space) or
+ * the #GduDrive (if the disk is uninitialized).
+ *
+ * Returns: %TRUE if @drive has unallocated space, %FALSE otherwise.
+ */
+gboolean
+gdu_drive_has_unallocated_space (GduDrive        *drive,
+                                 gboolean        *out_whole_disk_is_unitialized,
+                                 guint64         *out_largest_segment,
+                                 GduPresentable **out_presentable)
+{
+        GduDriveClass *klass = GDU_DRIVE_GET_CLASS (drive);
+
+        return klass->has_unallocated_space (drive,
+                                             out_whole_disk_is_unitialized,
+                                             out_largest_segment,
+                                             out_presentable);
+}
+
+static gboolean
+gdu_drive_has_unallocated_space_real (GduDrive        *drive,
+                                      gboolean        *out_whole_disk_is_unitialized,
+                                      guint64         *out_largest_segment,
+                                      GduPresentable **out_presentable)
+{
+        GduDevice *device;
+        GduPool *pool;
+        guint64 largest_segment;
+        gboolean whole_disk_uninitialized;
+        GList *enclosed_presentables;
+        GList *l;
+        gboolean has_extended_partition;
+        gboolean ret;
+        guint64 size;
+        GduPresentable *pres;
+
+        largest_segment = 0;
+        whole_disk_uninitialized = FALSE;
+        ret = FALSE;
+        device = NULL;
+        pool = NULL;
+        pres = NULL;
+
+        device = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
+
+        if (device != NULL && gdu_device_is_read_only (device))
+                goto out;
+
+        if (gdu_device_is_removable (device) && !gdu_device_is_media_available (device))
+                goto out;
+
+        /* now figure out @whole_disk_is_uninitialized... this is to be set to %TRUE exactly
+         * when we _think_ the disk has never been used - we define this to happen when
+         *
+         *  1. The disk has no partition table; and
+         *
+         *  2. the whole-disk device is unrecognized
+         */
+        if (!gdu_device_is_partition_table (device) && strlen (gdu_device_id_get_usage (device)) == 0) {
+                whole_disk_uninitialized = TRUE;
+                largest_segment = gdu_device_get_size (device);
+                ret = TRUE;
+                pres = GDU_PRESENTABLE (drive);
+                goto out;
+        }
+
+        pool = gdu_presentable_get_pool (GDU_PRESENTABLE (drive));
+
+        has_extended_partition = FALSE;
+        enclosed_presentables = gdu_pool_get_enclosed_presentables (pool,
+                                                                    GDU_PRESENTABLE (drive));
+        for (l = enclosed_presentables; l != NULL; l = l->next) {
+                GduPresentable *ep = GDU_PRESENTABLE (l->data);
+
+                if (GDU_IS_VOLUME_HOLE (ep)) {
+                        size = gdu_presentable_get_size (ep);
+
+                        if (size > largest_segment) {
+                                largest_segment = size;
+                                pres = ep;
+                        }
+                } else if (GDU_IS_VOLUME (ep)) {
+                        gint type;
+                        GduDevice *ep_device;
+
+                        ep_device = gdu_presentable_get_device (ep);
+
+                        type = strtol (gdu_device_partition_get_type (ep_device), NULL, 0);
+                        if (type == 0x05 || type == 0x0f || type == 0x85) {
+                                GList *logical_partitions;
+                                GList *ll;
+
+                                has_extended_partition = TRUE;
+
+                                /* This is MS-DOS extended partition, count volume holes inside */
+                                logical_partitions = gdu_pool_get_enclosed_presentables (pool, ep);
+                                for (ll = logical_partitions; ll != NULL; ll = ll->next) {
+                                        GduPresentable *lep = GDU_PRESENTABLE (ll->data);
+
+                                        if (GDU_IS_VOLUME_HOLE (lep)) {
+                                                size = gdu_presentable_get_size (lep);
+                                                if (size > largest_segment) {
+                                                        largest_segment = size;
+                                                        pres = lep;
+                                                }
+                                        }
+                                }
+                                g_list_foreach (logical_partitions, (GFunc) g_object_unref, NULL);
+                                g_list_free (logical_partitions);
+                        }
+                        g_object_unref (ep_device);
+                }
+        }
+        g_list_foreach (enclosed_presentables, (GFunc) g_object_unref, NULL);
+        g_list_free (enclosed_presentables);
+
+        ret = (largest_segment > 0);
+
+        /* Now igure out if the partition table is full (e.g. four primary partitions already) and
+         * return %FALSE and non-zero @out_largest_segment
+         */
+        if (g_strcmp0 (gdu_device_partition_table_get_scheme (device), "mbr") == 0 &&
+            gdu_device_partition_table_get_count (device) == 4 &&
+            !has_extended_partition) {
+                ret = FALSE;
+        }
+
+ out:
+        if (device != NULL)
+                g_object_unref (device);
+        if (pool != NULL)
+                g_object_unref (pool);
+
+        if (out_largest_segment != NULL)
+                *out_largest_segment = largest_segment;
+
+        if (out_whole_disk_is_unitialized != NULL)
+                *out_whole_disk_is_unitialized = whole_disk_uninitialized;
+
+        if (out_presentable != NULL) {
+                *out_presentable = (pres != NULL ? g_object_ref (pres) : NULL);
+        }
+
+        return ret;
+}
 
 static void
 gdu_drive_init (GduDrive *drive)
@@ -272,7 +454,7 @@ gdu_drive_get_name (GduPresentable *presentable)
         is_removable = gdu_device_is_removable (drive->priv->device);
         media_compat = (const gchar* const *) gdu_device_drive_get_media_compatibility (drive->priv->device);
         has_media = gdu_device_is_media_available (drive->priv->device);
-        is_rotational = TRUE; /* TODO: add support in DKD for this */
+        is_rotational = gdu_device_drive_get_is_rotational (drive->priv->device);
 
         if (has_media && size > 0) {
                 strsize = gdu_util_get_size_for_display (size, FALSE);
@@ -515,6 +697,34 @@ gdu_drive_get_description (GduPresentable *presentable)
         return g_string_free (result, FALSE);
 }
 
+static gchar *
+gdu_drive_get_vpd_name (GduPresentable *presentable)
+{
+        GduDrive *drive = GDU_DRIVE (presentable);
+        const gchar *vendor;
+        const gchar *model;
+        GString *result;
+
+        result = g_string_new (NULL);
+
+        vendor = gdu_device_drive_get_vendor (drive->priv->device);
+        model = gdu_device_drive_get_model (drive->priv->device);
+
+        if (vendor != NULL && strlen (vendor) == 0)
+                vendor = NULL;
+
+        if (model != NULL && strlen (model) == 0)
+                model = NULL;
+
+        g_string_append_printf (result,
+                                "%s%s%s",
+                                vendor != NULL ? vendor : "",
+                                vendor != NULL ? " " : "",
+                                model != NULL ? model : "");
+
+        return g_string_free (result, FALSE);
+}
+
 static gboolean
 strv_has (char **strv, const gchar *str)
 {
@@ -681,15 +891,17 @@ gdu_drive_is_recognized (GduPresentable *presentable)
 static void
 gdu_drive_presentable_iface_init (GduPresentableIface *iface)
 {
-        iface->get_id = gdu_drive_get_id;
-        iface->get_device = gdu_drive_get_device;
+        iface->get_id                    = gdu_drive_get_id;
+        iface->get_device                = gdu_drive_get_device;
         iface->get_enclosing_presentable = gdu_drive_get_enclosing_presentable;
-        iface->get_name = gdu_drive_get_name;
-        iface->get_description = gdu_drive_get_description;
-        iface->get_icon = gdu_drive_get_icon;
-        iface->get_offset = gdu_drive_get_offset;
-        iface->get_size = gdu_drive_get_size;
-        iface->get_pool = gdu_drive_get_pool;
-        iface->is_allocated = gdu_drive_is_allocated;
-        iface->is_recognized = gdu_drive_is_recognized;
+        iface->get_name                  = gdu_drive_get_name;
+        iface->get_description           = gdu_drive_get_description;
+        iface->get_vpd_name              = gdu_drive_get_vpd_name;
+        iface->get_icon                  = gdu_drive_get_icon;
+        iface->get_offset                = gdu_drive_get_offset;
+        iface->get_size                  = gdu_drive_get_size;
+        iface->get_pool                  = gdu_drive_get_pool;
+        iface->is_allocated              = gdu_drive_is_allocated;
+        iface->is_recognized             = gdu_drive_is_recognized;
 }
+
diff --git a/src/gdu/gdu-drive.h b/src/gdu/gdu-drive.h
index 37da590..0e5a6fe 100644
--- a/src/gdu/gdu-drive.h
+++ b/src/gdu/gdu-drive.h
@@ -66,6 +66,11 @@ struct _GduDriveClass
                                               GduDriveDeactivateFunc callback,
                                               gpointer               user_data);
 
+        gboolean   (*has_unallocated_space) (GduDrive        *drive,
+                                             gboolean        *out_whole_disk_is_unitialized,
+                                             guint64         *out_largest_segment,
+                                             GduPresentable **out_presentable);
+
 };
 
 GType       gdu_drive_get_type           (void);
@@ -82,6 +87,11 @@ void        gdu_drive_deactivate            (GduDrive              *drive,
                                              GduDriveDeactivateFunc callback,
                                              gpointer               user_data);
 
+gboolean    gdu_drive_has_unallocated_space (GduDrive        *drive,
+                                             gboolean        *out_whole_disk_is_unitialized,
+                                             guint64         *out_largest_segment,
+                                             GduPresentable **out_presentable);
+
 G_END_DECLS
 
 #endif /* __GDU_DRIVE_H */
diff --git a/src/gdu/gdu-linux-md-drive.c b/src/gdu/gdu-linux-md-drive.c
index 09a47ca..981582c 100644
--- a/src/gdu/gdu-linux-md-drive.c
+++ b/src/gdu/gdu-linux-md-drive.c
@@ -468,26 +468,36 @@ gdu_linux_md_drive_get_enclosing_presentable (GduPresentable *presentable)
 }
 
 static gchar *
-get_name_and_desc (GduPresentable  *presentable,
-                   gchar          **out_desc)
+get_names_and_desc (GduPresentable  *presentable,
+                    gchar          **out_vpd_name,
+                    gchar          **out_desc)
 {
         GduLinuxMdDrive *drive = GDU_LINUX_MD_DRIVE (presentable);
         GduDevice *component_device;
         gchar *ret;
         gchar *ret_desc;
+        gchar *ret_vpd;
         gchar *level_str;
         guint64 component_size;
         int num_slaves;
         int num_raid_devices;
         const char *level;
         const char *name;
+        gchar *strsize;
 
         ret = NULL;
         ret_desc = NULL;
+        ret_vpd = NULL;
+        strsize = NULL;
 
-        if (drive->priv->slaves != NULL) {
+        /* TODO: Maybe guess size from level, num_raid_devices and component_size? */
+        if (drive->priv->device != NULL) {
                 guint64 size;
-                gchar *strsize;
+                size = gdu_device_get_size (drive->priv->device);
+                strsize = gdu_util_get_size_for_display (size, FALSE);
+        }
+
+        if (drive->priv->slaves != NULL) {
 
                 component_device = GDU_DEVICE (drive->priv->slaves->data);
 
@@ -497,14 +507,7 @@ get_name_and_desc (GduPresentable  *presentable,
                 num_slaves = g_list_length (drive->priv->slaves);
                 component_size = gdu_device_get_size (component_device);
 
-                level_str = gdu_linux_md_get_raid_level_for_display (level);
-
-                strsize = NULL;
-                if (drive->priv->device != NULL) {
-                        size = gdu_device_get_size (component_device);
-                        strsize = gdu_util_get_size_for_display (size, FALSE);
-                }
-                /* TODO: Maybe guess size from level, num_raid_devices and component_size? */
+                level_str = gdu_linux_md_get_raid_level_for_display (level, FALSE);
 
                 if (name == NULL || strlen (name) == 0) {
                         if (strsize != NULL) {
@@ -565,10 +568,6 @@ get_name_and_desc (GduPresentable  *presentable,
 
                 g_free (level_str);
 
-                /* lame fallback */
-                if (ret_desc == NULL)
-                        ret_desc = g_strdup (_("RAID Array"));
-
         } else if (drive->priv->device != NULL) {
                 /* Translators: First %s is a device file such as /dev/sda4
                  * second %s is the state of the device
@@ -576,7 +575,6 @@ get_name_and_desc (GduPresentable  *presentable,
                 ret = g_strdup_printf (_("RAID device %s (%s)"),
                                        gdu_device_get_device_file (drive->priv->device),
                                        gdu_device_linux_md_get_state (drive->priv->device));
-
         } else {
                 g_warn_if_fail (drive->priv->device_file != NULL);
 
@@ -584,18 +582,41 @@ get_name_and_desc (GduPresentable  *presentable,
                 ret = g_strdup_printf (_("RAID device %s"), drive->priv->device_file);
         }
 
+        /* Fallback for description */
+        if (ret_desc == NULL) {
+                ret_desc = g_strdup (_("RAID Array"));
+        }
+
+        /* Fallback for VPD name */
+        if (ret_vpd == NULL) {
+                if (strsize != NULL) {
+                        /* Translators: %s is the size e.g. '45 GB' */
+                        ret_vpd = g_strdup_printf (_("%s Software RAID"),
+                                                   strsize);
+                } else {
+                        ret_vpd = g_strdup (_("Software RAID"));
+                }
+        }
+
         if (out_desc != NULL)
                 *out_desc = ret_desc;
         else
                 g_free (ret_desc);
 
+        if (out_vpd_name != NULL)
+                *out_vpd_name = ret_vpd;
+        else
+                g_free (ret_vpd);
+
+        g_free (strsize);
+
         return ret;
 }
 
 static char *
 gdu_linux_md_drive_get_name (GduPresentable *presentable)
 {
-        return get_name_and_desc (presentable, NULL);
+        return get_names_and_desc (presentable, NULL, NULL);
 }
 
 static gchar *
@@ -604,12 +625,24 @@ gdu_linux_md_drive_get_description (GduPresentable *presentable)
         gchar *desc;
         gchar *name;
 
-        name = get_name_and_desc (presentable, &desc);
+        name = get_names_and_desc (presentable, NULL, &desc);
         g_free (name);
 
         return desc;
 }
 
+static gchar *
+gdu_linux_md_drive_get_vpd_name (GduPresentable *presentable)
+{
+        gchar *vpd_name;
+        gchar *name;
+
+        name = get_names_and_desc (presentable, &vpd_name, NULL);
+        g_free (name);
+
+        return vpd_name;
+}
+
 static GIcon *
 gdu_linux_md_drive_get_icon (GduPresentable *presentable)
 {
@@ -700,17 +733,18 @@ gdu_linux_md_drive_is_recognized (GduPresentable *presentable)
 static void
 gdu_linux_md_drive_presentable_iface_init (GduPresentableIface *iface)
 {
-        iface->get_id = gdu_linux_md_drive_get_id;
-        iface->get_device = gdu_linux_md_drive_get_device;
+        iface->get_id                    = gdu_linux_md_drive_get_id;
+        iface->get_device                = gdu_linux_md_drive_get_device;
         iface->get_enclosing_presentable = gdu_linux_md_drive_get_enclosing_presentable;
-        iface->get_name = gdu_linux_md_drive_get_name;
-        iface->get_description = gdu_linux_md_drive_get_description;
-        iface->get_icon = gdu_linux_md_drive_get_icon;
-        iface->get_offset = gdu_linux_md_drive_get_offset;
-        iface->get_size = gdu_linux_md_drive_get_size;
-        iface->get_pool = gdu_linux_md_drive_get_pool;
-        iface->is_allocated = gdu_linux_md_drive_is_allocated;
-        iface->is_recognized = gdu_linux_md_drive_is_recognized;
+        iface->get_name                  = gdu_linux_md_drive_get_name;
+        iface->get_description           = gdu_linux_md_drive_get_description;
+        iface->get_vpd_name              = gdu_linux_md_drive_get_vpd_name;
+        iface->get_icon                  = gdu_linux_md_drive_get_icon;
+        iface->get_offset                = gdu_linux_md_drive_get_offset;
+        iface->get_size                  = gdu_linux_md_drive_get_size;
+        iface->get_pool                  = gdu_linux_md_drive_get_pool;
+        iface->is_allocated              = gdu_linux_md_drive_is_allocated;
+        iface->is_recognized             = gdu_linux_md_drive_is_recognized;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu/gdu-pool.c b/src/gdu/gdu-pool.c
index 0a337ed..180f368 100644
--- a/src/gdu/gdu-pool.c
+++ b/src/gdu/gdu-pool.c
@@ -1568,6 +1568,67 @@ gdu_pool_op_linux_md_start (GduPool *pool,
                                                               data);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+        GduPool *pool;
+        GduPoolLinuxMdCreateCompletedFunc callback;
+        gpointer user_data;
+} LinuxMdCreateData;
+
+static void
+op_linux_md_create_cb (DBusGProxy *proxy, char *assembled_array_object_path, GError *error, gpointer user_data)
+{
+        LinuxMdCreateData *data = user_data;
+        _gdu_error_fixup (error);
+        if (data->callback != NULL)
+                data->callback (data->pool, assembled_array_object_path, error, data->user_data);
+        g_object_unref (data->pool);
+        g_free (data);
+}
+
+/**
+ * gdu_pool_op_linux_md_create:
+ * @pool: A #GduPool.
+ * @component_objpaths: A #GPtrArray of object paths.
+ * @level: RAID level.
+ * @name: Name of array.
+ * @callback: Callback function.
+ * @user_data: User data to pass to @callback.
+ *
+ * Creates a Linux md Software Array.
+ **/
+void
+gdu_pool_op_linux_md_create (GduPool *pool,
+                             GPtrArray *component_objpaths,
+                             const gchar *level,
+                             guint64      stripe_size,
+                             const gchar *name,
+                             GduPoolLinuxMdCreateCompletedFunc callback,
+                             gpointer user_data)
+{
+        LinuxMdCreateData *data;
+        char *options[16];
+
+        options[0] = NULL;
+
+        data = g_new0 (LinuxMdCreateData, 1);
+        data->pool = g_object_ref (pool);
+        data->callback = callback;
+        data->user_data = user_data;
+
+        org_freedesktop_DeviceKit_Disks_linux_md_create_async (pool->priv->proxy,
+                                                               component_objpaths,
+                                                               level,
+                                                               stripe_size,
+                                                               name,
+                                                               (const char **) options,
+                                                               op_linux_md_create_cb,
+                                                               data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /**
  * gdu_pool_get_daemon_version:
  * @pool: A #GduPool.
diff --git a/src/gdu/gdu-pool.h b/src/gdu/gdu-pool.h
index 6a5909a..dd2f7b8 100644
--- a/src/gdu/gdu-pool.h
+++ b/src/gdu/gdu-pool.h
@@ -91,6 +91,14 @@ void gdu_pool_op_linux_md_start (GduPool *pool,
                                  GduPoolLinuxMdStartCompletedFunc callback,
                                  gpointer user_data);
 
+void gdu_pool_op_linux_md_create (GduPool     *pool,
+                                  GPtrArray   *component_objpaths,
+                                  const gchar *level,
+                                  guint64      stripe_size,
+                                  const gchar *name,
+                                  GduPoolLinuxMdCreateCompletedFunc callback,
+                                  gpointer user_data);
+
 G_END_DECLS
 
 #endif /* __GDU_POOL_H */
diff --git a/src/gdu/gdu-presentable.c b/src/gdu/gdu-presentable.c
index 8f75afb..6f38998 100644
--- a/src/gdu/gdu-presentable.c
+++ b/src/gdu/gdu-presentable.c
@@ -318,6 +318,18 @@ gdu_presentable_get_enclosing_presentable (GduPresentable *presentable)
  * Gets a name for @presentable suitable for presentation in an user
  * interface.
  *
+ * For drives (e.g. #GduDrive) this could be "80G Solid-State Disk",
+ * "500G Hard Disk", "CompactFlash Drive", "CD/DVD Drive"
+ *
+ * For volumes (e.g. #GduVolume) this string could be "Fedora
+ * (Rawhide)" (for filesystems with labels), "48G Free" (for
+ * unallocated space), "2GB Swap Space" (for swap), "430GB RAID
+ * Component" (for RAID components) and so on.
+ *
+ * Constrast with gdu_presentable_get_vpd_name() that returns a name
+ * based on Vital Product Data including things such as the name of
+ * the vendor, the model name and so on.
+ *
  * Returns: The name. Caller must free the string with g_free().
  **/
 gchar *
@@ -333,6 +345,39 @@ gdu_presentable_get_name (GduPresentable *presentable)
 }
 
 /**
+ * gdu_presentable_get_vpd_name:
+ * @presentable: A #GduPresentable.
+ *
+ * Gets a name for @presentable suitable for presentation in an user
+ * interface that includes Vital Product Data details such as the name
+ * of the vendor, the model name and so on.
+ *
+ * For drives (e.g. #GduDrive) this typically includes the
+ * vendor/model strings obtained from the hardware, for example
+ * "MATSHITA DVD/CDRW UJDA775" or "ATA INTEL SSDSA2MH080G1GC".
+ *
+ * For volumes (e.g. #GduVolume) this includes information about e.g.
+ * partition infomation for example "Whole-disk volume on ATA INTEL
+ * SSDSA2MH080G1GC", "Partition 2 of ATA INTEL SSDSA2MH080G1GC".
+ *
+ * Contrast with gdu_presentable_get_name() that may not include this
+ * information.
+ *
+ * Returns: The name. Caller must free the string with g_free().
+ **/
+gchar *
+gdu_presentable_get_vpd_name (GduPresentable *presentable)
+{
+  GduPresentableIface *iface;
+
+  g_return_val_if_fail (GDU_IS_PRESENTABLE (presentable), NULL);
+
+  iface = GDU_PRESENTABLE_GET_IFACE (presentable);
+
+  return (* iface->get_vpd_name) (presentable);
+}
+
+/**
  * gdu_presentable_get_description:
  * @presentable: A #GduPresentable.
  *
diff --git a/src/gdu/gdu-presentable.h b/src/gdu/gdu-presentable.h
index 2a384e7..13b5453 100644
--- a/src/gdu/gdu-presentable.h
+++ b/src/gdu/gdu-presentable.h
@@ -47,6 +47,8 @@ typedef struct _GduPresentableIface    GduPresentableIface;
  * @get_device: Returns the underlying #GduDevice.
  * @get_enclosing_presentable: Returns the #GduPresentable that is the parent or #NULL if there is no parent.
  * @get_name: Returns a name for the presentable suitable for presentation in an user interface.
+ * @get_description: Returns a description of the presentable suitable for presentation in an user interface.
+ * @get_vpd_name: Returns a name for the presentable suitable for UI that includes Vital Product Pata.
  * @get_icon: Returns an icon suitable for display in an user interface.
  * @get_offset: Returns where the data represented by the presentable starts on the underlying main block device.
  * @get_size: Returns the size of the presentable or zero if not allocated.
@@ -71,6 +73,7 @@ struct _GduPresentableIface
         GduPresentable * (*get_enclosing_presentable) (GduPresentable *presentable);
         gchar *          (*get_name)                  (GduPresentable *presentable);
         gchar *          (*get_description)           (GduPresentable *presentable);
+        gchar *          (*get_vpd_name)              (GduPresentable *presentable);
         GIcon *          (*get_icon)                  (GduPresentable *presentable);
         guint64          (*get_offset)                (GduPresentable *presentable);
         guint64          (*get_size)                  (GduPresentable *presentable);
@@ -85,6 +88,7 @@ GduDevice      *gdu_presentable_get_device                (GduPresentable *prese
 GduPresentable *gdu_presentable_get_enclosing_presentable (GduPresentable *presentable);
 gchar          *gdu_presentable_get_name                  (GduPresentable *presentable);
 gchar          *gdu_presentable_get_description           (GduPresentable *presentable);
+gchar          *gdu_presentable_get_vpd_name              (GduPresentable *presentable);
 GIcon          *gdu_presentable_get_icon                  (GduPresentable *presentable);
 guint64         gdu_presentable_get_offset                (GduPresentable *presentable);
 guint64         gdu_presentable_get_size                  (GduPresentable *presentable);
diff --git a/src/gdu/gdu-util.c b/src/gdu/gdu-util.c
index c0c1925..27ccffc 100644
--- a/src/gdu/gdu-util.c
+++ b/src/gdu/gdu-util.c
@@ -827,24 +827,46 @@ gdu_util_get_connection_for_display (const char *connection_interface, guint64 c
 /* ---------------------------------------------------------------------------------------------------- */
 
 gchar *
-gdu_linux_md_get_raid_level_for_display (const gchar *linux_md_raid_level)
+gdu_linux_md_get_raid_level_for_display (const gchar *linux_md_raid_level,
+                                         gboolean long_string)
 {
         gchar *ret;
 
         if (strcmp (linux_md_raid_level, "raid0") == 0) {
-                ret = g_strdup (C_("RAID level", "RAID-0"));
+                if (long_string)
+                        ret = g_strdup (C_("RAID level", "Stripe (RAID-0)"));
+                else
+                        ret = g_strdup (C_("RAID level", "RAID-0"));
         } else if (strcmp (linux_md_raid_level, "raid1") == 0) {
-                ret = g_strdup (C_("RAID level", "RAID-1"));
+                if (long_string)
+                        ret = g_strdup (C_("RAID level", "Mirror (RAID-1)"));
+                else
+                        ret = g_strdup (C_("RAID level", "RAID-1"));
         } else if (strcmp (linux_md_raid_level, "raid4") == 0) {
-                ret = g_strdup (C_("RAID level", "RAID-4"));
+                if (long_string)
+                        ret = g_strdup (C_("RAID level", "Parity Disk (RAID-4)"));
+                else
+                        ret = g_strdup (C_("RAID level", "RAID-4"));
         } else if (strcmp (linux_md_raid_level, "raid5") == 0) {
-                ret = g_strdup (C_("RAID level", "RAID-5"));
+                if (long_string)
+                        ret = g_strdup (C_("RAID level", "Distributed Parity (RAID-5)"));
+                else
+                        ret = g_strdup (C_("RAID level", "RAID-5"));
         } else if (strcmp (linux_md_raid_level, "raid6") == 0) {
-                ret = g_strdup (C_("RAID level", "RAID-6"));
+                if (long_string)
+                        ret = g_strdup (C_("RAID level", "Dual Distributed Parity (RAID-6)"));
+                else
+                        ret = g_strdup (C_("RAID level", "RAID-6"));
         } else if (strcmp (linux_md_raid_level, "raid10") == 0) {
-                ret = g_strdup (C_("RAID level", "RAID-10"));
+                if (long_string)
+                        ret = g_strdup (C_("RAID level", "Stripe of Mirrors (RAID-10)"));
+                else
+                        ret = g_strdup (C_("RAID level", "RAID-10"));
         } else if (strcmp (linux_md_raid_level, "linear") == 0) {
-                ret = g_strdup (C_("RAID level", "JBOD"));
+                if (long_string)
+                        ret = g_strdup (C_("RAID level", "Concatenated (Linear)"));
+                else
+                        ret = g_strdup (C_("RAID level", "Linear"));
         } else {
                 ret = g_strdup (linux_md_raid_level);
         }
@@ -852,5 +874,44 @@ gdu_linux_md_get_raid_level_for_display (const gchar *linux_md_raid_level)
         return ret;
 }
 
+char *
+gdu_linux_md_get_raid_level_description (const gchar *linux_md_raid_level)
+{
+        gchar *ret;
+
+        if (strcmp (linux_md_raid_level, "raid0") == 0) {
+                ret = g_strdup (_("Striped set without parity. "
+                                  "Provides improved performance but no fault tolerance. "
+                                  "If a single disk in the array fails, the entire RAID-0 array fails."));
+        } else if (strcmp (linux_md_raid_level, "raid1") == 0) {
+                ret = g_strdup (_("Mirrored set without parity. "
+                                  "Provides fault tolerance and improved performance for reading. "
+                                  "RAID-1 arrays can sustain all but one disk failing."));
+        } else if (strcmp (linux_md_raid_level, "raid4") == 0) {
+                ret = g_strdup (_("Striped set with parity on a single disk. "
+                                  "Provides improved performance and fault tolerance. "
+                                  "RAID-4 arrays can sustain a single disk failure."));
+        } else if (strcmp (linux_md_raid_level, "raid5") == 0) {
+                ret = g_strdup (_("Striped set with distributed parity. "
+                                  "Provides improved performance and fault tolerance. "
+                                  "RAID-5 arrays can sustain a single disk failure."));
+        } else if (strcmp (linux_md_raid_level, "raid6") == 0) {
+                ret = g_strdup (_("Striped set with dual distributed parity. "
+                                  "Provides improved performance and fault tolerance. "
+                                  "RAID-6 arrays can sustain two disk failures."));
+        } else if (strcmp (linux_md_raid_level, "raid10") == 0) {
+                ret = g_strdup (_("Striped set with distributed parity. "
+                                  "Provides improved performance and fault tolerance. "
+                                  "RAID-10 arrays can sustain multiple drive losses so long as no mirror loses all its drives."));
+        /*} else if (strcmp (linux_md_raid_level, "linear") == 0) {*/
+
+        } else {
+                ret = g_strdup_printf (_("Unknown RAID level %s."), linux_md_raid_level);
+                g_warning ("Please add support: %s", ret);
+        }
+
+        return ret;
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
diff --git a/src/gdu/gdu-util.h b/src/gdu/gdu-util.h
index 1ad6602..2c1adb1 100644
--- a/src/gdu/gdu-util.h
+++ b/src/gdu/gdu-util.h
@@ -45,7 +45,10 @@ char *gdu_util_get_desc_for_part_type (const char *part_scheme, const char *part
 
 char *gdu_get_job_description (const char *job_id);
 
-char *gdu_linux_md_get_raid_level_for_display (const gchar *linux_md_raid_level);
+char *gdu_linux_md_get_raid_level_for_display (const gchar *linux_md_raid_level,
+                                               gboolean long_string);
+
+char *gdu_linux_md_get_raid_level_description (const gchar *linux_md_raid_level);
 
 typedef void (*GduUtilPartTypeForeachFunc) (const char *scheme,
                                             const char *type,
diff --git a/src/gdu/gdu-volume-hole.c b/src/gdu/gdu-volume-hole.c
index cef5dab..11c8564 100644
--- a/src/gdu/gdu-volume-hole.c
+++ b/src/gdu/gdu-volume-hole.c
@@ -159,6 +159,18 @@ gdu_volume_hole_get_description (GduPresentable *presentable)
         return g_strdup (_("Unallocated Space"));
 }
 
+static char *
+gdu_volume_hole_get_vpd_name (GduPresentable *presentable)
+{
+        /* TODO: we might want to include more information in the future - such as
+         *
+         *       - Offset at where the hole is (at offset '45 GB')
+         *       - What partitions are adjacent (between partitions 3 and 4)
+         *
+         */
+        return g_strdup ("");
+}
+
 static GIcon *
 gdu_volume_hole_get_icon (GduPresentable *presentable)
 {
@@ -300,17 +312,18 @@ gdu_volume_hole_is_recognized (GduPresentable *presentable)
 static void
 gdu_volume_hole_presentable_iface_init (GduPresentableIface *iface)
 {
-        iface->get_id = gdu_volume_hole_get_id;
-        iface->get_device = gdu_volume_hole_get_device;
+        iface->get_id                    = gdu_volume_hole_get_id;
+        iface->get_device                = gdu_volume_hole_get_device;
         iface->get_enclosing_presentable = gdu_volume_hole_get_enclosing_presentable;
-        iface->get_name = gdu_volume_hole_get_name;
-        iface->get_description = gdu_volume_hole_get_description;
-        iface->get_icon = gdu_volume_hole_get_icon;
-        iface->get_offset = gdu_volume_hole_get_offset;
-        iface->get_size = gdu_volume_hole_get_size;
-        iface->get_pool = gdu_volume_hole_get_pool;
-        iface->is_allocated = gdu_volume_hole_is_allocated;
-        iface->is_recognized = gdu_volume_hole_is_recognized;
+        iface->get_name                  = gdu_volume_hole_get_name;
+        iface->get_description           = gdu_volume_hole_get_description;
+        iface->get_vpd_name              = gdu_volume_hole_get_vpd_name;
+        iface->get_icon                  = gdu_volume_hole_get_icon;
+        iface->get_offset                = gdu_volume_hole_get_offset;
+        iface->get_size                  = gdu_volume_hole_get_size;
+        iface->get_pool                  = gdu_volume_hole_get_pool;
+        iface->is_allocated              = gdu_volume_hole_is_allocated;
+        iface->is_recognized             = gdu_volume_hole_is_recognized;
 }
 
 void
diff --git a/src/gdu/gdu-volume.c b/src/gdu/gdu-volume.c
index 0912356..e4504ab 100644
--- a/src/gdu/gdu-volume.c
+++ b/src/gdu/gdu-volume.c
@@ -196,8 +196,9 @@ gdu_volume_get_enclosing_presentable (GduPresentable *presentable)
 }
 
 static char *
-get_name_and_desc (GduPresentable  *presentable,
-                   gchar          **out_desc)
+get_names_and_desc (GduPresentable  *presentable,
+                    gchar          **out_vpd_name,
+                    gchar          **out_desc)
 {
         GduVolume *volume = GDU_VOLUME (presentable);
         GduPresentable *drive_presentable;
@@ -214,9 +215,11 @@ get_name_and_desc (GduPresentable  *presentable,
         guint64 size;
         guint n;
         gchar *result_desc;
+        gchar *result_vpd;
 
         result = NULL;
         result_desc = NULL;
+        result_vpd = NULL;
 
         drive_presentable = NULL;
         drive_device = NULL;
@@ -279,6 +282,7 @@ get_name_and_desc (GduPresentable  *presentable,
                  * %s is the size, formatted like '45 GB'
                  */
                 result = g_strdup_printf (_("%s Extended"), strsize);
+                result_desc = g_strdup (_("Contains logical partitions"));
         } else if ((usage != NULL && strcmp (usage, "filesystem") == 0) &&
                    (label != NULL && strlen (label) > 0)) {
                 gchar *fsdesc;
@@ -331,7 +335,7 @@ get_name_and_desc (GduPresentable  *presentable,
                                 level = gdu_device_linux_md_component_get_level (volume->priv->device);
 
                                 if (level != NULL && strlen (level) > 0)
-                                        level_str = gdu_linux_md_get_raid_level_for_display (level);
+                                        level_str = gdu_linux_md_get_raid_level_for_display (level, FALSE);
                                 else
                                         /* Translators: Used if no specific RAID level could be determined */
                                         level_str = g_strdup (C_("RAID level", "RAID"));
@@ -398,15 +402,60 @@ get_name_and_desc (GduPresentable  *presentable,
         if (drive_presentable != NULL)
                 g_object_unref (drive_presentable);
 
+        /* Fallback if description isn't explicitly set */
         if (result_desc == NULL) {
                 result_desc = g_strdup (strsize);
         }
 
+        /* Fallback if VPD name isn't explicitly set */
+        if (result_vpd == NULL) {
+                gchar *drive_vpd_name;
+
+                drive_vpd_name = NULL;
+                if (volume->priv->enclosing_presentable != NULL) {
+                        drive_vpd_name = gdu_presentable_get_vpd_name (volume->priv->enclosing_presentable);
+                }
+
+                if (gdu_device_is_partition (volume->priv->device)) {
+                        if (drive_vpd_name != NULL) {
+                                /* Translators: The VPD name for a volume. The %d is the partition number
+                                 * and the %s is the VPD name for the drive.
+                                 */
+                                result_vpd = g_strdup_printf (_("Partition %d of %s"),
+                                                              gdu_device_partition_get_number (volume->priv->device),
+                                                              drive_vpd_name);
+                        } else {
+                                /* Translators: The VPD name for a volume. The %d is the partition number.
+                                 */
+                                result_vpd = g_strdup_printf (_("Partition %d"),
+                                                              gdu_device_partition_get_number (volume->priv->device));
+                        }
+                } else {
+                        if (drive_vpd_name != NULL) {
+                                /* Translators: The VPD name for a whole-disk volume.
+                                 * The %s is the VPD name for the drive.
+                                 */
+                                result_vpd = g_strdup_printf (_("Whole-disk volume on %s"),
+                                                              drive_vpd_name);
+                        } else {
+                                /* Translators: The VPD name for a whole-disk volume.
+                                 */
+                                result_vpd = g_strdup (_("Whole-disk volume"));
+                        }
+                }
+                g_free (drive_vpd_name);
+        }
+
         if (out_desc != NULL)
                 *out_desc = result_desc;
         else
                 g_free (result_desc);
 
+        if (out_vpd_name != NULL)
+                *out_vpd_name = result_vpd;
+        else
+                g_free (result_vpd);
+
         g_free (strsize);
 
         return result;
@@ -415,7 +464,7 @@ get_name_and_desc (GduPresentable  *presentable,
 static char *
 gdu_volume_get_name (GduPresentable *presentable)
 {
-        return get_name_and_desc (presentable, NULL);
+        return get_names_and_desc (presentable, NULL, NULL);
 }
 
 static gchar *
@@ -424,12 +473,24 @@ gdu_volume_get_description (GduPresentable *presentable)
         gchar *desc;
         gchar *name;
 
-        name = get_name_and_desc (presentable, &desc);
+        name = get_names_and_desc (presentable, NULL, &desc);
         g_free (name);
 
         return desc;
 }
 
+static gchar *
+gdu_volume_get_vpd_name (GduPresentable *presentable)
+{
+        gchar *vpd_name;
+        gchar *name;
+
+        name = get_names_and_desc (presentable, &vpd_name, NULL);
+        g_free (name);
+
+        return vpd_name;
+}
+
 static GIcon *
 gdu_volume_get_icon (GduPresentable *presentable)
 {
@@ -659,17 +720,18 @@ gdu_volume_is_recognized (GduPresentable *presentable)
 static void
 gdu_volume_presentable_iface_init (GduPresentableIface *iface)
 {
-        iface->get_id = gdu_volume_get_id;
-        iface->get_device = gdu_volume_get_device;
+        iface->get_id                    = gdu_volume_get_id;
+        iface->get_device                = gdu_volume_get_device;
         iface->get_enclosing_presentable = gdu_volume_get_enclosing_presentable;
-        iface->get_name = gdu_volume_get_name;
-        iface->get_description = gdu_volume_get_description;
-        iface->get_icon = gdu_volume_get_icon;
-        iface->get_offset = gdu_volume_get_offset;
-        iface->get_size = gdu_volume_get_size;
-        iface->get_pool = gdu_volume_get_pool;
-        iface->is_allocated = gdu_volume_is_allocated;
-        iface->is_recognized = gdu_volume_is_recognized;
+        iface->get_name                  = gdu_volume_get_name;
+        iface->get_description           = gdu_volume_get_description;
+        iface->get_vpd_name              = gdu_volume_get_vpd_name;
+        iface->get_icon                  = gdu_volume_get_icon;
+        iface->get_offset                = gdu_volume_get_offset;
+        iface->get_size                  = gdu_volume_get_size;
+        iface->get_pool                  = gdu_volume_get_pool;
+        iface->is_allocated              = gdu_volume_is_allocated;
+        iface->is_recognized             = gdu_volume_is_recognized;
 }
 
 void
diff --git a/src/palimpsest/gdu-section-linux-md-drive.c b/src/palimpsest/gdu-section-linux-md-drive.c
index edc2a76..c3f6941 100644
--- a/src/palimpsest/gdu-section-linux-md-drive.c
+++ b/src/palimpsest/gdu-section-linux-md-drive.c
@@ -170,7 +170,8 @@ on_add_clicked (GtkButton *button,
                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
                                              GTK_SHADOW_IN);
-        model = gdu_pool_tree_model_new (pool);
+        model = gdu_pool_tree_model_new (pool,
+                                         GDU_POOL_TREE_MODEL_FLAGS_NONE);
         tree_view = gdu_pool_tree_view_new (model, GDU_POOL_TREE_VIEW_FLAGS_NONE);
         g_object_unref (model);
         gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index 2da8eb3..a397f70 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -1557,6 +1557,229 @@ help_contents_action_callback (GtkAction *action, gpointer user_data)
         g_warning ("TODO: launch help");
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+        GduShell *shell;
+
+        /* data obtained from GduCreateLinuxMdDialog */
+        gchar *level;
+        gchar *name;
+        guint64 size;
+        guint64 component_size;
+        guint64 stripe_size;
+        GPtrArray *drives;
+
+        /* List of created components - GduDevice objects */
+        GPtrArray *components;
+
+} CreateLinuxMdData;
+
+static void
+create_linux_md_data_free (CreateLinuxMdData *data)
+{
+        g_object_unref (data->shell);
+        g_free (data->level);
+        g_free (data->name);
+        g_ptr_array_unref (data->drives);
+        g_ptr_array_unref (data->components);
+        g_free (data);
+}
+
+static void create_linux_md_do (CreateLinuxMdData *data);
+
+static void
+new_linux_md_create_part_cb (GduDevice  *device,
+                             gchar      *created_device_object_path,
+                             GError     *error,
+                             gpointer    user_data)
+{
+        CreateLinuxMdData *data = user_data;
+
+        if (error != NULL) {
+                gdu_shell_raise_error (data->shell,
+                                       NULL,
+                                       error,
+                                       _("Error creating component for RAID array"));
+                g_error_free (error);
+
+                //g_debug ("Error creating component");
+        } else {
+                GduDevice *d;
+                d = gdu_pool_get_by_object_path (data->shell->priv->pool, created_device_object_path);
+                g_ptr_array_add (data->components, d);
+
+                //g_debug ("Done creating component");
+
+                /* now that we have a component... carry on... */
+                create_linux_md_do (data);
+        }
+}
+
+static void
+new_linux_md_create_part_table_cb (GduDevice  *device,
+                                   GError     *error,
+                                   gpointer    user_data)
+{
+        CreateLinuxMdData *data = user_data;
+
+        if (error != NULL) {
+                gdu_shell_raise_error (data->shell,
+                                       NULL,
+                                       error,
+                                       _("Error creating partition table for component for RAID array"));
+                g_error_free (error);
+
+                //g_debug ("Error creating partition table");
+        } else {
+
+                //g_debug ("Done creating partition table");
+
+                /* now that we have a partition table... carry on... */
+                create_linux_md_do (data);
+        }
+}
+
+static void
+new_linux_md_create_array_cb (GduPool    *pool,
+                              char       *array_object_path,
+                              GError     *error,
+                              gpointer    user_data)
+{
+
+        CreateLinuxMdData *data = user_data;
+
+        if (error != NULL) {
+                gdu_shell_raise_error (data->shell,
+                                       NULL,
+                                       error,
+                                       _("Error creating RAID array"));
+                g_error_free (error);
+
+                //g_debug ("Error creating array");
+        } else {
+                GduDevice *d;
+                GduPresentable *p;
+
+                /* YAY - array has been created - switch the shell to it */
+                d = gdu_pool_get_by_object_path (data->shell->priv->pool, array_object_path);
+                p = gdu_pool_get_drive_by_device (data->shell->priv->pool, d);
+                gdu_shell_select_presentable (data->shell, p);
+                g_object_unref (p);
+                g_object_unref (d);
+
+                //g_debug ("Done creating array");
+        }
+
+        create_linux_md_data_free (data);
+}
+
+static void
+create_linux_md_do (CreateLinuxMdData *data)
+{
+        if (data->components->len == data->drives->len) {
+                GPtrArray *objpaths;
+                guint n;
+
+                /* Create array */
+                //g_debug ("Yay, now creating array");
+
+                objpaths = g_ptr_array_new ();
+                for (n = 0; n < data->components->len; n++) {
+                        GduDevice *d = GDU_DEVICE (data->components->pdata[n]);
+                        g_ptr_array_add (objpaths, (gpointer) gdu_device_get_object_path (d));
+                }
+
+                gdu_pool_op_linux_md_create (data->shell->priv->pool,
+                                             objpaths,
+                                             data->level,
+                                             data->stripe_size,
+                                             data->name,
+                                             new_linux_md_create_array_cb,
+                                             data);
+                g_ptr_array_free (objpaths, TRUE);
+
+        } else {
+                GduDrive *drive;
+                guint num_component;
+                GduPresentable *p;
+                GduDevice *d;
+                guint64 largest_segment;
+                gboolean whole_disk_is_uninitialized;
+
+                num_component = data->components->len;
+                drive = GDU_DRIVE (data->drives->pdata[num_component]);
+
+                g_warn_if_fail (gdu_drive_has_unallocated_space (drive,
+                                                                 &whole_disk_is_uninitialized,
+                                                                 &largest_segment,
+                                                                 &p));
+                g_assert (p != NULL);
+
+                d = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
+
+                if (GDU_IS_VOLUME_HOLE (p)) {
+                        guint64 offset;
+                        guint64 size;
+                        const gchar *scheme;
+                        const gchar *type;
+                        gchar *label;
+
+                        offset = gdu_presentable_get_offset (p);
+                        size = data->component_size;
+
+                        //g_debug ("Creating component %d/%d of size %" G_GUINT64_FORMAT " bytes",
+                        //         num_component + 1,
+                        //         data->drives->len,
+                        //         size);
+
+                        scheme = gdu_device_partition_table_get_scheme (d);
+                        type = "";
+                        label = NULL;
+                        if (g_strcmp0 (scheme, "mbr") == 0) {
+                                type = "0xfd";
+                        } else if (g_strcmp0 (scheme, "gpt") == 0) {
+                                type = "A19D880F-05FC-4D3B-A006-743F0F84911E";
+                                /* Limited to 36 UTF-16LE characters according to on-disk format..
+                                 * Since a RAID array name is limited to 32 chars this should fit */
+                                label = g_strdup_printf ("RAID: %s", data->name);
+                        } else if (g_strcmp0 (scheme, "apt") == 0) {
+                                type = "Apple_Unix_SVR2";
+                                label = g_strdup_printf ("RAID: %s", data->name);
+                        }
+
+                        gdu_device_op_partition_create (d,
+                                                        offset,
+                                                        size,
+                                                        type,
+                                                        label != NULL ? label : "",
+                                                        NULL,
+                                                        "",
+                                                        "",
+                                                        "",
+                                                        FALSE,
+                                                        new_linux_md_create_part_cb,
+                                                        data);
+                        g_free (label);
+
+                } else {
+
+                        /* otherwise the whole disk must be uninitialized... */
+                        g_assert (whole_disk_is_uninitialized);
+
+                        /* so create a partition table... */
+                        gdu_device_op_partition_table_create (d,
+                                                              "mbr",
+                                                              new_linux_md_create_part_table_cb,
+                                                              data);
+                }
+
+                g_object_unref (d);
+                g_object_unref (p);
+
+        }
+}
+
 static void
 new_linud_md_array_callback (GtkAction *action, gpointer user_data)
 {
@@ -1564,18 +1787,36 @@ new_linud_md_array_callback (GtkAction *action, gpointer user_data)
         GtkWidget *dialog;
         gint response;
 
-        g_debug ("New Linux MD Array!");
+        //g_debug ("New Linux MD Array!");
 
         dialog = gdu_create_linux_md_dialog_new (GTK_WINDOW (shell->priv->app_window),
                                                  shell->priv->pool);
 
         gtk_widget_show_all (dialog);
         response = gtk_dialog_run (GTK_DIALOG (dialog));
-        gtk_widget_destroy (dialog);
+        gtk_widget_hide (dialog);
+
+        if (response == GTK_RESPONSE_OK) {
+                CreateLinuxMdData *data;
+
+                data = g_new0 (CreateLinuxMdData, 1);
+                data->shell          = g_object_ref (shell);
+                data->level          = gdu_create_linux_md_dialog_get_level (GDU_CREATE_LINUX_MD_DIALOG (dialog));
+                data->name           = gdu_create_linux_md_dialog_get_name (GDU_CREATE_LINUX_MD_DIALOG (dialog));
+                data->size           = gdu_create_linux_md_dialog_get_size (GDU_CREATE_LINUX_MD_DIALOG (dialog));
+                data->component_size = gdu_create_linux_md_dialog_get_component_size (GDU_CREATE_LINUX_MD_DIALOG (dialog));
+                data->stripe_size    = gdu_create_linux_md_dialog_get_stripe_size (GDU_CREATE_LINUX_MD_DIALOG (dialog));
+                data->drives         = gdu_create_linux_md_dialog_get_drives (GDU_CREATE_LINUX_MD_DIALOG (dialog));
 
-        g_debug ("response = %d", response);
+                data->components  = g_ptr_array_new_with_free_func (g_object_unref);
+
+                create_linux_md_do (data);
+        }
+        gtk_widget_destroy (dialog);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 quit_action_callback (GtkAction *action, gpointer user_data)
 {
@@ -1731,7 +1972,7 @@ expander_cb (GtkExpander *expander, GParamSpec *pspec, GtkWindow *dialog)
 /**
  * gdu_shell_raise_error:
  * @shell: An object implementing the #GduShell interface
- * @presentable: The #GduPresentable for which the error was rasied
+ * @presentable: The #GduPresentable for which the error was raised or %NULL.
  * @error: The #GError obtained from the operation
  * @primary_markup_format: Format string for the primary markup text of the dialog
  * @...: Arguments for markup string
@@ -1756,11 +1997,15 @@ gdu_shell_raise_error (GduShell       *shell,
         GtkTextBuffer *buffer;
 
         g_return_if_fail (shell != NULL);
-        g_return_if_fail (presentable != NULL);
         g_return_if_fail (error != NULL);
 
-        window_title = gdu_presentable_get_name (presentable);
-        window_icon = gdu_presentable_get_icon (presentable);
+        window_icon = NULL;
+        if (presentable != NULL) {
+                window_title = gdu_presentable_get_name (presentable);
+                window_icon = gdu_presentable_get_icon (presentable);
+        } else {
+                window_title = g_strdup (_("An error occured"));
+        }
 
         va_start (args, primary_markup_format);
         error_text = g_strdup_vprintf (primary_markup_format, args);
@@ -1921,7 +2166,8 @@ create_window (GduShell *shell)
                                         GTK_POLICY_AUTOMATIC);
         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (tree_view_scrolled_window),
                                              GTK_SHADOW_IN);
-        model = gdu_pool_tree_model_new (shell->priv->pool);
+        model = gdu_pool_tree_model_new (shell->priv->pool,
+                                         GDU_POOL_TREE_MODEL_FLAGS_NONE);
         shell->priv->tree_view = gdu_pool_tree_view_new (model,
                                                          GDU_POOL_TREE_VIEW_FLAGS_NONE);
         g_object_unref (model);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]