[gnome-disk-utility/new-ui] Implement Linux MD RAID handling for the new-ui branch



commit 6632f1e50684b623a2321a0624fd68c6127288fa
Author: David Zeuthen <davidz redhat com>
Date:   Sat Oct 31 15:48:43 2009 -0400

    Implement Linux MD RAID handling for the new-ui branch

 configure.ac                                    |    2 +-
 src/gdu-gtk/Makefile.am                         |    6 +
 src/gdu-gtk/gdu-add-component-linux-md-dialog.c |  302 ++++
 src/gdu-gtk/gdu-add-component-linux-md-dialog.h |   63 +
 src/gdu-gtk/gdu-details-element.c               |   46 +-
 src/gdu-gtk/gdu-details-element.h               |    3 +
 src/gdu-gtk/gdu-details-table.c                 |   24 +-
 src/gdu-gtk/gdu-disk-selection-widget.c         | 1032 +++++++++++++
 src/gdu-gtk/gdu-disk-selection-widget.h         |   69 +
 src/gdu-gtk/gdu-edit-linux-md-dialog.c          |  864 +++++++++++
 src/gdu-gtk/gdu-edit-linux-md-dialog.h          |   66 +
 src/gdu-gtk/gdu-gtk-enums.h                     |   14 +-
 src/gdu-gtk/gdu-gtk-enumtypes.h                 |    2 +
 src/gdu-gtk/gdu-gtk-types.h                     |   51 +-
 src/gdu-gtk/gdu-gtk.h                           |    3 +
 src/gdu-gtk/gdu-volume-grid.c                   |   38 +-
 src/gdu-gtk/gdu-volume-grid.h                   |    2 +
 src/gdu/gdu-device.c                            |    9 +
 src/gdu/gdu-device.h                            |    1 +
 src/gdu/gdu-linux-md-drive.c                    |   72 +-
 src/gdu/gdu-linux-md-drive.h                    |   17 +-
 src/gdu/gdu-pool.c                              |   26 +
 src/gdu/gdu-pool.h                              |    2 +
 src/gdu/gdu-volume.c                            |   12 +-
 src/palimpsest/gdu-section-drive.c              |   62 +-
 src/palimpsest/gdu-section-drive.h              |    6 +
 src/palimpsest/gdu-section-linux-md-drive.c     | 1862 ++++++++++++-----------
 src/palimpsest/gdu-section-volumes.c            |   81 +-
 src/palimpsest/gdu-section-volumes.h            |    8 +-
 src/palimpsest/gdu-shell.c                      |   83 +-
 30 files changed, 3811 insertions(+), 1017 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 98252ba..a5281e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -128,7 +128,7 @@ GTK2_REQUIRED=2.17.2
 UNIQUE_REQUIRED=1.0
 LIBNOTIFY_REQUIRED=0.3.0
 NAUTILUS_REQUIRED=2.24.0
-DEVKIT_DISKS_REQUIRED=007
+DEVKIT_DISKS_REQUIRED=009
 
 SCROLLKEEPER_REQUIRED=0.3.14
 INTLTOOL_REQUIRED=0.35.0
diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index 0cab29f..19c9403 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -50,6 +50,9 @@ libgdu_gtkinclude_HEADERS =              				\
 	gdu-partition-dialog.h						\
 	gdu-create-partition-dialog.h					\
 	gdu-edit-filesystem-dialog.h					\
+	gdu-disk-selection-widget.h					\
+	gdu-add-component-linux-md-dialog.h				\
+	gdu-edit-linux-md-dialog.h					\
 	$(NULL)
 
 libgdu_gtk_la_SOURCES =                 	               				\
@@ -77,6 +80,9 @@ libgdu_gtk_la_SOURCES =                 	               				\
 	gdu-partition-dialog.h			gdu-partition-dialog.c			\
 	gdu-create-partition-dialog.h		gdu-create-partition-dialog.c		\
 	gdu-edit-filesystem-dialog.h		gdu-edit-filesystem-dialog.c		\
+	gdu-disk-selection-widget.h		gdu-disk-selection-widget.c		\
+	gdu-add-component-linux-md-dialog.h	gdu-add-component-linux-md-dialog.c	\
+	gdu-edit-linux-md-dialog.h		gdu-edit-linux-md-dialog.c		\
 	$(NULL)
 
 libgdu_gtk_la_CPPFLAGS = 				\
diff --git a/src/gdu-gtk/gdu-add-component-linux-md-dialog.c b/src/gdu-gtk/gdu-add-component-linux-md-dialog.c
new file mode 100644
index 0000000..adcb540
--- /dev/null
+++ b/src/gdu-gtk/gdu-add-component-linux-md-dialog.c
@@ -0,0 +1,302 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* Copyright (C) 2009 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <atasmart.h>
+#include <glib/gstdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "gdu-gtk.h"
+#include "gdu-add-component-linux-md-dialog.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+struct GduAddComponentLinuxMdDialogPrivate
+{
+        GtkWidget *disk_selection_widget;
+};
+
+enum {
+        PROP_0,
+        PROP_DRIVE,
+        PROP_SIZE
+};
+
+G_DEFINE_TYPE (GduAddComponentLinuxMdDialog, gdu_add_component_linux_md_dialog, GDU_TYPE_DIALOG)
+
+static void
+gdu_add_component_linux_md_dialog_finalize (GObject *object)
+{
+        /*GduAddComponentLinuxMdDialog *dialog = GDU_ADD_COMPONENT_LINUX_MD_DIALOG (object);*/
+
+        if (G_OBJECT_CLASS (gdu_add_component_linux_md_dialog_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_add_component_linux_md_dialog_parent_class)->finalize (object);
+}
+
+static void
+gdu_add_component_linux_md_dialog_get_property (GObject    *object,
+                                                guint       property_id,
+                                                GValue     *value,
+                                                GParamSpec *pspec)
+{
+        GduAddComponentLinuxMdDialog *dialog = GDU_ADD_COMPONENT_LINUX_MD_DIALOG (object);
+
+        switch (property_id) {
+        case PROP_DRIVE:
+                g_value_take_object (value, gdu_add_component_linux_md_dialog_get_drive (dialog));
+                break;
+
+        case PROP_SIZE:
+                g_value_set_uint64 (value, gdu_add_component_linux_md_dialog_get_size (dialog));
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_add_sensitivity (GduAddComponentLinuxMdDialog *dialog)
+{
+        GPtrArray *drives;
+        gboolean add_is_sensitive;
+
+        drives = gdu_disk_selection_widget_get_selected_drives (GDU_DISK_SELECTION_WIDGET (dialog->priv->disk_selection_widget));
+        add_is_sensitive = (drives->len > 0);
+        g_ptr_array_unref (drives);
+
+        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
+                                           GTK_RESPONSE_APPLY,
+                                           add_is_sensitive);
+}
+
+static void
+update (GduAddComponentLinuxMdDialog *dialog)
+{
+        update_add_sensitivity (dialog);
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_disk_selection_widget_changed (GduDiskSelectionWidget *widget,
+                                  gpointer                user_data)
+{
+        GduAddComponentLinuxMdDialog *dialog = GDU_ADD_COMPONENT_LINUX_MD_DIALOG (user_data);
+        update_add_sensitivity (dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_add_component_linux_md_dialog_constructed (GObject *object)
+{
+        GduAddComponentLinuxMdDialog *dialog = GDU_ADD_COMPONENT_LINUX_MD_DIALOG (object);
+        GtkWidget *content_area;
+        GtkWidget *hbox;
+        GtkWidget *vbox;
+        GtkWidget *image;
+        GtkWidget *label;
+        gchar *s;
+        GIcon *icon;
+        GduPresentable *p;
+        GduDevice *d;
+        GduPool *pool;
+        GtkWidget *disk_selection_widget;
+        GList *slaves;
+        GduDevice *slave;
+        guint64 component_size;
+        gchar *component_size_str;
+        gchar *array_name;
+        gchar *array_name_vpd;
+
+        slaves = gdu_linux_md_drive_get_slaves (GDU_LINUX_MD_DRIVE (gdu_dialog_get_presentable (GDU_DIALOG (dialog))));
+        slave = GDU_DEVICE (slaves->data);
+        /* TODO: need size slider for e.g. linear arrays */
+        component_size = gdu_device_get_size (slave);
+        component_size_str = gdu_util_get_size_for_display (component_size, FALSE, FALSE);
+        array_name = gdu_presentable_get_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+        array_name_vpd = gdu_presentable_get_vpd_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+
+        gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+        gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+
+        gtk_dialog_add_button (GTK_DIALOG (dialog),
+                               GTK_STOCK_CANCEL,
+                               GTK_RESPONSE_CANCEL);
+
+        gtk_dialog_add_button (GTK_DIALOG (dialog),
+                               GTK_STOCK_ADD,
+                               GTK_RESPONSE_APPLY);
+
+        content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+        icon = gdu_presentable_get_icon (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+
+        hbox = gtk_hbox_new (FALSE, 12);
+        gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0);
+
+        image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
+        gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+        vbox = gtk_vbox_new (FALSE, 12);
+        gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+        p = gdu_dialog_get_presentable (GDU_DIALOG (dialog));
+        d = gdu_presentable_get_device (p);
+        pool = gdu_presentable_get_pool (p);
+
+        s = g_strdup_printf (_("Add Component to %s"), array_name);
+        gtk_window_set_title (GTK_WINDOW (dialog), s);
+        g_free (s);
+
+        /* --- */
+
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+        gtk_label_set_width_chars (GTK_LABEL (label), 70); /* TODO: hate */
+        s = g_strdup_printf (_("Select a disk to create a %s component on for the RAID Array \"%s\" (%s)"),
+                             component_size_str,
+                             array_name,
+                             array_name_vpd);
+        gtk_label_set_markup (GTK_LABEL (label), s);
+        g_free (s);
+        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+        /* --- */
+
+        disk_selection_widget = gdu_disk_selection_widget_new (pool,
+                                                               NULL, /* TODO: ignored_drives */
+                                                               GDU_DISK_SELECTION_WIDGET_FLAGS_NONE);
+        gdu_disk_selection_widget_set_component_size (GDU_DISK_SELECTION_WIDGET (disk_selection_widget),
+                                                      component_size);
+        dialog->priv->disk_selection_widget = disk_selection_widget;
+        gtk_box_pack_start (GTK_BOX (vbox), disk_selection_widget, TRUE, TRUE, 0);
+
+        /* --- */
+
+
+        g_signal_connect (dialog->priv->disk_selection_widget,
+                          "changed",
+                          G_CALLBACK (on_disk_selection_widget_changed),
+                          dialog);
+
+        g_object_unref (icon);
+        g_object_unref (d);
+        g_object_unref (pool);
+
+        /* select a sane size for the widget and allow resizing */
+        gtk_widget_set_size_request (GTK_WIDGET (dialog), 550, 450);
+        gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+
+        update (dialog);
+
+        g_list_foreach (slaves, (GFunc) g_object_unref, NULL);
+        g_list_free (slaves);
+        g_free (component_size_str);
+        g_free (array_name);
+        g_free (array_name_vpd);
+
+        if (G_OBJECT_CLASS (gdu_add_component_linux_md_dialog_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_add_component_linux_md_dialog_parent_class)->constructed (object);
+}
+
+static void
+gdu_add_component_linux_md_dialog_class_init (GduAddComponentLinuxMdDialogClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        g_type_class_add_private (klass, sizeof (GduAddComponentLinuxMdDialogPrivate));
+
+        object_class->get_property = gdu_add_component_linux_md_dialog_get_property;
+        object_class->constructed  = gdu_add_component_linux_md_dialog_constructed;
+        object_class->finalize     = gdu_add_component_linux_md_dialog_finalize;
+
+        g_object_class_install_property (object_class,
+                                         PROP_DRIVE,
+                                         g_param_spec_object ("drive",
+                                                              NULL,
+                                                              NULL,
+                                                              GDU_TYPE_DRIVE,
+                                                              G_PARAM_READABLE));
+
+        g_object_class_install_property (object_class,
+                                         PROP_SIZE,
+                                         g_param_spec_uint64 ("size",
+                                                              NULL,
+                                                              NULL,
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE));
+}
+
+static void
+gdu_add_component_linux_md_dialog_init (GduAddComponentLinuxMdDialog *dialog)
+{
+        dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
+                                                    GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG,
+                                                    GduAddComponentLinuxMdDialogPrivate);
+}
+
+GtkWidget *
+gdu_add_component_linux_md_dialog_new (GtkWindow       *parent,
+                                       GduLinuxMdDrive *linux_md_drive)
+{
+        g_return_val_if_fail (GDU_IS_LINUX_MD_DRIVE (linux_md_drive), NULL);
+        return GTK_WIDGET (g_object_new (GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG,
+                                         "transient-for", parent,
+                                         "presentable", linux_md_drive,
+                                         NULL));
+}
+
+GduDrive *
+gdu_add_component_linux_md_dialog_get_drive (GduAddComponentLinuxMdDialog *dialog)
+{
+        GPtrArray *drives;
+        GduDrive *ret;
+
+        g_return_val_if_fail (GDU_IS_ADD_COMPONENT_LINUX_MD_DIALOG (dialog), NULL);
+
+        ret = NULL;
+        drives = gdu_disk_selection_widget_get_selected_drives (GDU_DISK_SELECTION_WIDGET (dialog->priv->disk_selection_widget));
+        if (drives->len > 0)
+                ret = g_object_ref (GDU_DRIVE (drives->pdata[0]));
+        g_ptr_array_unref (drives);
+
+        return ret;
+}
+
+guint64
+gdu_add_component_linux_md_dialog_get_size  (GduAddComponentLinuxMdDialog *dialog)
+{
+        g_return_val_if_fail (GDU_IS_ADD_COMPONENT_LINUX_MD_DIALOG (dialog), 0);
+        return gdu_disk_selection_widget_get_component_size (GDU_DISK_SELECTION_WIDGET (dialog->priv->disk_selection_widget));
+}
+
diff --git a/src/gdu-gtk/gdu-add-component-linux-md-dialog.h b/src/gdu-gtk/gdu-add-component-linux-md-dialog.h
new file mode 100644
index 0000000..24658e3
--- /dev/null
+++ b/src/gdu-gtk/gdu-add-component-linux-md-dialog.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* Copyright (C) 2009 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#if !defined (__GDU_GTK_INSIDE_GDU_GTK_H) && !defined (GDU_GTK_COMPILATION)
+#error "Only <gdu-gtk/gdu-gtk.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __GDU_ADD_COMPONENT_LINUX_MD_DIALOG_H
+#define __GDU_ADD_COMPONENT_LINUX_MD_DIALOG_H
+
+#include <gdu-gtk/gdu-gtk-types.h>
+#include <gdu-gtk/gdu-dialog.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG            gdu_add_component_linux_md_dialog_get_type()
+#define GDU_ADD_COMPONENT_LINUX_MD_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG, GduAddComponentLinuxMdDialog))
+#define GDU_ADD_COMPONENT_LINUX_MD_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG, GduAddComponentLinuxMdDialogClass))
+#define GDU_IS_ADD_COMPONENT_LINUX_MD_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG))
+#define GDU_IS_ADD_COMPONENT_LINUX_MD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG))
+#define GDU_ADD_COMPONENT_LINUX_MD_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG, GduAddComponentLinuxMdDialogClass))
+
+typedef struct GduAddComponentLinuxMdDialogClass   GduAddComponentLinuxMdDialogClass;
+typedef struct GduAddComponentLinuxMdDialogPrivate GduAddComponentLinuxMdDialogPrivate;
+
+struct GduAddComponentLinuxMdDialog
+{
+        GduDialog parent;
+
+        /*< private >*/
+        GduAddComponentLinuxMdDialogPrivate *priv;
+};
+
+struct GduAddComponentLinuxMdDialogClass
+{
+        GduDialogClass parent_class;
+};
+
+GType         gdu_add_component_linux_md_dialog_get_type  (void) G_GNUC_CONST;
+GtkWidget    *gdu_add_component_linux_md_dialog_new       (GtkWindow                    *parent,
+                                                           GduLinuxMdDrive              *linux_md_drive);
+GduDrive     *gdu_add_component_linux_md_dialog_get_drive (GduAddComponentLinuxMdDialog *dialog);
+guint64       gdu_add_component_linux_md_dialog_get_size  (GduAddComponentLinuxMdDialog *dialog);
+
+G_END_DECLS
+
+#endif /* __GDU_ADD_COMPONENT_LINUX_MD_DIALOG_H */
diff --git a/src/gdu-gtk/gdu-details-element.c b/src/gdu-gtk/gdu-details-element.c
index 9393149..51f90c7 100644
--- a/src/gdu-gtk/gdu-details-element.c
+++ b/src/gdu-gtk/gdu-details-element.c
@@ -41,6 +41,7 @@ struct GduDetailsElementPrivate
         gchar *action_uri;
         gchar *action_tooltip;
         gboolean is_spinning;
+        GtkWidget *widget;
 };
 
 enum
@@ -55,7 +56,8 @@ enum
         PROP_ACTION_TEXT,
         PROP_ACTION_URI,
         PROP_ACTION_TOOLTIP,
-        PROP_IS_SPINNING
+        PROP_IS_SPINNING,
+        PROP_WIDGET
 };
 
 enum
@@ -136,6 +138,10 @@ gdu_details_element_get_property (GObject    *object,
                 g_value_set_boolean (value, gdu_details_element_get_is_spinning (element));
                 break;
 
+        case PROP_WIDGET:
+                g_value_set_object (value, gdu_details_element_get_widget (element));
+                break;
+
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
                 break;
@@ -192,6 +198,10 @@ gdu_details_element_set_property (GObject      *object,
                 gdu_details_element_set_is_spinning (element, g_value_get_boolean (value));
                 break;
 
+        case PROP_WIDGET:
+                gdu_details_element_set_widget (element, g_value_get_object (value));
+                break;
+
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
                 break;
@@ -323,6 +333,16 @@ gdu_details_element_class_init (GduDetailsElementClass *klass)
                                                                G_PARAM_WRITABLE |
                                                                G_PARAM_CONSTRUCT));
 
+        g_object_class_install_property (gobject_class,
+                                         PROP_WIDGET,
+                                         g_param_spec_object ("widget",
+                                                              NULL,
+                                                              NULL,
+                                                              GTK_TYPE_WIDGET,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT));
+
         signals[CHANGED_SIGNAL] = g_signal_new ("changed",
                                                 GDU_TYPE_DETAILS_ELEMENT,
                                                 G_SIGNAL_RUN_LAST,
@@ -497,7 +517,7 @@ gdu_details_element_set_icon (GduDetailsElement *element,
         if (!g_icon_equal (element->priv->icon, icon)) {
                 if (element->priv->icon != NULL)
                         g_object_unref (element->priv->icon);
-                element->priv->icon = g_object_ref (icon);
+                element->priv->icon = icon != NULL ? g_object_ref (icon) : NULL;
                 g_object_notify (G_OBJECT (element), "icon");
                 g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
         }
@@ -554,3 +574,25 @@ gdu_details_element_set_is_spinning (GduDetailsElement *element,
         }
 }
 
+
+/* widget overrides anything else */
+
+GtkWidget *
+gdu_details_element_get_widget (GduDetailsElement *element)
+{
+        g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+        return element->priv->widget;
+}
+
+void
+gdu_details_element_set_widget (GduDetailsElement *element,
+                                GtkWidget         *widget)
+{
+        g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+        if (element->priv->widget != NULL)
+                g_object_unref (element->priv->widget);
+        element->priv->widget = widget != NULL ? g_object_ref_sink (widget) : NULL;
+        g_object_notify (G_OBJECT (element), "widget");
+        g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+}
+
diff --git a/src/gdu-gtk/gdu-details-element.h b/src/gdu-gtk/gdu-details-element.h
index ebc0854..037d7de 100644
--- a/src/gdu-gtk/gdu-details-element.h
+++ b/src/gdu-gtk/gdu-details-element.h
@@ -71,6 +71,7 @@ const gchar        *gdu_details_element_get_action_text    (GduDetailsElement *e
 const gchar        *gdu_details_element_get_action_uri     (GduDetailsElement *element);
 const gchar        *gdu_details_element_get_action_tooltip (GduDetailsElement *element);
 gboolean            gdu_details_element_get_is_spinning    (GduDetailsElement *element);
+GtkWidget          *gdu_details_element_get_widget         (GduDetailsElement *element);
 
 void                gdu_details_element_set_heading        (GduDetailsElement *element,
                                                             const gchar       *heading);
@@ -92,6 +93,8 @@ void                gdu_details_element_set_action_tooltip (GduDetailsElement *e
                                                             const gchar       *action_tooltip);
 void                gdu_details_element_set_is_spinning    (GduDetailsElement *element,
                                                             gboolean           is_spinning);
+void                gdu_details_element_set_widget         (GduDetailsElement *element,
+                                                            GtkWidget         *widget);
 
 G_END_DECLS
 
diff --git a/src/gdu-gtk/gdu-details-table.c b/src/gdu-gtk/gdu-details-table.c
index 2784a0e..345d8c7 100644
--- a/src/gdu-gtk/gdu-details-table.c
+++ b/src/gdu-gtk/gdu-details-table.c
@@ -229,6 +229,7 @@ typedef struct {
         GtkWidget *action_hyphen_label;
         GtkWidget *action_label;
         GtkWidget *progress_bar;
+        GtkWidget *widget_bin;
 } ElementData;
 
 static void on_details_element_changed (GduDetailsElement *element,
@@ -264,6 +265,7 @@ on_details_element_changed (GduDetailsElement *element,
         const gchar *action_tooltip;
         guint64 time;
         gdouble progress;
+        GtkWidget *widget;
 
         s = g_strdup_printf ("<span fgcolor='#404040'>%s</span>",
                              gdu_details_element_get_heading (element));
@@ -348,6 +350,23 @@ on_details_element_changed (GduDetailsElement *element,
                 gtk_widget_set_no_show_all (data->progress_bar, TRUE);
                 gtk_widget_hide (data->progress_bar);
         }
+
+        widget = gdu_details_element_get_widget (element);
+        if (widget != NULL) {
+                GtkWidget *child;
+                child = gtk_bin_get_child (GTK_BIN (data->widget_bin));
+                if (child != widget) {
+                        if (child != NULL)
+                                gtk_container_remove (GTK_CONTAINER (data->widget_bin), child);
+                        gtk_container_add (GTK_CONTAINER (data->widget_bin), widget);
+                }
+        } else {
+                GtkWidget *child;
+                child = gtk_bin_get_child (GTK_BIN (data->widget_bin));
+                if (child != NULL) {
+                        gtk_container_remove (GTK_CONTAINER (data->widget_bin), child);
+                }
+        }
 }
 
 static void
@@ -419,7 +438,7 @@ do_relayout (GduDetailsTable *table)
                 data->element = g_object_ref (element);
 
                 data->heading_label = gtk_label_new (NULL);
-                gtk_misc_set_alignment (GTK_MISC (data->heading_label), 0.0, 0.5);
+                gtk_misc_set_alignment (GTK_MISC (data->heading_label), 0.0, 0.0);
                 gtk_table_attach (GTK_TABLE (column_table),
                                   data->heading_label,
                                   0, 1, row, row + 1,
@@ -453,6 +472,9 @@ do_relayout (GduDetailsTable *table)
                 gtk_misc_set_alignment (GTK_MISC (data->action_label), 0.0, 0.5);
                 gtk_box_pack_start (GTK_BOX (hbox), data->action_label, FALSE, FALSE, 0);
 
+                data->widget_bin = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+                gtk_box_pack_start (GTK_BOX (hbox), data->widget_bin, FALSE, FALSE, 0);
+
                 gtk_table_attach (GTK_TABLE (column_table),
                                   hbox,
                                   1, 2, row, row + 1,
diff --git a/src/gdu-gtk/gdu-disk-selection-widget.c b/src/gdu-gtk/gdu-disk-selection-widget.c
new file mode 100644
index 0000000..3b74f74
--- /dev/null
+++ b/src/gdu-gtk/gdu-disk-selection-widget.c
@@ -0,0 +1,1032 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <math.h>
+
+#include "gdu-disk-selection-widget.h"
+#include "gdu-size-widget.h"
+
+struct GduDiskSelectionWidgetPrivate
+{
+        GduPool *pool;
+        GduDiskSelectionWidgetFlags flags;
+
+        GtkTreeModel *model;
+        GtkWidget *tree_view;
+
+        guint64 component_size;
+
+        /* A list of GduDrive objects that are selected */
+        GList *selected_drives;
+
+        /* A list of GduDrive objects that are ignored */
+        GPtrArray *ignored_drives;
+};
+
+enum
+{
+        PROP_0,
+        PROP_POOL,
+        PROP_FLAGS,
+        PROP_SELECTED_DRIVES,
+        PROP_IGNORED_DRIVES,
+        PROP_COMPONENT_SIZE,
+        PROP_LARGEST_FREE_SEGMENT
+};
+
+enum
+{
+        CHANGED_SIGNAL,
+        LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void gdu_disk_selection_widget_constructed (GObject *object);
+
+static void update (GduDiskSelectionWidget *widget);
+
+static void on_presentable_added   (GduPool          *pool,
+                                    GduPresentable   *presentable,
+                                    gpointer          user_data);
+static void on_presentable_removed (GduPool          *pool,
+                                    GduPresentable   *presentable,
+                                    gpointer          user_data);
+static void on_presentable_changed (GduPool          *pool,
+                                    GduPresentable   *presentable,
+                                    gpointer          user_data);
+
+static void on_row_changed (GtkTreeModel *tree_model,
+                            GtkTreePath  *path,
+                            GtkTreeIter  *iter,
+                            gpointer      user_data);
+
+static void on_row_deleted (GtkTreeModel *tree_model,
+                            GtkTreePath  *path,
+                            gpointer      user_data);
+
+static void on_row_inserted (GtkTreeModel *tree_model,
+                             GtkTreePath  *path,
+                             GtkTreeIter  *iter,
+                             gpointer      user_data);
+
+G_DEFINE_TYPE (GduDiskSelectionWidget, gdu_disk_selection_widget, GTK_TYPE_VBOX)
+
+static void
+gdu_disk_selection_widget_finalize (GObject *object)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (object);
+
+        g_signal_handlers_disconnect_by_func (widget->priv->pool, on_presentable_added, widget);
+        g_signal_handlers_disconnect_by_func (widget->priv->pool, on_presentable_removed, widget);
+        g_signal_handlers_disconnect_by_func (widget->priv->pool, on_presentable_changed, widget);
+        g_signal_handlers_disconnect_by_func (widget->priv->model, on_row_changed, widget);
+        g_signal_handlers_disconnect_by_func (widget->priv->model, on_row_deleted, widget);
+        g_signal_handlers_disconnect_by_func (widget->priv->model, on_row_inserted, widget);
+
+        g_object_unref (widget->priv->pool);
+        g_object_unref (widget->priv->model);
+
+        g_list_foreach (widget->priv->selected_drives, (GFunc) g_object_unref, NULL);
+        g_list_free (widget->priv->selected_drives);
+
+        if (widget->priv->ignored_drives != NULL)
+                g_ptr_array_unref (widget->priv->ignored_drives);
+
+        if (G_OBJECT_CLASS (gdu_disk_selection_widget_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_disk_selection_widget_parent_class)->finalize (object);
+}
+
+static void
+gdu_disk_selection_widget_get_property (GObject    *object,
+                                         guint       property_id,
+                                         GValue     *value,
+                                         GParamSpec *pspec)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (object);
+        GPtrArray *p;
+
+        switch (property_id) {
+        case PROP_POOL:
+                g_value_set_object (value, widget->priv->pool);
+                break;
+
+        case PROP_FLAGS:
+                g_value_set_flags (value, widget->priv->flags);
+                break;
+
+        case PROP_SELECTED_DRIVES:
+                p = gdu_disk_selection_widget_get_selected_drives (widget);
+                g_value_set_boxed (value, p);
+                g_ptr_array_unref (p);
+                break;
+
+        case PROP_IGNORED_DRIVES:
+                p = gdu_disk_selection_widget_get_ignored_drives (widget);
+                g_value_set_boxed (value, p);
+                g_ptr_array_unref (p);
+                break;
+
+        case PROP_COMPONENT_SIZE:
+                g_value_set_uint64 (value, gdu_disk_selection_widget_get_component_size (widget));
+                break;
+
+        case PROP_LARGEST_FREE_SEGMENT:
+                g_value_set_uint64 (value, gdu_disk_selection_widget_get_largest_free_segment (widget));
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_disk_selection_widget_set_property (GObject      *object,
+                                         guint         property_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (object);
+
+        switch (property_id) {
+        case PROP_POOL:
+                widget->priv->pool = g_value_dup_object (value);
+                break;
+
+        case PROP_FLAGS:
+                widget->priv->flags = g_value_get_flags (value);
+                break;
+
+        case PROP_IGNORED_DRIVES:
+                widget->priv->ignored_drives = g_value_dup_boxed (value);
+                break;
+
+        case PROP_COMPONENT_SIZE:
+                gdu_disk_selection_widget_set_component_size (widget, g_value_get_uint64 (value));
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_disk_selection_widget_class_init (GduDiskSelectionWidgetClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        g_type_class_add_private (klass, sizeof (GduDiskSelectionWidgetPrivate));
+
+        object_class->get_property = gdu_disk_selection_widget_get_property;
+        object_class->set_property = gdu_disk_selection_widget_set_property;
+        object_class->constructed  = gdu_disk_selection_widget_constructed;
+        object_class->finalize     = gdu_disk_selection_widget_finalize;
+
+        g_object_class_install_property (object_class,
+                                         PROP_POOL,
+                                         g_param_spec_object ("pool",
+                                                              _("Pool"),
+                                                              _("The pool of devices"),
+                                                              GDU_TYPE_POOL,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_FLAGS,
+                                         g_param_spec_flags ("flags",
+                                                             _("Flags"),
+                                                             _("Flags for the widget"),
+                                                             GDU_TYPE_DISK_SELECTION_WIDGET_FLAGS,
+                                                             GDU_DISK_SELECTION_WIDGET_FLAGS_NONE,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT_ONLY |
+                                                             G_PARAM_STATIC_NAME |
+                                                             G_PARAM_STATIC_NICK |
+                                                             G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_SELECTED_DRIVES,
+                                         g_param_spec_boxed ("selected-drives",
+                                                             _("Selected Drives"),
+                                                             _("Array of selected drives"),
+                                                             G_TYPE_PTR_ARRAY,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_STATIC_NAME |
+                                                             G_PARAM_STATIC_NICK |
+                                                             G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_IGNORED_DRIVES,
+                                         g_param_spec_boxed ("ignored-drives",
+                                                             _("Ignored Drives"),
+                                                             _("Array of drives to ignore"),
+                                                             G_TYPE_PTR_ARRAY,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT_ONLY |
+                                                             G_PARAM_STATIC_NAME |
+                                                             G_PARAM_STATIC_NICK |
+                                                             G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_LARGEST_FREE_SEGMENT,
+                                         g_param_spec_uint64 ("largest-free-segment",
+                                                              _("Largest Free Segment"),
+                                                              _("The largest free segment on the available drives"),
+                                                              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 to use in the details header"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+                                                G_TYPE_FROM_CLASS (klass),
+                                                G_SIGNAL_RUN_LAST,
+                                                G_STRUCT_OFFSET (GduDiskSelectionWidgetClass, changed),
+                                                NULL,
+                                                NULL,
+                                                g_cclosure_marshal_VOID__VOID,
+                                                G_TYPE_NONE,
+                                                0);
+
+}
+
+static void
+gdu_disk_selection_widget_init (GduDiskSelectionWidget *widget)
+{
+        widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (widget,
+                                                    GDU_TYPE_DISK_SELECTION_WIDGET,
+                                                    GduDiskSelectionWidgetPrivate);
+}
+
+GtkWidget *
+gdu_disk_selection_widget_new (GduPool                    *pool,
+                               GPtrArray                  *drives_to_ignore,
+                               GduDiskSelectionWidgetFlags flags)
+{
+        return GTK_WIDGET (g_object_new (GDU_TYPE_DISK_SELECTION_WIDGET,
+                                         "pool", pool,
+                                         "ignored-drives", drives_to_ignore,
+                                         "flags", flags,
+                                         NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+GPtrArray *
+gdu_disk_selection_widget_get_selected_drives (GduDiskSelectionWidget  *widget)
+{
+        GPtrArray *p;
+        GList *l;
+
+        g_return_val_if_fail (GDU_IS_DISK_SELECTION_WIDGET (widget), NULL);
+
+        p = g_ptr_array_new_with_free_func (g_object_unref);
+        for (l = widget->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;
+}
+
+GPtrArray *
+gdu_disk_selection_widget_get_ignored_drives (GduDiskSelectionWidget  *widget)
+{
+        return widget->priv->ignored_drives != NULL ? g_ptr_array_ref (widget->priv->ignored_drives) : NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+drive_is_selected (GduDiskSelectionWidget *widget,
+                   GduPresentable         *drive)
+{
+        return g_list_find (widget->priv->selected_drives, drive) != NULL;
+}
+
+static void
+drive_remove (GduDiskSelectionWidget *widget,
+              GduPresentable         *drive)
+{
+        GList *l;
+
+        l = g_list_find (widget->priv->selected_drives, drive);
+        if (l != NULL) {
+                g_object_unref (l->data);
+                widget->priv->selected_drives = g_list_delete_link (widget->priv->selected_drives,
+                                                                    l);
+        }
+}
+
+static void
+drive_add (GduDiskSelectionWidget *widget,
+           GduPresentable         *drive)
+{
+        g_return_if_fail (!drive_is_selected (widget, drive));
+
+        widget->priv->selected_drives = g_list_prepend (widget->priv->selected_drives,
+                                                        g_object_ref (drive));
+}
+
+
+static void
+drive_toggle (GduDiskSelectionWidget *widget,
+              GduPresentable         *drive)
+{
+        if (drive_is_selected (widget, drive)) {
+                drive_remove (widget, drive);
+        } else {
+                drive_add (widget, drive);
+        }
+}
+
+
+static void
+toggle_data_func (GtkCellLayout   *cell_layout,
+                  GtkCellRenderer *renderer,
+                  GtkTreeModel    *tree_model,
+                  GtkTreeIter     *iter,
+                  gpointer         user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (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 (widget, p);
+
+        g_object_set (renderer,
+                      "active", is_toggled,
+                      NULL);
+
+        g_object_unref (p);
+}
+
+static gboolean
+update_all_func (GtkTreeModel *model,
+                 GtkTreePath  *path,
+                 GtkTreeIter  *iter,
+                 gpointer      user_data)
+{
+        gtk_tree_model_row_changed (model, path, iter);
+        return FALSE; /* keep iterating */
+}
+
+static void
+on_disk_toggled (GtkCellRendererToggle *renderer,
+                 const gchar           *path_string,
+                 gpointer               user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+        GtkTreeIter iter;
+        GtkTreePath *path;
+        GduPresentable *p;
+
+        if (!gtk_tree_model_get_iter_from_string (widget->priv->model,
+                                                  &iter,
+                                                  path_string))
+                goto out;
+
+        gtk_tree_model_get (widget->priv->model,
+                            &iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+                            -1);
+
+        if (! (widget->priv->flags & GDU_DISK_SELECTION_WIDGET_FLAGS_ALLOW_MULTIPLE)) {
+                /* untoggle all */
+                g_list_foreach (widget->priv->selected_drives, (GFunc) g_object_unref, NULL);
+                g_list_free (widget->priv->selected_drives);
+                widget->priv->selected_drives = NULL;
+
+                drive_toggle (widget, p);
+
+                gtk_tree_model_foreach (widget->priv->model,
+                                        update_all_func,
+                                        NULL);
+        } else {
+                drive_toggle (widget, p);
+                path = gtk_tree_model_get_path (widget->priv->model,
+                                                &iter);
+                gtk_tree_model_row_changed (widget->priv->model,
+                                            path,
+                                            &iter);
+                gtk_tree_path_free (path);
+        }
+
+        g_object_unref (p);
+        update (widget);
+
+ out:
+        ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+disk_name_data_func (GtkCellLayout   *cell_layout,
+                     GtkCellRenderer *renderer,
+                     GtkTreeModel    *tree_model,
+                     GtkTreeIter     *iter,
+                     gpointer         user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (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 (widget->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 (widget->priv->tree_view));
+        if (gtk_tree_selection_iter_is_selected (tree_selection, iter)) {
+                if (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (widget->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 gboolean
+count_num_available_disks_func (GtkTreeModel *model,
+                                GtkTreePath  *path,
+                                GtkTreeIter  *iter,
+                                gpointer      data)
+{
+        GduPresentable *p;
+        guint *num_available_disks = data;
+
+        gtk_tree_model_get (model,
+                            iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+                            -1);
+
+        if (GDU_IS_DRIVE (p))
+                *num_available_disks = *num_available_disks + 1;
+
+        g_object_unref (p);
+
+        return FALSE;
+}
+
+static void
+get_sizes (GduDiskSelectionWidget *widget,
+           guint                  *out_num_disks,
+           guint                  *out_num_available_disks,
+           guint64                *out_largest_free_segment)
+{
+        guint num_disks;
+        guint num_available_disks;
+        guint64 largest_free_segment;
+        GList *l;
+
+        num_disks = 0;
+        num_available_disks = 0;
+        largest_free_segment = G_MAXUINT64;
+
+        for (l = widget->priv->selected_drives; l != NULL; l = l->next) {
+                GduPresentable *p = GDU_PRESENTABLE (l->data);
+                guint64 largest_segment;
+                gboolean whole_disk_is_uninitialized;
+
+                g_warn_if_fail (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
+                                                                 &whole_disk_is_uninitialized,
+                                                                 &largest_segment,
+                                                                 NULL));
+
+                if (largest_segment < largest_free_segment)
+                        largest_free_segment = largest_segment;
+
+                num_disks++;
+        }
+        if (largest_free_segment == G_MAXUINT64)
+                largest_free_segment = 0;
+
+        gtk_tree_model_foreach (widget->priv->model,
+                                count_num_available_disks_func,
+                                &num_available_disks);
+
+        if (out_num_disks != NULL)
+                *out_num_disks = num_disks;
+
+        if (out_num_available_disks != NULL)
+                *out_num_available_disks = num_available_disks;
+
+        if (out_largest_free_segment != NULL)
+                *out_largest_free_segment = largest_free_segment;
+}
+
+static void
+notes_data_func (GtkCellLayout   *cell_layout,
+                 GtkCellRenderer *renderer,
+                 GtkTreeModel    *tree_model,
+                 GtkTreeIter     *iter,
+                 gpointer         user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (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 (widget, p)) {
+                        guint num_disks;
+                        guint num_available_disks;
+                        guint64 largest_free_segment;
+                        gchar *strsize;
+
+                        get_sizes (widget,
+                                   &num_disks,
+                                   &num_available_disks,
+                                   &largest_free_segment);
+
+                        strsize = gdu_util_get_size_for_display (widget->priv->component_size, FALSE, 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 {
+                        gchar *strsize;
+
+                        strsize = gdu_util_get_size_for_display (largest_segment, FALSE, 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 (_("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 gboolean
+model_visible_func (GtkTreeModel  *model,
+                    GtkTreeIter   *iter,
+                    gpointer       user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+        GduPresentable *p;
+        gboolean ret;
+
+        ret = FALSE;
+
+        /* Only show a drive if it has enough free space */
+        gtk_tree_model_get (model,
+                            iter,
+                            GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+                            -1);
+        if (p != NULL) {
+                guint64 largest_segment;
+                gboolean whole_disk_is_uninitialized;
+
+                if (gdu_drive_has_unallocated_space (GDU_DRIVE (p),
+                                                     &whole_disk_is_uninitialized,
+                                                     &largest_segment,
+                                                     NULL)) {
+                        if (largest_segment >= widget->priv->component_size) {
+                                ret = TRUE;
+                        }
+                }
+                g_object_unref (p);
+        }
+
+        return ret;
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_disk_selection_widget_constructed (GObject *object)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (object);
+        GtkWidget *tree_view;
+        GtkWidget *scrolled_window;
+        GtkCellRenderer *renderer;
+        GtkTreeViewColumn *column;
+        GtkTreeModel *model;
+
+        model = GTK_TREE_MODEL (gdu_pool_tree_model_new (widget->priv->pool,
+                                                         NULL,
+                                                         GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES |
+                                                         GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES));
+
+        widget->priv->model = gtk_tree_model_filter_new (model, NULL);
+        g_object_unref (model);
+        gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (widget->priv->model),
+                                                model_visible_func,
+                                                widget,
+                                                NULL);
+
+        tree_view = gtk_tree_view_new_with_model (widget->priv->model);
+        gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
+        widget->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 ();
+        if (! (widget->priv->flags & GDU_DISK_SELECTION_WIDGET_FLAGS_ALLOW_MULTIPLE))
+                gtk_cell_renderer_toggle_set_radio (GTK_CELL_RENDERER_TOGGLE (renderer), TRUE);
+        gtk_tree_view_column_pack_start (column,
+                                         renderer,
+                                         FALSE);
+        g_signal_connect (renderer,
+                          "toggled",
+                          G_CALLBACK (on_disk_toggled),
+                          widget);
+        gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+                                            renderer,
+                                            toggle_data_func,
+                                            widget,
+                                            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,
+                                            widget,
+                                            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,
+                                            widget,
+                                            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,
+                                        GTK_POLICY_AUTOMATIC);
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
+                                             GTK_SHADOW_IN);
+
+        gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
+
+        gtk_box_pack_start (GTK_BOX (widget), scrolled_window, TRUE, TRUE, 0);
+
+        /* -------------------------------------------------------------------------------- */
+
+        g_signal_connect (widget->priv->pool,
+                          "presentable-added",
+                          G_CALLBACK (on_presentable_added),
+                          widget);
+        g_signal_connect (widget->priv->pool,
+                          "presentable-removed",
+                          G_CALLBACK (on_presentable_removed),
+                          widget);
+        g_signal_connect (widget->priv->pool,
+                          "presentable-changed",
+                          G_CALLBACK (on_presentable_changed),
+                          widget);
+        g_signal_connect (widget->priv->model,
+                          "row-changed",
+                          G_CALLBACK (on_row_changed),
+                          widget);
+        g_signal_connect (widget->priv->model,
+                          "row-deleted",
+                          G_CALLBACK (on_row_deleted),
+                          widget);
+        g_signal_connect (widget->priv->model,
+                          "row-inserted",
+                          G_CALLBACK (on_row_inserted),
+                          widget);
+
+        if (G_OBJECT_CLASS (gdu_disk_selection_widget_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_disk_selection_widget_parent_class)->constructed (object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_presentable_added (GduPool          *pool,
+                      GduPresentable   *presentable,
+                      gpointer          user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+        update (widget);
+}
+
+static void
+on_presentable_removed (GduPool          *pool,
+                        GduPresentable   *presentable,
+                        gpointer          user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+
+        if (drive_is_selected (widget, presentable))
+                drive_remove (widget, presentable);
+
+        update (widget);
+}
+
+static void
+on_presentable_changed (GduPool          *pool,
+                        GduPresentable   *presentable,
+                        gpointer          user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+        update (widget);
+}
+
+static void
+on_row_changed (GtkTreeModel *tree_model,
+                GtkTreePath  *path,
+                GtkTreeIter  *iter,
+                gpointer      user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+        update (widget);
+}
+
+static void
+on_row_deleted (GtkTreeModel *tree_model,
+                GtkTreePath  *path,
+                gpointer      user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+        update (widget);
+}
+
+static void
+on_row_inserted (GtkTreeModel *tree_model,
+                 GtkTreePath  *path,
+                 GtkTreeIter  *iter,
+                 gpointer      user_data)
+{
+        GduDiskSelectionWidget *widget = GDU_DISK_SELECTION_WIDGET (user_data);
+        update (widget);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+guint64
+gdu_disk_selection_widget_get_component_size (GduDiskSelectionWidget *widget)
+{
+        g_return_val_if_fail (GDU_IS_DISK_SELECTION_WIDGET (widget), 0);
+        return widget->priv->component_size;
+}
+
+void
+gdu_disk_selection_widget_set_component_size (GduDiskSelectionWidget *widget,
+                                              guint64                 component_size)
+{
+        g_return_if_fail (GDU_IS_DISK_SELECTION_WIDGET (widget));
+        widget->priv->component_size = component_size;
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->model));
+}
+
+guint64
+gdu_disk_selection_widget_get_largest_free_segment (GduDiskSelectionWidget *widget)
+{
+        guint64 largest_free_segment;
+
+        g_return_val_if_fail (GDU_IS_DISK_SELECTION_WIDGET (widget), 0);
+
+        get_sizes (widget,
+                   NULL,
+                   NULL,
+                   &largest_free_segment);
+
+        return largest_free_segment;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update (GduDiskSelectionWidget *widget)
+{
+        g_signal_emit (widget, signals[CHANGED_SIGNAL], 0);
+}
+
diff --git a/src/gdu-gtk/gdu-disk-selection-widget.h b/src/gdu-gtk/gdu-disk-selection-widget.h
new file mode 100644
index 0000000..34eaeab
--- /dev/null
+++ b/src/gdu-gtk/gdu-disk-selection-widget.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GDU_DISK_SELECTION_WIDGET_H
+#define __GDU_DISK_SELECTION_WIDGET_H
+
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_DISK_SELECTION_WIDGET         (gdu_disk_selection_widget_get_type())
+#define GDU_DISK_SELECTION_WIDGET(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_DISK_SELECTION_WIDGET, GduDiskSelectionWidget))
+#define GDU_DISK_SELECTION_WIDGET_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_DISK_SELECTION_WIDGET, GduDiskSelectionWidgetClass))
+#define GDU_IS_DISK_SELECTION_WIDGET(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_DISK_SELECTION_WIDGET))
+#define GDU_IS_DISK_SELECTION_WIDGET_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_DISK_SELECTION_WIDGET))
+#define GDU_DISK_SELECTION_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_DISK_SELECTION_WIDGET, GduDiskSelectionWidgetClass))
+
+typedef struct GduDiskSelectionWidgetClass   GduDiskSelectionWidgetClass;
+typedef struct GduDiskSelectionWidgetPrivate GduDiskSelectionWidgetPrivate;
+
+struct GduDiskSelectionWidget
+{
+        GtkVBox parent;
+
+        /*< private >*/
+        GduDiskSelectionWidgetPrivate *priv;
+};
+
+struct GduDiskSelectionWidgetClass
+{
+        GtkVBoxClass parent_class;
+
+        void (*changed) (GduDiskSelectionWidget *widget);
+};
+
+GType       gdu_disk_selection_widget_get_type                 (void) G_GNUC_CONST;
+GtkWidget  *gdu_disk_selection_widget_new                      (GduPool                     *pool,
+                                                                GPtrArray                   *drives_to_ignore,
+                                                                GduDiskSelectionWidgetFlags  flags);
+GPtrArray  *gdu_disk_selection_widget_get_ignored_drives       (GduDiskSelectionWidget      *widget);
+GPtrArray  *gdu_disk_selection_widget_get_selected_drives      (GduDiskSelectionWidget      *widget);
+guint64     gdu_disk_selection_widget_get_component_size       (GduDiskSelectionWidget      *widget);
+void        gdu_disk_selection_widget_set_component_size       (GduDiskSelectionWidget      *widget,
+                                                                guint64                      component_size);
+guint64     gdu_disk_selection_widget_get_largest_free_segment (GduDiskSelectionWidget      *widget);
+
+G_END_DECLS
+
+#endif  /* __GDU_DISK_SELECTION_WIDGET_H */
+
diff --git a/src/gdu-gtk/gdu-edit-linux-md-dialog.c b/src/gdu-gtk/gdu-edit-linux-md-dialog.c
new file mode 100644
index 0000000..3011e31
--- /dev/null
+++ b/src/gdu-gtk/gdu-edit-linux-md-dialog.c
@@ -0,0 +1,864 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <math.h>
+
+#include "gdu-edit-linux-md-dialog.h"
+#include "gdu-size-widget.h"
+
+struct GduEditLinuxMdDialogPrivate
+{
+        gulong changed_id;
+        gulong removed_id;
+
+        GtkWidget *components_tree_view;
+        GtkTreeStore *components_tree_store;
+
+        GduDetailsElement *component_smart_element;
+        GduDetailsElement *component_position_element;
+        GduDetailsElement *component_state_element;
+        GduDetailsElement *component_device_element;
+
+        GduButtonElement *component_new_button;
+        GduButtonElement *component_attach_button;
+        GduButtonElement *component_remove_button;
+
+};
+
+enum {
+        NEW_BUTTON_CLICKED_SIGNAL,
+        ATTACH_BUTTON_CLICKED_SIGNAL,
+        REMOVE_BUTTON_CLICKED_SIGNAL,
+        LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+        MD_LINUX_SLAVE_VOLUME_COLUMN,
+        MD_LINUX_SLAVE_DRIVE_COLUMN,
+        MD_LINUX_POSITION_COLUMN,
+        MD_LINUX_POSITION_STRING_COLUMN,
+        MD_LINUX_ICON_COLUMN,
+        MD_LINUX_OBJPATH_COLUMN,
+        MD_LINUX_SLAVE_STATE_STRING_COLUMN,
+        MD_LINUX_N_COLUMNS,
+};
+
+static void gdu_edit_linux_md_dialog_constructed (GObject *object);
+
+static void update_tree (GduEditLinuxMdDialog *dialog);
+static void update_details (GduEditLinuxMdDialog *dialog);
+
+static GduDevice *get_selected_component (GduEditLinuxMdDialog *dialog);
+
+G_DEFINE_TYPE (GduEditLinuxMdDialog, gdu_edit_linux_md_dialog, GDU_TYPE_DIALOG)
+
+static void
+gdu_edit_linux_md_dialog_finalize (GObject *object)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (object);
+
+        if (dialog->priv->changed_id > 0) {
+                g_signal_handler_disconnect (gdu_dialog_get_presentable (GDU_DIALOG (dialog)),
+                                             dialog->priv->changed_id);
+        }
+        if (dialog->priv->removed_id > 0) {
+                g_signal_handler_disconnect (gdu_dialog_get_presentable (GDU_DIALOG (dialog)),
+                                             dialog->priv->removed_id);
+        }
+
+        if (G_OBJECT_CLASS (gdu_edit_linux_md_dialog_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_edit_linux_md_dialog_parent_class)->finalize (object);
+}
+
+static void
+gdu_edit_linux_md_dialog_class_init (GduEditLinuxMdDialogClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        g_type_class_add_private (klass, sizeof (GduEditLinuxMdDialogPrivate));
+
+        object_class->constructed  = gdu_edit_linux_md_dialog_constructed;
+        object_class->finalize     = gdu_edit_linux_md_dialog_finalize;
+
+        signals[NEW_BUTTON_CLICKED_SIGNAL] =
+                g_signal_new ("new-button-clicked",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduEditLinuxMdDialogClass, new_button_clicked),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+
+        signals[ATTACH_BUTTON_CLICKED_SIGNAL] =
+                g_signal_new ("attach-button-clicked",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduEditLinuxMdDialogClass, attach_button_clicked),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE,
+                              1,
+                              GDU_TYPE_DEVICE);
+
+        signals[REMOVE_BUTTON_CLICKED_SIGNAL] =
+                g_signal_new ("remove-button-clicked",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduEditLinuxMdDialogClass, attach_button_clicked),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE,
+                              1,
+                              GDU_TYPE_DEVICE);
+}
+
+static void
+gdu_edit_linux_md_dialog_init (GduEditLinuxMdDialog *dialog)
+{
+        dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
+                                                    GDU_TYPE_EDIT_LINUX_MD_DIALOG,
+                                                    GduEditLinuxMdDialogPrivate);
+}
+
+GtkWidget *
+gdu_edit_linux_md_dialog_new (GtkWindow        *parent,
+                              GduLinuxMdDrive  *linux_md_drive)
+{
+        g_return_val_if_fail (GDU_IS_LINUX_MD_DRIVE (linux_md_drive), NULL);
+        return GTK_WIDGET (g_object_new (GDU_TYPE_EDIT_LINUX_MD_DIALOG,
+                                         "transient-for", parent,
+                                         "presentable", linux_md_drive,
+                                         NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_component_new_button_clicked (GduButtonElement *button_element,
+                                 gpointer          user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+        g_signal_emit (dialog, signals[NEW_BUTTON_CLICKED_SIGNAL], 0);
+}
+
+static void
+on_component_attach_button_clicked (GduButtonElement *button_element,
+                                    gpointer          user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+        GduDevice *slave;
+
+        slave = get_selected_component (dialog);
+        g_signal_emit (dialog, signals[ATTACH_BUTTON_CLICKED_SIGNAL], 0, slave);
+        g_object_unref (slave);
+}
+
+static void
+on_component_remove_button_clicked (GduButtonElement *button_element,
+                                    gpointer          user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+        GduDevice *slave;
+
+        slave = get_selected_component (dialog);
+        g_signal_emit (dialog, signals[REMOVE_BUTTON_CLICKED_SIGNAL], 0, slave);
+        g_object_unref (slave);
+}
+
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+format_markup (GtkCellLayout   *cell_layout,
+               GtkCellRenderer *renderer,
+               GtkTreeModel    *tree_model,
+               GtkTreeIter     *iter,
+               gpointer         user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+        GtkTreeSelection *tree_selection;
+        gchar *name;
+        gchar *drive_name;
+        GduPresentable *volume_for_slave;
+        GduPresentable *drive_for_slave;
+        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->components_tree_view));
+
+        gtk_tree_model_get (tree_model,
+                            iter,
+                            MD_LINUX_SLAVE_VOLUME_COLUMN, &volume_for_slave,
+                            MD_LINUX_SLAVE_DRIVE_COLUMN, &drive_for_slave,
+                            -1);
+
+        /* This color business shouldn't be this hard... */
+        style = gtk_widget_get_style (GTK_WIDGET (dialog->priv->components_tree_view));
+        if (gtk_tree_selection_iter_is_selected (tree_selection, iter)) {
+                if (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (dialog->priv->components_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));
+
+        name = gdu_presentable_get_vpd_name (volume_for_slave);
+        if (drive_for_slave != NULL) {
+                drive_name = gdu_presentable_get_vpd_name (drive_for_slave);
+        } else {
+                drive_name = g_strdup ("");
+        }
+
+        markup = g_strdup_printf ("<b>%s</b>\n"
+                                  "<span fgcolor=\"%s\"><small>%s</small></span>",
+                                  name,
+                                  desc_color,
+                                  drive_name);
+
+        g_object_set (renderer,
+                      "markup", markup,
+                      NULL);
+
+        g_free (name);
+        g_free (drive_name);
+        g_free (markup);
+        g_free (desc_color);
+        g_object_unref (volume_for_slave);
+        if (drive_for_slave != NULL)
+                g_object_unref (drive_for_slave);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_component_tree_selection_changed  (GtkTreeSelection *selection,
+                                      gpointer          user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+
+        update_details (dialog);
+}
+
+static void
+on_linux_md_drive_changed (GduPresentable   *presentable,
+                           gpointer          user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+
+        update_tree (dialog);
+
+        /* close the dialog if the RAID array stops */
+        if (!gdu_drive_is_active (GDU_DRIVE (gdu_dialog_get_presentable (GDU_DIALOG (dialog))))) {
+                gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+        }
+}
+
+static void
+on_linux_md_drive_removed (GduPresentable   *presentable,
+                           gpointer          user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+
+        /* close the dialog if the RAID array disappears */
+        gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+}
+
+static void
+gdu_edit_linux_md_dialog_constructed (GObject *object)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (object);
+        GduLinuxMdDrive *linux_md_drive;
+        GtkWidget *content_area;
+        GtkWidget *vbox;
+        GtkWidget *vbox2;
+        GtkWidget *hbox;
+        GtkWidget *align;
+        GIcon *icon;
+        GtkWidget *image;
+        GtkWidget *table;
+        GtkWidget *label;
+        gchar *s;
+        gchar *name;
+        gchar *vpd_name;
+        GPtrArray *elements;
+        GduDetailsElement *element;
+        GtkWidget *tree_view;
+        GtkWidget *scrolled_window;
+        GtkTreeSelection *selection;
+        GtkTreeViewColumn *column;
+        GtkCellRenderer *renderer;
+        GduButtonElement *button_element;
+
+        linux_md_drive = GDU_LINUX_MD_DRIVE (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+
+        icon = gdu_presentable_get_icon (GDU_PRESENTABLE (linux_md_drive));
+
+        content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+        gtk_container_set_border_width (GTK_CONTAINER (content_area), 10);
+
+        hbox = gtk_hbox_new (FALSE, 12);
+        gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0);
+
+        image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
+        gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+        vbox = gtk_vbox_new (FALSE, 6);
+        gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+
+        gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+        gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+        gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 0);
+        gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
+        gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
+
+        name = gdu_presentable_get_name (GDU_PRESENTABLE (linux_md_drive));
+        vpd_name = gdu_presentable_get_vpd_name (GDU_PRESENTABLE (linux_md_drive));
+        s = g_strdup_printf (_("Edit components on %s (%s)"), name, vpd_name);
+        gtk_window_set_title (GTK_WINDOW (dialog), s);
+        g_free (s);
+
+        gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+        gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+
+        /* -------------------------------------------------------------------------------- */
+
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+        s = g_strconcat ("<b>", _("C_omponents"), "</b>", NULL);
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), s);
+        g_free (s);
+        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+        vbox2 = gtk_vbox_new (FALSE, 12);
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 6, 0, 12, 0);
+        gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
+        gtk_container_add (GTK_CONTAINER (align), vbox2);
+
+        /* -------------------------------------------------------------------------------- */
+
+        tree_view = gtk_tree_view_new ();
+        dialog->priv->components_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,
+                                        GTK_POLICY_AUTOMATIC);
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
+                                             GTK_SHADOW_IN);
+        gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
+        gtk_box_pack_start (GTK_BOX (vbox2), scrolled_window, TRUE, TRUE, 0);
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), tree_view);
+
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+        g_signal_connect (selection, "changed", G_CALLBACK (on_component_tree_selection_changed), dialog);
+
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_set_title (column, _("Position"));
+        renderer = gtk_cell_renderer_text_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_column_set_attributes (column, renderer,
+                                             "markup", MD_LINUX_POSITION_STRING_COLUMN,
+                                             NULL);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_set_title (column, _("Component"));
+        renderer = gtk_cell_renderer_pixbuf_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_column_set_attributes (column, renderer,
+                                             "pixbuf", MD_LINUX_ICON_COLUMN,
+                                             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,
+                                            format_markup,
+                                            dialog,
+                                            NULL);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_set_title (column, _("State"));
+        renderer = gtk_cell_renderer_text_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_column_set_attributes (column, renderer,
+                                             "markup", MD_LINUX_SLAVE_STATE_STRING_COLUMN,
+                                             NULL);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), TRUE);
+
+        /* -------------------------------------------------------------------------------- */
+
+        elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+        element = gdu_details_element_new (_("SMART Status:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        dialog->priv->component_smart_element = element;
+
+        element = gdu_details_element_new (_("Position:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        dialog->priv->component_position_element = element;
+
+        element = gdu_details_element_new (_("State:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        dialog->priv->component_state_element = element;
+
+        element = gdu_details_element_new (_("Device:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        dialog->priv->component_device_element = element;
+
+        table = gdu_details_table_new (2, elements);
+        g_ptr_array_unref (elements);
+        gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
+
+        /* -------------------------------------------------------------------------------- */
+
+        elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+        button_element = gdu_button_element_new (GTK_STOCK_NEW,
+                                                 _("_New Component"),
+                                                 _("Add a new component to the array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_component_new_button_clicked),
+                          dialog);
+        g_ptr_array_add (elements, button_element);
+        dialog->priv->component_attach_button = button_element;
+
+        button_element = gdu_button_element_new (GTK_STOCK_ADD,
+                                                 _("_Attach Component"),
+                                                 _("Attach the component to the array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_component_attach_button_clicked),
+                          dialog);
+        g_ptr_array_add (elements, button_element);
+        dialog->priv->component_attach_button = button_element;
+
+        button_element = gdu_button_element_new (GTK_STOCK_DELETE,
+                                                 _("_Remove Component"),
+                                                 _("Remove the component from the array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_component_remove_button_clicked),
+                          dialog);
+        g_ptr_array_add (elements, button_element);
+        dialog->priv->component_remove_button = button_element;
+
+        table = gdu_button_table_new (2, elements);
+        g_ptr_array_unref (elements);
+        gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+
+        /* -------------------------------------------------------------------------------- */
+
+        dialog->priv->changed_id = g_signal_connect (linux_md_drive,
+                                                     "changed",
+                                                     G_CALLBACK (on_linux_md_drive_changed),
+                                                     dialog);
+        dialog->priv->removed_id = g_signal_connect (linux_md_drive,
+                                                     "removed",
+                                                     G_CALLBACK (on_linux_md_drive_removed),
+                                                     dialog);
+        update_tree (dialog);
+        update_details (dialog);
+
+        /* close the dialog if the RAID array is not running */
+        if (!gdu_drive_is_active (GDU_DRIVE (gdu_dialog_get_presentable (GDU_DIALOG (dialog))))) {
+                g_warning ("Tried to construct a dialog for a non-running array");
+                gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+        }
+
+        g_free (name);
+        g_free (vpd_name);
+
+        /* select a sane size for the dialog and allow resizing */
+        gtk_widget_set_size_request (GTK_WIDGET (dialog), 650, 450);
+        gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+
+        if (G_OBJECT_CLASS (gdu_edit_linux_md_dialog_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_edit_linux_md_dialog_parent_class)->constructed (object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GduDevice *
+get_selected_component (GduEditLinuxMdDialog *dialog)
+{
+        gchar *component_objpath;
+        GduPool *pool;
+        GduDevice *slave_device;
+        GtkTreeSelection *tree_selection;
+        GtkTreeIter iter;
+
+        component_objpath = NULL;
+        slave_device = NULL;
+        pool = NULL;
+
+        tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->components_tree_view));
+        if (gtk_tree_selection_get_selected (tree_selection, NULL, &iter)) {
+                gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->components_tree_store), &iter,
+                                    MD_LINUX_OBJPATH_COLUMN,
+                                    &component_objpath,
+                                    -1);
+        }
+
+        if (component_objpath == NULL) {
+                goto out;
+        }
+
+        pool = gdu_presentable_get_pool (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+        slave_device = gdu_pool_get_by_object_path (pool, component_objpath);
+
+ out:
+        g_free (component_objpath);
+        if (pool != NULL)
+                g_object_unref (pool);
+
+        return slave_device;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gint
+component_tree_sort_func (GtkTreeModel *model,
+                          GtkTreeIter  *a,
+                          GtkTreeIter  *b,
+                          gpointer      user_data)
+{
+        gint ret;
+        gint a_position;
+        gint b_position;
+        gchar *a_objpath;
+        gchar *b_objpath;
+
+        gtk_tree_model_get (model,
+                            a,
+                            MD_LINUX_OBJPATH_COLUMN, &a_objpath,
+                            MD_LINUX_POSITION_COLUMN, &a_position,
+                            -1);
+
+        gtk_tree_model_get (model,
+                            b,
+                            MD_LINUX_OBJPATH_COLUMN, &b_objpath,
+                            MD_LINUX_POSITION_COLUMN, &b_position,
+                            -1);
+
+        if (a_position != b_position)
+                ret = a_position - b_position;
+        else
+                ret = g_strcmp0 (a_objpath, b_objpath);
+
+        g_free (a_objpath);
+        g_free (b_objpath);
+        return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_tree (GduEditLinuxMdDialog *dialog)
+{
+        GduLinuxMdDrive *linux_md_drive;
+        GtkTreeStore *store;
+        GList *slaves;
+        GList *l;
+        gchar *selected_component_objpath;
+        GtkTreeSelection *tree_selection;
+        GtkTreeIter *iter_to_select;
+
+        linux_md_drive = GDU_LINUX_MD_DRIVE (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+        slaves = gdu_linux_md_drive_get_slaves (linux_md_drive);
+
+        tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->components_tree_view));
+
+        iter_to_select = NULL;
+        selected_component_objpath = NULL;
+        if (dialog->priv->components_tree_store != NULL) {
+                GtkTreeIter iter;
+                if (gtk_tree_selection_get_selected (tree_selection, NULL, &iter)) {
+                        gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->components_tree_store), &iter,
+                                            MD_LINUX_OBJPATH_COLUMN,
+                                            &selected_component_objpath,
+                                            -1);
+                }
+                g_object_unref (dialog->priv->components_tree_store);
+        }
+
+        store = gtk_tree_store_new (MD_LINUX_N_COLUMNS,
+                                    GDU_TYPE_VOLUME,
+                                    GDU_TYPE_DRIVE,
+                                    G_TYPE_INT,
+                                    G_TYPE_STRING,
+                                    GDK_TYPE_PIXBUF,
+                                    G_TYPE_STRING,
+                                    G_TYPE_STRING);
+        dialog->priv->components_tree_store = store;
+
+        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+                                         MD_LINUX_OBJPATH_COLUMN,
+                                         component_tree_sort_func,
+                                         NULL,
+                                         NULL);
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+                                              MD_LINUX_OBJPATH_COLUMN,
+                                              GTK_SORT_ASCENDING);
+
+        /* add all slaves */
+        for (l = slaves; l != NULL; l = l->next) {
+                GduDevice *sd = GDU_DEVICE (l->data);
+                GdkPixbuf *pixbuf;
+                GtkTreeIter iter;
+                GduPool *pool;
+                GduPresentable *volume_for_slave;
+                GduPresentable *drive_for_slave;
+                gchar *position_str;
+                const gchar *object_path;
+                gint position;
+                gchar *slave_state_str;
+
+                pool = gdu_device_get_pool (sd);
+                volume_for_slave = gdu_pool_get_volume_by_device (pool, sd);
+                g_object_unref (pool);
+
+                if (volume_for_slave == NULL) {
+                        g_warning ("Cannot find volume for device `%s'", gdu_device_get_object_path (sd));
+                        continue;
+                }
+
+                if (gdu_device_is_partition (sd)) {
+                        GduDevice *drive_device;
+                        drive_device = gdu_pool_get_by_object_path (pool, gdu_device_partition_get_slave (sd));
+                        if (drive_device != NULL) {
+                                drive_for_slave = gdu_pool_get_drive_by_device (pool, drive_device);
+                                g_object_unref (drive_device);
+                        } else {
+                                g_warning ("No slave with objpath %s", gdu_device_partition_get_slave (sd));
+                        }
+                } else {
+                        drive_for_slave = gdu_pool_get_drive_by_device (pool, sd);
+                 }
+
+                if (gdu_drive_is_active (GDU_DRIVE (linux_md_drive))) {
+                        position = gdu_device_linux_md_component_get_position (sd);
+                        if (position >= 0) {
+                                position_str = g_strdup_printf ("%d", position);
+                        } else {
+                                position = G_MAXINT; /* to appear last in list */
+                                position_str = g_strdup ("â??");
+                        }
+                } else {
+                        position = G_MAXINT; /* to appear last in list */
+                        position_str = g_strdup ("â??");
+                }
+
+                pixbuf = gdu_util_get_pixbuf_for_presentable (volume_for_slave, GTK_ICON_SIZE_SMALL_TOOLBAR);
+                object_path = gdu_device_get_object_path (sd);
+
+                slave_state_str = gdu_linux_md_drive_get_slave_state_markup (linux_md_drive, sd);
+                if (slave_state_str == NULL)
+                        slave_state_str = g_strdup ("â??");
+
+                gtk_tree_store_append (store, &iter, NULL);
+                gtk_tree_store_set (store,
+                                    &iter,
+                                    MD_LINUX_SLAVE_VOLUME_COLUMN, volume_for_slave,
+                                    MD_LINUX_SLAVE_DRIVE_COLUMN, drive_for_slave,
+                                    MD_LINUX_POSITION_COLUMN, position,
+                                    MD_LINUX_POSITION_STRING_COLUMN, position_str,
+                                    MD_LINUX_ICON_COLUMN, pixbuf,
+                                    MD_LINUX_OBJPATH_COLUMN, object_path,
+                                    MD_LINUX_SLAVE_STATE_STRING_COLUMN, slave_state_str,
+                                    -1);
+
+                if (g_strcmp0 (object_path, selected_component_objpath) == 0) {
+                        g_assert (iter_to_select == NULL);
+                        iter_to_select = gtk_tree_iter_copy (&iter);
+                }
+
+                g_free (position_str);
+                g_free (slave_state_str);
+                if (pixbuf != NULL)
+                        g_object_unref (pixbuf);
+
+                g_object_unref (volume_for_slave);
+                if (drive_for_slave != NULL)
+                        g_object_unref (drive_for_slave);
+        }
+
+        gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->priv->components_tree_view), GTK_TREE_MODEL (store));
+
+        /* Select the first iter if nothing is currently selected */
+        if (iter_to_select == NULL) {
+                GtkTreeIter iter;
+                if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
+                        iter_to_select = gtk_tree_iter_copy (&iter);
+        }
+        /* (Re-)select the component */
+        if (iter_to_select != NULL) {
+                gtk_tree_selection_select_iter (tree_selection, iter_to_select);
+                gtk_tree_iter_free (iter_to_select);
+        }
+
+        g_list_foreach (slaves, (GFunc) g_object_unref, NULL);
+        g_list_free (slaves);
+        g_free (selected_component_objpath);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_details (GduEditLinuxMdDialog *dialog)
+{
+        GduLinuxMdDrive *linux_md_drive;
+        GduDevice *slave_device;
+        GduDevice *slave_drive_device;
+        gchar *s;
+        gchar *s2;
+        GIcon *icon;
+        gint position;
+        gboolean show_component_attach_button;
+        gboolean show_component_remove_button;
+        GduLinuxMdDriveSlaveFlags slave_flags;
+
+        show_component_attach_button = FALSE;
+        show_component_remove_button = FALSE;
+
+        slave_drive_device = NULL;
+
+        slave_device = get_selected_component (dialog);
+        if (slave_device == NULL) {
+                gdu_details_element_set_text (dialog->priv->component_smart_element, "â??");
+                gdu_details_element_set_icon (dialog->priv->component_smart_element, NULL);
+                gdu_details_element_set_text (dialog->priv->component_position_element, "â??");
+                gdu_details_element_set_text (dialog->priv->component_state_element, "â??");
+                gdu_details_element_set_text (dialog->priv->component_device_element, "â??");
+                goto out;
+        }
+
+        linux_md_drive = GDU_LINUX_MD_DRIVE (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+
+        s = gdu_linux_md_drive_get_slave_state_markup (linux_md_drive, slave_device);
+        if (s == NULL)
+                s = g_strdup ("â??");
+        gdu_details_element_set_text (dialog->priv->component_state_element, s);
+        g_free (s);
+
+        if (gdu_device_is_partition (slave_device)) {
+                GduPool *pool;
+                pool = gdu_device_get_pool (slave_device);
+                slave_drive_device = gdu_pool_get_by_object_path (pool, gdu_device_partition_get_slave (slave_device));
+                g_object_unref (pool);
+        } else {
+                slave_drive_device = g_object_ref (slave_device);
+        }
+
+        if (gdu_device_drive_ata_smart_get_is_available (slave_drive_device) &&
+            gdu_device_drive_ata_smart_get_time_collected (slave_drive_device) > 0) {
+                gboolean highlight;
+
+                s = gdu_util_ata_smart_status_to_desc (gdu_device_drive_ata_smart_get_status (slave_drive_device),
+                                                       &highlight,
+                                                       NULL,
+                                                       &icon);
+                if (highlight) {
+                        s2 = g_strdup_printf ("<span fgcolor=\"red\"><b>%s</b></span>", s);
+                        g_free (s);
+                        s = s2;
+                }
+
+                gdu_details_element_set_text (dialog->priv->component_smart_element, s);
+                gdu_details_element_set_icon (dialog->priv->component_smart_element, icon);
+
+                g_free (s);
+                g_object_unref (icon);
+        } else {
+                gdu_details_element_set_text (dialog->priv->component_smart_element,
+                                              _("Not Supported"));
+                icon = g_themed_icon_new ("gdu-smart-unknown");
+                gdu_details_element_set_icon (dialog->priv->component_smart_element, icon);
+                g_object_unref (icon);
+        }
+
+        if (gdu_drive_is_active (GDU_DRIVE (linux_md_drive))) {
+                position = gdu_device_linux_md_component_get_position (slave_device);
+                if (position >= 0) {
+                        s = g_strdup_printf ("%d", position);
+                } else {
+                        s = g_strdup ("â??");
+                }
+        } else {
+                s = g_strdup ("â??");
+        }
+        gdu_details_element_set_text (dialog->priv->component_position_element, s);
+        g_free (s);
+        gdu_details_element_set_text (dialog->priv->component_device_element,
+                                      gdu_device_get_device_file (slave_device));
+
+        if (gdu_drive_is_active (GDU_DRIVE (linux_md_drive))) {
+                slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, slave_device);
+                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED)
+                        show_component_attach_button = TRUE;
+                else
+                        show_component_remove_button = TRUE;
+        }
+
+ out:
+        gdu_button_element_set_visible (dialog->priv->component_attach_button, show_component_attach_button);
+        gdu_button_element_set_visible (dialog->priv->component_remove_button, show_component_remove_button);
+
+        if (slave_device != NULL)
+                g_object_unref (slave_device);
+        if (slave_drive_device != NULL)
+                g_object_unref (slave_drive_device);
+}
+
diff --git a/src/gdu-gtk/gdu-edit-linux-md-dialog.h b/src/gdu-gtk/gdu-edit-linux-md-dialog.h
new file mode 100644
index 0000000..11bb72f
--- /dev/null
+++ b/src/gdu-gtk/gdu-edit-linux-md-dialog.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GDU_EDIT_LINUX_MD_DIALOG_H
+#define __GDU_EDIT_LINUX_MD_DIALOG_H
+
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_EDIT_LINUX_MD_DIALOG         (gdu_edit_linux_md_dialog_get_type())
+#define GDU_EDIT_LINUX_MD_DIALOG(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_EDIT_LINUX_MD_DIALOG, GduEditLinuxMdDialog))
+#define GDU_EDIT_LINUX_MD_DIALOG_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_EDIT_LINUX_MD_DIALOG, GduEditLinuxMdDialogClass))
+#define GDU_IS_EDIT_LINUX_MD_DIALOG(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_EDIT_LINUX_MD_DIALOG))
+#define GDU_IS_EDIT_LINUX_MD_DIALOG_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_EDIT_LINUX_MD_DIALOG))
+#define GDU_EDIT_LINUX_MD_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_EDIT_LINUX_MD_DIALOG, GduEditLinuxMdDialogClass))
+
+typedef struct GduEditLinuxMdDialogClass   GduEditLinuxMdDialogClass;
+typedef struct GduEditLinuxMdDialogPrivate GduEditLinuxMdDialogPrivate;
+
+struct GduEditLinuxMdDialog
+{
+        GduDialog parent;
+
+        /*< private >*/
+        GduEditLinuxMdDialogPrivate *priv;
+};
+
+struct GduEditLinuxMdDialogClass
+{
+        GduDialogClass parent_class;
+
+        void (*new_button_clicked)    (GduEditLinuxMdDialog *dialog);
+        void (*attach_button_clicked) (GduEditLinuxMdDialog *dialog,
+                                       GduDevice            *slave);
+        void (*remove_button_clicked) (GduEditLinuxMdDialog *dialog,
+                                       GduDevice            *slave);
+};
+
+GType       gdu_edit_linux_md_dialog_get_type           (void) G_GNUC_CONST;
+GtkWidget*  gdu_edit_linux_md_dialog_new                (GtkWindow        *parent,
+                                                         GduLinuxMdDrive  *linux_md_drive);
+
+G_END_DECLS
+
+#endif  /* __GDU_EDIT_LINUX_MD_DIALOG_H */
+
diff --git a/src/gdu-gtk/gdu-gtk-enums.h b/src/gdu-gtk/gdu-gtk-enums.h
index d062e1b..006a1f0 100644
--- a/src/gdu-gtk/gdu-gtk-enums.h
+++ b/src/gdu-gtk/gdu-gtk-enums.h
@@ -79,7 +79,7 @@ typedef enum {
  * @GDU_FORMAT_DIALOG_FLAGS_NONE: No flags set.
  * @GDU_FORMAT_DIALOG_FLAGS_SIMPLE: Show a simple form of the dialog.
  * @GDU_FORMAT_DIALOG_FLAGS_DISK_UTILITY_BUTTON: Show a "Disk Utility" button.
- * @GDU_FORMAT_DIALOG_FLAGS_ALLOW_MSDOS_EXTENDED: Allow selection MS-DOS extended partition instead of a file system.
+ * @GDU_FORMAT_DIALOG_FLAGS_ALLOW_MSDOS_EXTENDED: Allow selecting a MS-DOS extended partition instead of a file system.
  *
  * Flags used when creating a #GduFormatDialog.
  */
@@ -90,4 +90,16 @@ typedef enum {
         GDU_FORMAT_DIALOG_FLAGS_ALLOW_MSDOS_EXTENDED = (1<<2)
 } GduFormatDialogFlags;
 
+/**
+ * GduDiskSelectionWidgetFlags:
+ * @GDU_DISK_SELECTION_WIDGET_FLAGS_NONE: No flags set.
+ * @GDU_DISK_SELECTION_WIDGET_FLAGS_ALLOW_MULTIPLE: Allow multiple disks to be selected.
+ *
+ * Flags used when creating a #GduDiskSelectionWidget.
+ */
+typedef enum {
+        GDU_DISK_SELECTION_WIDGET_FLAGS_NONE = 0,
+        GDU_DISK_SELECTION_WIDGET_FLAGS_ALLOW_MULTIPLE = (1<<0)
+} GduDiskSelectionWidgetFlags;
+
 #endif /* GDU_GTK_ENUMS_H */
diff --git a/src/gdu-gtk/gdu-gtk-enumtypes.h b/src/gdu-gtk/gdu-gtk-enumtypes.h
index c3b4642..0e299a8 100644
--- a/src/gdu-gtk/gdu-gtk-enumtypes.h
+++ b/src/gdu-gtk/gdu-gtk-enumtypes.h
@@ -17,6 +17,8 @@ GType gdu_pool_tree_model_flags_get_type (void) G_GNUC_CONST;
 #define GDU_TYPE_POOL_TREE_MODEL_FLAGS (gdu_pool_tree_model_flags_get_type ())
 GType gdu_format_dialog_flags_get_type (void) G_GNUC_CONST;
 #define GDU_TYPE_FORMAT_DIALOG_FLAGS (gdu_format_dialog_flags_get_type ())
+GType gdu_disk_selection_widget_flags_get_type (void) G_GNUC_CONST;
+#define GDU_TYPE_DISK_SELECTION_WIDGET_FLAGS (gdu_disk_selection_widget_flags_get_type ())
 G_END_DECLS
 
 #endif /* __GDU_GTK_ENUM_TYPES_H__ */
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index f37e657..bb4639d 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -33,30 +33,33 @@
 
 G_BEGIN_DECLS
 
-typedef struct GduSample                   GduSample;
-typedef struct GduColor                    GduColor;
-typedef struct GduCurve                    GduCurve;
-typedef struct GduGraph                    GduGraph;
-typedef struct GduTimeLabel                GduTimeLabel;
-typedef struct GduAtaSmartDialog           GduAtaSmartDialog;
-typedef struct GduSpinner                  GduSpinner;
-typedef struct GduPoolTreeModel            GduPoolTreeModel;
-typedef struct GduPoolTreeView             GduPoolTreeView;
-typedef struct GduCreateLinuxMdDialog      GduCreateLinuxMdDialog;
-typedef struct GduSizeWidget               GduSizeWidget;
-typedef struct GduVolumeGrid               GduVolumeGrid;
-typedef struct GduDetailsTable             GduDetailsTable;
-typedef struct GduDetailsElement           GduDetailsElement;
-typedef struct GduErrorDialog              GduErrorDialog;
-typedef struct GduConfirmationDialog       GduConfirmationDialog;
-typedef struct GduButtonElement            GduButtonElement;
-typedef struct GduButtonTable              GduButtonTable;
-typedef struct GduDialog                   GduDialog;
-typedef struct GduEditPartitionDialog      GduEditPartitionDialog;
-typedef struct GduFormatDialog             GduFormatDialog;
-typedef struct GduPartitionDialog          GduPartitionDialog;
-typedef struct GduCreatePartitionDialog    GduCreatePartitionDialog;
-typedef struct GduEditFilesystemDialog     GduEditFilesystemDialog;
+typedef struct GduSample                    GduSample;
+typedef struct GduColor                     GduColor;
+typedef struct GduCurve                     GduCurve;
+typedef struct GduGraph                     GduGraph;
+typedef struct GduTimeLabel                 GduTimeLabel;
+typedef struct GduAtaSmartDialog            GduAtaSmartDialog;
+typedef struct GduSpinner                   GduSpinner;
+typedef struct GduPoolTreeModel             GduPoolTreeModel;
+typedef struct GduPoolTreeView              GduPoolTreeView;
+typedef struct GduCreateLinuxMdDialog       GduCreateLinuxMdDialog;
+typedef struct GduSizeWidget                GduSizeWidget;
+typedef struct GduVolumeGrid                GduVolumeGrid;
+typedef struct GduDetailsTable              GduDetailsTable;
+typedef struct GduDetailsElement            GduDetailsElement;
+typedef struct GduErrorDialog               GduErrorDialog;
+typedef struct GduConfirmationDialog        GduConfirmationDialog;
+typedef struct GduButtonElement             GduButtonElement;
+typedef struct GduButtonTable               GduButtonTable;
+typedef struct GduDialog                    GduDialog;
+typedef struct GduEditPartitionDialog       GduEditPartitionDialog;
+typedef struct GduFormatDialog              GduFormatDialog;
+typedef struct GduPartitionDialog           GduPartitionDialog;
+typedef struct GduCreatePartitionDialog     GduCreatePartitionDialog;
+typedef struct GduEditFilesystemDialog      GduEditFilesystemDialog;
+typedef struct GduDiskSelectionWidget       GduDiskSelectionWidget;
+typedef struct GduAddComponentLinuxMdDialog GduAddComponentLinuxMdDialog;
+typedef struct GduEditLinuxMdDialog         GduEditLinuxMdDialog;
 
 
 G_END_DECLS
diff --git a/src/gdu-gtk/gdu-gtk.h b/src/gdu-gtk/gdu-gtk.h
index 91997eb..3326628 100644
--- a/src/gdu-gtk/gdu-gtk.h
+++ b/src/gdu-gtk/gdu-gtk.h
@@ -49,6 +49,9 @@
 #include <gdu-gtk/gdu-partition-dialog.h>
 #include <gdu-gtk/gdu-create-partition-dialog.h>
 #include <gdu-gtk/gdu-edit-filesystem-dialog.h>
+#include <gdu-gtk/gdu-disk-selection-widget.h>
+#include <gdu-gtk/gdu-add-component-linux-md-dialog.h>
+#include <gdu-gtk/gdu-edit-linux-md-dialog.h>
 #undef __GDU_GTK_INSIDE_GDU_GTK_H
 
 G_BEGIN_DECLS
diff --git a/src/gdu-gtk/gdu-volume-grid.c b/src/gdu-gtk/gdu-volume-grid.c
index 5e72440..1d30473 100644
--- a/src/gdu-gtk/gdu-volume-grid.c
+++ b/src/gdu-gtk/gdu-volume-grid.c
@@ -1174,7 +1174,11 @@ render_element (GduVolumeGrid *grid,
                 cairo_text_extents_t te;
                 const gchar *text;
 
-                text = _("No Media Detected");
+                if (GDU_IS_LINUX_MD_DRIVE (grid->priv->drive)) {
+                        text = _("RAID Array is not running");
+                } else {
+                        text = _("No Media Detected");
+                }
 
                 if (is_selected) {
                         if (is_grid_focused) {
@@ -1259,6 +1263,9 @@ render_element (GduVolumeGrid *grid,
                         } else {
                                 render_padlock_open = TRUE;
                         }
+                } else if (d != NULL && g_strcmp0 (gdu_device_id_get_usage (d), "raid") == 0 &&
+                           gdu_device_is_linux_md_component (d)) {
+                        s1 = g_strdup (gdu_device_linux_md_component_get_name (d));
                 } else if (!gdu_presentable_is_allocated (element->presentable)) {
                         s = g_strdup (_("Free"));
                         s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->presentable),
@@ -1608,3 +1615,32 @@ on_presentable_job_changed (GduPool        *pool,
         GduVolumeGrid *grid = GDU_VOLUME_GRID (user_data);
         maybe_recompute (grid, p);
 }
+
+gboolean
+gdu_volume_grid_select (GduVolumeGrid       *grid,
+                        GduPresentable      *volume)
+{
+        GridElement *element;
+        gboolean ret;
+
+        g_return_val_if_fail (GDU_IS_VOLUME_GRID (grid), FALSE);
+
+        ret = FALSE;
+
+        element = find_element_for_presentable (grid, volume);
+        if (element != NULL) {
+                grid->priv->selected = element;
+                grid->priv->focused = element;
+
+                g_signal_emit (grid,
+                               signals[CHANGED_SIGNAL],
+                               0);
+
+                gtk_widget_grab_focus (GTK_WIDGET (grid));
+                gtk_widget_queue_draw (GTK_WIDGET (grid));
+
+                ret = TRUE;
+        }
+
+        return ret;
+}
diff --git a/src/gdu-gtk/gdu-volume-grid.h b/src/gdu-gtk/gdu-volume-grid.h
index a3f6777..4aa1d73 100644
--- a/src/gdu-gtk/gdu-volume-grid.h
+++ b/src/gdu-gtk/gdu-volume-grid.h
@@ -59,6 +59,8 @@ struct GduVolumeGridClass
 GType           gdu_volume_grid_get_type         (void) G_GNUC_CONST;
 GtkWidget*      gdu_volume_grid_new              (GduDrive            *drive);
 GduPresentable *gdu_volume_grid_get_selected     (GduVolumeGrid       *grid);
+gboolean        gdu_volume_grid_select           (GduVolumeGrid       *grid,
+                                                  GduPresentable      *volume);
 
 G_END_DECLS
 
diff --git a/src/gdu/gdu-device.c b/src/gdu/gdu-device.c
index 184f424..67d3698 100644
--- a/src/gdu/gdu-device.c
+++ b/src/gdu/gdu-device.c
@@ -135,6 +135,7 @@ typedef struct
         gsize drive_ata_smart_blob_size;
 
         char    *linux_md_component_level;
+        int      linux_md_component_position;
         int      linux_md_component_num_raid_devices;
         char    *linux_md_component_uuid;
         char    *linux_md_component_home_host;
@@ -337,6 +338,8 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
 
         else if (strcmp (key, "LinuxMdComponentLevel") == 0)
                 props->linux_md_component_level = g_strdup (g_value_get_string (value));
+        else if (strcmp (key, "LinuxMdComponentPosition") == 0)
+                props->linux_md_component_position = g_value_get_int (value);
         else if (strcmp (key, "LinuxMdComponentNumRaidDevices") == 0)
                 props->linux_md_component_num_raid_devices = g_value_get_int (value);
         else if (strcmp (key, "LinuxMdComponentUuid") == 0)
@@ -1130,6 +1133,12 @@ gdu_device_linux_md_component_get_level (GduDevice *device)
 }
 
 int
+gdu_device_linux_md_component_get_position (GduDevice *device)
+{
+        return device->priv->props->linux_md_component_position;
+}
+
+int
 gdu_device_linux_md_component_get_num_raid_devices (GduDevice *device)
 {
         return device->priv->props->linux_md_component_num_raid_devices;
diff --git a/src/gdu/gdu-device.h b/src/gdu/gdu-device.h
index 8b9fddf..a53190d 100644
--- a/src/gdu/gdu-device.h
+++ b/src/gdu/gdu-device.h
@@ -150,6 +150,7 @@ guint gdu_device_optical_disc_get_num_audio_tracks (GduDevice *device);
 guint gdu_device_optical_disc_get_num_sessions (GduDevice *device);
 
 const char *gdu_device_linux_md_component_get_level (GduDevice *device);
+int         gdu_device_linux_md_component_get_position (GduDevice *device);
 int         gdu_device_linux_md_component_get_num_raid_devices (GduDevice *device);
 const char *gdu_device_linux_md_component_get_uuid (GduDevice *device);
 const char *gdu_device_linux_md_component_get_home_host (GduDevice *device);
diff --git a/src/gdu/gdu-linux-md-drive.c b/src/gdu/gdu-linux-md-drive.c
index 8b69981..bbdf453 100644
--- a/src/gdu/gdu-linux-md-drive.c
+++ b/src/gdu/gdu-linux-md-drive.c
@@ -379,6 +379,12 @@ gdu_linux_md_drive_has_slave    (GduLinuxMdDrive  *drive,
         return g_list_find (drive->priv->slaves, device) != NULL;
 }
 
+const gchar *
+gdu_linux_md_drive_get_uuid (GduLinuxMdDrive *drive)
+{
+        return drive->priv->uuid;
+}
+
 /**
  * gdu_linux_md_drive_get_slaves:
  * @drive: A #GduLinuxMdDrive.
@@ -489,6 +495,7 @@ get_names_and_desc (GduPresentable  *presentable,
         ret_desc = NULL;
         ret_vpd = NULL;
         strsize = NULL;
+        level_str = NULL;
 
         /* TODO: Maybe guess size from level, num_raid_devices and component_size? */
         if (drive->priv->device != NULL) {
@@ -512,12 +519,12 @@ get_names_and_desc (GduPresentable  *presentable,
                 if (name == NULL || strlen (name) == 0) {
                         if (strsize != NULL) {
                                 /* Translators: First %s is the size, second %s is a RAID level, e.g. 'RAID-5' */
-                                ret = g_strdup_printf (_("%s %s Drive"),
+                                ret = g_strdup_printf (_("%s %s Array"),
                                                        strsize,
                                                        level_str);
                         } else {
                                 /* Translators: %s is a RAID level, e.g. 'RAID-5' */
-                                ret = g_strdup_printf (_("%s Drive"),
+                                ret = g_strdup_printf (_("%s Array"),
                                                        level_str);
                         }
                 } else {
@@ -566,13 +573,11 @@ get_names_and_desc (GduPresentable  *presentable,
                         }
                 }
 
-                g_free (level_str);
-
         } 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
                  */
-                ret = g_strdup_printf (_("RAID device %s (%s)"),
+                ret = g_strdup_printf (_("RAID Array %s (%s)"),
                                        gdu_device_get_device_file (drive->priv->device),
                                        gdu_device_linux_md_get_state (drive->priv->device));
         } else {
@@ -582,6 +587,12 @@ get_names_and_desc (GduPresentable  *presentable,
                 ret = g_strdup_printf (_("RAID device %s"), drive->priv->device_file);
         }
 
+        /* Fallback for level_str */
+        if (level_str == NULL) {
+                /* Translators: fallback for level */
+                level_str = g_strdup (C_("RAID Level fallback", "RAID"));
+        }
+
         /* Fallback for description */
         if (ret_desc == NULL) {
                 ret_desc = g_strdup (_("RAID Array"));
@@ -590,11 +601,13 @@ get_names_and_desc (GduPresentable  *presentable,
         /* 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);
+                        /* Translators: first %s is the size e.g. '45 GB', second %s is the level e.g. 'RAID-5' */
+                        ret_vpd = g_strdup_printf (_("%s %s Array"),
+                                                   strsize,
+                                                   level_str);
                 } else {
-                        ret_vpd = g_strdup (_("Software RAID"));
+                        /* Translators: %s is the level e.g. 'RAID-5' */
+                        ret_vpd = g_strdup_printf (_("%s Array"), level_str);
                 }
         }
 
@@ -609,6 +622,7 @@ get_names_and_desc (GduPresentable  *presentable,
                 g_free (ret_vpd);
 
         g_free (strsize);
+        g_free (level_str);
 
         return ret;
 }
@@ -1005,3 +1019,43 @@ gdu_linux_md_drive_deactivate (GduDrive               *_drive,
                                      deactivation_completed,
                                      deactivation_data_new (drive, callback, user_data));
 }
+
+gchar *
+gdu_linux_md_drive_get_slave_state_markup (GduLinuxMdDrive  *drive,
+                                           GduDevice        *slave)
+{
+        gchar *slave_state_str;
+
+        slave_state_str = NULL;
+        if (gdu_drive_is_active (GDU_DRIVE (drive))) {
+                GduLinuxMdDriveSlaveFlags slave_flags;
+                GPtrArray *slave_state;
+                gchar *s;
+
+                slave_flags = gdu_linux_md_drive_get_slave_flags (drive, slave);
+
+                slave_state = g_ptr_array_new_with_free_func (g_free);
+                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED)
+                        g_ptr_array_add (slave_state, g_strdup (C_("Linux MD slave state", "Not Attached")));
+                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_FAULTY) {
+                        s = g_strconcat ("<span foreground='red'><b>",
+                                         C_("Linux MD slave state", "Faulty"),
+                                         "</b></span>", NULL);
+                        g_ptr_array_add (slave_state, s);
+                }
+                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_IN_SYNC)
+                        g_ptr_array_add (slave_state, g_strdup (C_("Linux MD slave state", "Fully Synchronized")));
+                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_WRITEMOSTLY)
+                        g_ptr_array_add (slave_state, g_strdup (C_("Linux MD slave state", "Writemostly")));
+                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_BLOCKED)
+                        g_ptr_array_add (slave_state, g_strdup (C_("Linux MD slave state", "Blocked")));
+                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_SPARE)
+                        g_ptr_array_add (slave_state, g_strdup (C_("Linux MD slave state", "Spare")));
+                g_ptr_array_add (slave_state, NULL);
+                slave_state_str = g_strjoinv (", ", (gchar **) slave_state->pdata);
+                g_ptr_array_free (slave_state, TRUE);
+
+        }
+
+        return slave_state_str;
+}
diff --git a/src/gdu/gdu-linux-md-drive.h b/src/gdu/gdu-linux-md-drive.h
index 490563a..f6a05bf 100644
--- a/src/gdu/gdu-linux-md-drive.h
+++ b/src/gdu/gdu-linux-md-drive.h
@@ -92,13 +92,16 @@ typedef enum {
         GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_SPARE         = (1<<5),
 } GduLinuxMdDriveSlaveFlags;
 
-GType                      gdu_linux_md_drive_get_type             (void);
-const gchar               *gdu_linux_md_drive_get_uuid             (GduLinuxMdDrive  *drive);
-gboolean                   gdu_linux_md_drive_has_slave            (GduLinuxMdDrive  *drive,
-                                                                    GduDevice        *device);
-GList                     *gdu_linux_md_drive_get_slaves           (GduLinuxMdDrive  *drive);
-GduLinuxMdDriveSlaveFlags  gdu_linux_md_drive_get_slave_flags      (GduLinuxMdDrive  *drive,
-                                                                    GduDevice        *slave);
+GType                      gdu_linux_md_drive_get_type               (void);
+const gchar               *gdu_linux_md_drive_get_uuid               (GduLinuxMdDrive  *drive);
+gboolean                   gdu_linux_md_drive_has_slave              (GduLinuxMdDrive  *drive,
+                                                                      GduDevice        *device);
+GList                     *gdu_linux_md_drive_get_slaves             (GduLinuxMdDrive  *drive);
+GduLinuxMdDriveSlaveFlags  gdu_linux_md_drive_get_slave_flags        (GduLinuxMdDrive  *drive,
+                                                                      GduDevice        *slave);
+gchar                     *gdu_linux_md_drive_get_slave_state_markup (GduLinuxMdDrive  *drive,
+                                                                      GduDevice        *slave);
+
 G_END_DECLS
 
 #endif /* __GDU_LINUX_MD_DRIVE_H */
diff --git a/src/gdu/gdu-pool.c b/src/gdu/gdu-pool.c
index 0258e6e..c4dcb96 100644
--- a/src/gdu/gdu-pool.c
+++ b/src/gdu/gdu-pool.c
@@ -1493,6 +1493,32 @@ gdu_pool_get_drive_by_device (GduPool *pool, GduDevice *device)
         return ret;
 }
 
+GduLinuxMdDrive *
+gdu_pool_get_linux_md_drive_by_uuid (GduPool *pool, const gchar *uuid)
+{
+        GduLinuxMdDrive *ret;
+        GList *l;
+
+        /* TODO: use lookaside hash table */
+
+        ret = NULL;
+
+        for (l = pool->priv->presentables; l != NULL; l = l->next) {
+                GduPresentable *p = GDU_PRESENTABLE (l->data);
+
+                if (! GDU_IS_LINUX_MD_DRIVE (p))
+                        continue;
+
+                if (g_strcmp0 (uuid, gdu_linux_md_drive_get_uuid (GDU_LINUX_MD_DRIVE (p))) == 0) {
+                        ret = g_object_ref (p);
+                        goto out;
+                }
+        }
+
+ out:
+        return ret;
+}
+
 GduPresentable *
 gdu_pool_get_presentable_by_id (GduPool *pool, const gchar *id)
 {
diff --git a/src/gdu/gdu-pool.h b/src/gdu/gdu-pool.h
index dd2f7b8..555e331 100644
--- a/src/gdu/gdu-pool.h
+++ b/src/gdu/gdu-pool.h
@@ -77,9 +77,11 @@ GduDevice  *gdu_pool_get_by_object_path (GduPool *pool, const char *object_path)
 GduDevice  *gdu_pool_get_by_device_file (GduPool *pool, const char *device_file);
 GduPresentable *gdu_pool_get_volume_by_device      (GduPool *pool, GduDevice *device);
 GduPresentable *gdu_pool_get_drive_by_device       (GduPool *pool, GduDevice *device);
+GduLinuxMdDrive *gdu_pool_get_linux_md_drive_by_uuid (GduPool *pool, const gchar *uuid);
 
 GduPresentable *gdu_pool_get_presentable_by_id     (GduPool *pool, const gchar *id);
 
+
 GList      *gdu_pool_get_devices               (GduPool *pool);
 GList      *gdu_pool_get_presentables          (GduPool *pool);
 GList      *gdu_pool_get_enclosed_presentables (GduPool *pool, GduPresentable *presentable);
diff --git a/src/gdu/gdu-volume.c b/src/gdu/gdu-volume.c
index d33affe..5b64333 100644
--- a/src/gdu/gdu-volume.c
+++ b/src/gdu/gdu-volume.c
@@ -343,20 +343,20 @@ get_names_and_desc (GduPresentable  *presentable,
                                 if (array_name != NULL && strlen (array_name) > 0) {
                                         /* Translators: label for a RAID component
                                          * First %s is the size, formatted like '45 GB'
+                                         * Second %s is the RAID level string, e.g 'RAID-5'
                                          */
-                                        result = g_strdup_printf (_("%s RAID Component"), strsize);
+                                        result = g_strdup_printf (_("%s %s Component"), strsize, level_str);
                                         /* Translators: description for a RAID component
                                          * First %s is the array name, e.g. 'My Photos RAID',
-                                         * second %s is the RAID level string, e.g 'RAID-5'
                                          */
-                                        result_desc = g_strdup_printf (_("Part of \"%s\" %s array"),
-                                                                       array_name,
-                                                                       level_str);
+                                        result_desc = g_strdup_printf (_("Part of \"%s\" array"),
+                                                                       array_name);
                                 } else {
                                         /* Translators: label for a RAID component
                                          * First %s is the size, formatted like '45 GB'
+                                         * Second %s is the RAID level string, e.g 'RAID-5'
                                          */
-                                        result = g_strdup_printf (_("%s RAID Component"), strsize);
+                                        result = g_strdup_printf (_("%s %s Component"), strsize, level_str);
                                         result_desc = g_strdup (level_str);
                                 }
 
diff --git a/src/palimpsest/gdu-section-drive.c b/src/palimpsest/gdu-section-drive.c
index e919ec6..3f26d2c 100644
--- a/src/palimpsest/gdu-section-drive.c
+++ b/src/palimpsest/gdu-section-drive.c
@@ -96,6 +96,17 @@ gdu_section_drive_update (GduSection *_section)
         const gchar *serial;
         const gchar *wwn;
         GIcon *icon;
+        gboolean show_cddvd_button;
+        gboolean show_format_button;
+        gboolean show_eject_button;
+        gboolean show_detach_button;
+        gboolean show_smart_button;
+
+        show_cddvd_button = FALSE;
+        show_format_button = FALSE;
+        show_eject_button = FALSE;
+        show_detach_button = FALSE;
+        show_smart_button = FALSE;
 
         d = NULL;
         p = gdu_section_get_presentable (_section);
@@ -200,32 +211,31 @@ gdu_section_drive_update (GduSection *_section)
         if (d != NULL &&
             gdu_device_drive_ata_smart_get_is_available (d) &&
             gdu_device_drive_ata_smart_get_time_collected (d) > 0) {
-                gdu_button_element_set_visible (section->priv->smart_button, TRUE);
-        } else {
-                gdu_button_element_set_visible (section->priv->smart_button, FALSE);
+                show_smart_button = TRUE;
         }
 
         if (d != NULL && gdu_device_drive_get_is_media_ejectable (d)) {
-                gdu_button_element_set_visible (section->priv->eject_button, TRUE);
-        } else {
-                gdu_button_element_set_visible (section->priv->eject_button, FALSE);
+                show_eject_button =  TRUE;
         }
 
         if (d != NULL && gdu_device_drive_get_can_detach (d)) {
-                gdu_button_element_set_visible (section->priv->detach_button, TRUE);
-        } else {
-                gdu_button_element_set_visible (section->priv->detach_button, FALSE);
+                show_detach_button = TRUE;
         }
 
         if (d != NULL && has_strv0 (gdu_device_drive_get_media_compatibility (d), "optical_cd")) {
-                gdu_button_element_set_visible (section->priv->cddvd_button, TRUE);
-                gdu_button_element_set_visible (section->priv->format_button, FALSE);
+                show_cddvd_button = TRUE;
         } else {
-                gdu_button_element_set_visible (section->priv->cddvd_button, FALSE);
-                gdu_button_element_set_visible (section->priv->format_button, TRUE);
+                show_format_button = TRUE;
         }
 
  out:
+        gdu_button_element_set_visible (section->priv->cddvd_button, show_cddvd_button);
+        gdu_button_element_set_visible (section->priv->format_button, show_format_button);
+        gdu_button_element_set_visible (section->priv->eject_button, show_eject_button);
+        gdu_button_element_set_visible (section->priv->detach_button, show_detach_button);
+        gdu_button_element_set_visible (section->priv->smart_button, show_smart_button);
+
+
         if (d != NULL)
                 g_object_unref (d);
 }
@@ -406,8 +416,6 @@ partition_table_create_op_callback (GduDevice  *device,
         if (error != NULL) {
                 GtkWidget *dialog;
 
-                g_debug ("error: %s", error->message);
-
                 dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
                                                          device,
                                                          _("Error formatting drive"),
@@ -421,11 +429,12 @@ partition_table_create_op_callback (GduDevice  *device,
         g_object_unref (shell);
 }
 
-static void
-on_format_button_clicked (GduButtonElement *button_element,
-                          gpointer          user_data)
+/* exported, can only assume user_data is a GduSection */
+void
+gdu_section_drive_on_format_button_clicked (GduButtonElement *button_element,
+                                            gpointer          user_data)
 {
-        GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
+        GduSection *section = GDU_SECTION (user_data);
         GduDevice *d;
         GtkWindow *toplevel;
         GtkWidget *dialog;
@@ -435,11 +444,11 @@ on_format_button_clicked (GduButtonElement *button_element,
         dialog = NULL;
         confirmation_dialog = NULL;
 
-        d = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
+        d = gdu_presentable_get_device (gdu_section_get_presentable (section));
         if (d == NULL)
                 goto out;
 
-        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
+        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (section)));
         dialog = gdu_partition_dialog_new_for_drive (toplevel, d);
         gtk_widget_show_all (dialog);
         response = gtk_dialog_run (GTK_DIALOG (dialog));
@@ -456,7 +465,7 @@ on_format_button_clicked (GduButtonElement *button_element,
                         gdu_device_op_partition_table_create (d,
                                                     gdu_partition_dialog_get_scheme (GDU_PARTITION_DIALOG (dialog)),
                                                     partition_table_create_op_callback,
-                                                    g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
+                                                    g_object_ref (gdu_section_get_shell (section)));
                 }
         }
  out:
@@ -485,7 +494,8 @@ gdu_section_drive_constructed (GObject *object)
         GduDetailsElement *element;
         GduButtonElement *button_element;
 
-        d = NULL;
+        p = gdu_section_get_presentable (GDU_SECTION (section));
+        d = gdu_presentable_get_device (p);
 
         gtk_box_set_spacing (GTK_BOX (section), 12);
 
@@ -549,8 +559,6 @@ gdu_section_drive_constructed (GObject *object)
         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
         gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
 
-        p = gdu_section_get_presentable (GDU_SECTION (section));
-        d = gdu_presentable_get_device (p);
         elements = g_ptr_array_new_with_free_func (g_object_unref);
 
         button_element = gdu_button_element_new ("brasero",
@@ -565,10 +573,10 @@ gdu_section_drive_constructed (GObject *object)
 
         button_element = gdu_button_element_new ("nautilus-gdu",
                                                  _("Format _Drive"),
-                                                 _("Delete all data and partition the drive"));
+                                                 _("Erase or partition the drive"));
         g_signal_connect (button_element,
                           "clicked",
-                          G_CALLBACK (on_format_button_clicked),
+                          G_CALLBACK (gdu_section_drive_on_format_button_clicked),
                           section);
         g_ptr_array_add (elements, button_element);
         section->priv->format_button = button_element;
diff --git a/src/palimpsest/gdu-section-drive.h b/src/palimpsest/gdu-section-drive.h
index 901df80..9c21b09 100644
--- a/src/palimpsest/gdu-section-drive.h
+++ b/src/palimpsest/gdu-section-drive.h
@@ -55,4 +55,10 @@ GType            gdu_section_drive_get_type (void);
 GtkWidget       *gdu_section_drive_new      (GduShell       *shell,
                                              GduPresentable *presentable);
 
+/* exported for use in GduSectionLinuxMd and others - user_data must be a GduSection instance */
+void
+gdu_section_drive_on_format_button_clicked (GduButtonElement *button_element,
+                                            gpointer          user_data);
+
+
 #endif /* GDU_SECTION_DRIVE_H */
diff --git a/src/palimpsest/gdu-section-linux-md-drive.c b/src/palimpsest/gdu-section-linux-md-drive.c
index 6162944..9021a14 100644
--- a/src/palimpsest/gdu-section-linux-md-drive.c
+++ b/src/palimpsest/gdu-section-linux-md-drive.c
@@ -29,1122 +29,1144 @@
 #include <gdu/gdu.h>
 #include <gdu-gtk/gdu-gtk.h>
 
+#include "gdu-section-drive.h"
 #include "gdu-section-linux-md-drive.h"
 
 struct _GduSectionLinuxMdDrivePrivate
 {
-        GtkWidget *linux_md_name_label;
-        GtkWidget *linux_md_home_host_label;
-        GtkWidget *linux_md_type_label;
-        GtkWidget *linux_md_size_label;
-        GtkWidget *linux_md_components_label;
-        GtkWidget *linux_md_state_label;
-        GtkWidget *linux_md_tree_view;
-        GtkTreeStore *linux_md_tree_store;
-
-        GtkWidget *attach_button;
-        GtkWidget *detach_button;
-        GtkWidget *add_button;
+        GduDetailsElement *level_element;
+        GduDetailsElement *metadata_version_element;
+        GduDetailsElement *name_element;
+        GduDetailsElement *partitioning_element;
+        GduDetailsElement *state_element;
+        GduDetailsElement *capacity_element;
+        GduDetailsElement *action_element;
+        GduDetailsElement *active_components_element;
+
+        GtkWidget *components_vbox;
+
+        GduButtonElement *md_start_button;
+        GduButtonElement *md_stop_button;
+        GduButtonElement *format_button;
+        GduButtonElement *edit_components_button;
+        GduButtonElement *check_button;
 };
 
-static GObjectClass *parent_class = NULL;
-
 G_DEFINE_TYPE (GduSectionLinuxMdDrive, gdu_section_linux_md_drive, GDU_TYPE_SECTION)
 
-enum {
-        MD_LINUX_ICON_COLUMN,
-        MD_LINUX_NAME_COLUMN,
-        MD_LINUX_STATE_STRING_COLUMN,
-        MD_LINUX_STATE_COLUMN,
-        MD_LINUX_OBJPATH_COLUMN,
-        MD_LINUX_N_COLUMNS,
-};
-
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-add_component_callback (GduDevice *device,
-                        GError *error,
-                        gpointer user_data)
+gdu_section_linux_md_drive_finalize (GObject *object)
 {
-        GduSection *section = GDU_SECTION (user_data);
-        if (error != NULL) {
-                gdu_shell_raise_error (gdu_section_get_shell (section),
-                                       gdu_section_get_presentable (section),
-                                       error,
-                                       _("Error adding component"));
-        }
-        g_object_unref (section);
+        //GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (object);
+
+        if (G_OBJECT_CLASS (gdu_section_linux_md_drive_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_section_linux_md_drive_parent_class)->finalize (object);
 }
 
 static void
-on_add_clicked (GtkButton *button,
-                gpointer   user_data)
+update_state_and_action_elements (GduSectionLinuxMdDrive *section)
 {
-        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
-        GduPresentable *presentable;
-        GduPresentable *selected_presentable;
-        GduDevice *device;
-        GduDevice *selected_device;
-        GduLinuxMdDrive *linux_md_drive;
-        GduPool *pool;
-        GtkWidget *dialog;
-        GtkWidget *vbox;
-        int response;
-        GtkWidget *tree_view;
-        char *array_name;
-        char *s;
-        char *s2;
-        GtkWidget *scrolled_window;
-        GduPoolTreeModel *model;
-
-        device = NULL;
-        selected_device = NULL;
-        pool = NULL;
-        array_name = NULL;
-        selected_presentable = NULL;
-
-        presentable = gdu_section_get_presentable (GDU_SECTION (section));
-        if (!GDU_IS_LINUX_MD_DRIVE (presentable)) {
-                g_warning ("%s: is not an linux_md drive", __FUNCTION__);
-                goto out;
-        }
-
-        device = gdu_presentable_get_device (presentable);
-        if (device == NULL) {
-                g_warning ("%s: linux_md drive not active", __FUNCTION__);
-                goto out;
-        }
-
-        linux_md_drive = GDU_LINUX_MD_DRIVE (presentable);
-
-        pool = gdu_device_get_pool (device);
-
-        dialog = gtk_dialog_new_with_buttons ("",
-                                              GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section)))),
-                                              GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
-                                              NULL);
-
+        GduLinuxMdDrive *drive;
+        GduDevice *d;
+        gchar *state_str;
+        gchar *action_str;
+        gdouble action_progress;
+
+        drive = GDU_LINUX_MD_DRIVE (gdu_section_get_presentable (GDU_SECTION (section)));
+        d = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
+
+        action_str = NULL;
+        action_progress = -1.0;
+        if (!gdu_drive_is_active (GDU_DRIVE (drive))) {
+                if (d != NULL) {
+                        state_str = g_strdup (C_("RAID status", "Not running, partially assembled"));
+                } else {
+                        gboolean can_activate;
+                        gboolean degraded;
 
-	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
-	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
-	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
+                        can_activate = gdu_drive_can_activate (GDU_DRIVE (drive), &degraded);
 
-        GtkWidget *hbox;
+                        if (can_activate && !degraded) {
+                                state_str = g_strdup (C_("RAID status", "Not running"));
+                        } else if (can_activate && degraded) {
+                                state_str = g_strdup (C_("RAID status", "Not running, can only start degraded"));
+                        } else {
+                                state_str = g_strdup (C_("RAID status", "Not running, not enough components to start"));
+                        }
+                }
 
-	hbox = gtk_hbox_new (FALSE, 12);
-	gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
-	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
+                action_str = g_strdup ("â??");
+        } else {
+                gboolean is_degraded;
+                const gchar *sync_action;
+                gdouble sync_percentage;
+                guint64 sync_speed;
 
-        GtkWidget *image;
+                is_degraded = gdu_device_linux_md_is_degraded (d);
+                sync_action = gdu_device_linux_md_get_sync_action (d);
+                sync_percentage = gdu_device_linux_md_get_sync_percentage (d);
+                sync_speed = gdu_device_linux_md_get_sync_speed (d);
 
-	image = gtk_image_new_from_pixbuf (gdu_util_get_pixbuf_for_presentable (presentable, GTK_ICON_SIZE_DIALOG));
-	gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
-	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+                if (is_degraded) {
+                        state_str  = g_strdup_printf ("<span foreground='red'><b>%s</b></span>",
+                                                      C_("RAID status", "DEGRADED"));
+                } else {
+                        state_str = g_strdup (C_("RAID status", "Running"));
+                }
 
-	vbox = gtk_vbox_new (FALSE, 10);
-	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
+                if (strcmp (sync_action, "idle") != 0) {
 
-        array_name = gdu_presentable_get_name (presentable);
+                        /* TODO: include speed somewhere? */
 
-        GtkWidget *label;
-        label = gtk_label_new (NULL);
-        s2 = g_strdup_printf (_("Select a volume to use as component in the array \"%s\""),
-                              array_name);
-        s = g_strconcat ("<big><b>",
-                         s2,
-                         "%s</b></big>\n\n",
-                         _("Only volumes of acceptable sizes can be selected. You may "
-                           "need to manually create new volumes of acceptable sizes."),
-                         NULL),
-        g_free (s2);
-        gtk_label_set_markup (GTK_LABEL (label), s);
-        g_free (s);
-        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
+                        if (strcmp (sync_action, "reshape") == 0) {
+                                action_str = g_strdup_printf (C_("RAID action", "Reshaping"));
+                        } else if (strcmp (sync_action, "resync") == 0) {
+                                action_str = g_strdup_printf (C_("RAID action", "Resyncing"));
+                        } else if (strcmp (sync_action, "repair") == 0) {
+                                action_str = g_strdup_printf (C_("RAID action", "Repairing"));
+                        } else if (strcmp (sync_action, "recover") == 0) {
+                                action_str = g_strdup_printf (C_("RAID action", "Recovering"));
+                        } else if (strcmp (sync_action, "check") == 0) {
+                                action_str = g_strdup_printf (C_("RAID action", "Checking"));
+                        }
 
-        scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
-                                        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,
-                                         NULL,
-                                         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);
+                        action_progress = sync_percentage / 100.0;
+                } else {
+                        action_str = g_strdup (C_("RAID action", "Idle"));
+                }
+        }
 
-	gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+        gdu_details_element_set_text (section->priv->state_element, state_str);
+        gdu_details_element_set_text (section->priv->action_element, action_str);
+        gdu_details_element_set_progress (section->priv->action_element, action_progress);
 
-        gtk_widget_grab_focus (gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL));
-        gtk_dialog_add_button (GTK_DIALOG (dialog), _("Add _Volume"), 0);
+        g_free (state_str);
+        g_free (action_str);
 
-        gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 350);
+        if (d != NULL)
+                g_object_unref (d);
+}
 
-        gtk_widget_show_all (dialog);
-        response = gtk_dialog_run (GTK_DIALOG (dialog));
+static gboolean
+on_component_label_activate_link (GtkLabel    *label,
+                                  const gchar *uri,
+                                  gpointer     user_data)
+{
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
+        GduPool *pool;
+        GduDevice *device;
+        GduPresentable *volume;
 
-        selected_presentable = gdu_pool_tree_view_get_selected_presentable (GDU_POOL_TREE_VIEW (tree_view));
-        gtk_widget_destroy (dialog);
+        pool = NULL;
+        device = NULL;
+        volume = NULL;
 
-        if (response < 0)
-                goto out;
+        pool = gdu_presentable_get_pool (gdu_section_get_presentable (GDU_SECTION (section)));
 
-        if (selected_presentable == NULL)
+        device = gdu_pool_get_by_object_path (pool, uri);
+        if (device == NULL)
                 goto out;
 
-        selected_device = gdu_presentable_get_device (selected_presentable);
-        if (selected_device == NULL)
+        volume = gdu_pool_get_volume_by_device (pool, device);
+        if (volume == NULL)
                 goto out;
 
-        g_warning ("got it: %s", gdu_device_get_object_path (selected_device));
-
-        /* got it! */
-        gdu_device_op_linux_md_add_component (device,
-                                              gdu_device_get_object_path (selected_device),
-                                              add_component_callback,
-                                              g_object_ref (section));
-
+        gdu_shell_select_presentable (gdu_section_get_shell (GDU_SECTION (section)), GDU_PRESENTABLE (volume));
 
-out:
-        g_free (array_name);
-        if (selected_presentable != NULL)
-                g_object_unref (selected_presentable);
-        if (selected_device != NULL)
-                g_object_unref (selected_device);
-        if (device != NULL)
-                g_object_unref (device);
+ out:
         if (pool != NULL)
                 g_object_unref (pool);
+        if (volume != NULL)
+                g_object_unref (volume);
+        if (device != NULL)
+                g_object_unref (device);
+        return TRUE;
 }
 
 static void
-on_attach_clicked (GtkButton *button,
-                   gpointer   user_data)
+update_components_list (GduSectionLinuxMdDrive *section)
 {
-        GtkTreePath *path;
-        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
-        GduDevice *device;
-        GduPresentable *presentable;
-        GduLinuxMdDrive *linux_md_drive;
-        GduDevice *slave_device;
+        GduPresentable *p;
         GduPool *pool;
-        GduLinuxMdDriveSlaveFlags slave_flags;
-        char *component_objpath;
+        GList *children;
+        GList *slaves;
+        GList *l;
+        gboolean is_running;
 
-        device = NULL;
-        slave_device = NULL;
-        pool = NULL;
-        component_objpath = NULL;
+        p = gdu_section_get_presentable (GDU_SECTION (section));
+        pool = gdu_presentable_get_pool (p);
+        slaves = gdu_linux_md_drive_get_slaves (GDU_LINUX_MD_DRIVE (p));
+        is_running = gdu_drive_is_active (GDU_DRIVE (p));
 
-        presentable = gdu_section_get_presentable (GDU_SECTION (section));
-        if (!GDU_IS_LINUX_MD_DRIVE (presentable)) {
-                g_warning ("%s: is not an linux_md drive", __FUNCTION__);
-                goto out;
+        /* out with the old */
+        children = gtk_container_get_children (GTK_CONTAINER (section->priv->components_vbox));
+        for (l = children; l != NULL; l = l->next) {
+                gtk_container_remove (GTK_CONTAINER (section->priv->components_vbox), GTK_WIDGET (l->data));
+        }
+        g_list_free (children);
+
+        /* and in with the new */
+        for (l = slaves; l != NULL; l = l->next) {
+                GduDevice *slave_device = GDU_DEVICE (l->data);
+                GtkWidget *hbox;
+                GtkWidget *image;
+                GtkWidget *label;
+                GduPresentable *volume;
+                gchar *vpd_name;
+                GIcon *icon;
+                gchar *s;
+                gchar *s2;
+                gchar *slave_state_str;
+
+                volume = gdu_pool_get_volume_by_device (pool, slave_device);
+                if (volume == NULL)
+                        continue;
+
+                hbox = gtk_hbox_new (FALSE, 4);
+                gtk_box_pack_start (GTK_BOX (section->priv->components_vbox), hbox, FALSE, FALSE, 0);
+
+                icon = gdu_presentable_get_icon (volume);
+                vpd_name = gdu_presentable_get_vpd_name (volume);
+
+                image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
+                gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+                s2 = g_strdup_printf ("<a href=\"%s\">%s</a>",
+                                      gdu_device_get_object_path (slave_device),
+                                      /* Translators: The text for the hyperlink of the component */
+                                      _("Go to volume"));
+
+                slave_state_str = gdu_linux_md_drive_get_slave_state_markup (GDU_LINUX_MD_DRIVE (p), slave_device);
+                if (slave_state_str != NULL) {
+
+                        /* Translators: The text used to display the RAID component for an array that is running.
+                         * First %s is the VPD name.
+                         * Second %s is the state of the component.
+                         * Third %s is the "Go to volume" link.
+                         */
+                        s = g_strdup_printf (C_("RAID component label", "%s (%s) â?? %s"),
+                                             vpd_name,
+                                             slave_state_str,
+                                             s2);
+                } else {
+                        /* Translators: The text used to display the RAID component for an array that is not running.
+                         * First %s is the VPD name.
+                         * Second %s is the "Go to volume" link.
+                         */
+                        s = g_strdup_printf (C_("RAID component label", "%s â?? %s"),
+                                             vpd_name,
+                                             s2);
+                }
+                g_free (s2);
+                label = gtk_label_new (NULL);
+                gtk_label_set_markup (GTK_LABEL (label), s);
+                gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
+                g_free (s);
+                gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+                gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+                g_signal_connect (label,
+                                  "activate-link",
+                                  G_CALLBACK (on_component_label_activate_link),
+                                  section);
+
+                g_free (vpd_name);
+                g_free (slave_state_str);
+                g_object_unref (icon);
         }
 
-        device = gdu_presentable_get_device (presentable);
-        if (device == NULL) {
-                g_warning ("%s: linux_md drive not active", __FUNCTION__);
+        gtk_widget_show_all (section->priv->components_vbox);
+
+        g_list_foreach (slaves, (GFunc) g_object_unref, NULL);
+        g_list_free (slaves);
+        g_object_unref (pool);
+}
+
+static void
+gdu_section_linux_md_drive_update (GduSection *_section)
+{
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (_section);
+        GduPresentable *p;
+        GduDevice *d;
+        gchar *s;
+        gboolean show_md_start_button;
+        gboolean show_md_stop_button;
+        gboolean show_format_button;
+        gboolean show_edit_components_button;
+        gboolean show_check_button;
+        GList *slaves;
+        GduDevice *slave;
+        const gchar *level;
+        const gchar *metadata_version;
+        const gchar *name;
+        const gchar *home_host;
+        guint num_raid_devices;
+
+        show_md_start_button = FALSE;
+        show_md_stop_button = FALSE;
+        show_format_button = FALSE;
+        show_edit_components_button = FALSE;
+        show_check_button = FALSE;
+
+        p = gdu_section_get_presentable (_section);
+        d = gdu_presentable_get_device (p);
+        slaves = gdu_linux_md_drive_get_slaves (GDU_LINUX_MD_DRIVE (p));
+        if (slaves == NULL)
                 goto out;
-        }
 
-        linux_md_drive = GDU_LINUX_MD_DRIVE (presentable);
+        slave = GDU_DEVICE (slaves->data);
 
-        gtk_tree_view_get_cursor (GTK_TREE_VIEW (section->priv->linux_md_tree_view), &path, NULL);
-        if (path != NULL) {
-                GtkTreeIter iter;
+        level = gdu_device_linux_md_component_get_level (slave);
+        metadata_version = gdu_device_linux_md_component_get_version (slave);
+        name = gdu_device_linux_md_component_get_name (slave);
+        home_host = gdu_device_linux_md_component_get_home_host (slave);
+        num_raid_devices = (guint) gdu_device_linux_md_component_get_num_raid_devices (slave);
 
-                if (gtk_tree_model_get_iter (GTK_TREE_MODEL (section->priv->linux_md_tree_store), &iter, path)) {
+        s = gdu_linux_md_get_raid_level_for_display (level, TRUE);
+        gdu_details_element_set_text (section->priv->level_element, s);
+        g_free (s);
+        gdu_details_element_set_text (section->priv->metadata_version_element, metadata_version);
 
-                        gtk_tree_model_get (GTK_TREE_MODEL (section->priv->linux_md_tree_store), &iter,
-                                            MD_LINUX_OBJPATH_COLUMN,
-                                            &component_objpath,
-                                            -1);
-                }
-                gtk_tree_path_free (path);
-        }
+        if (name != NULL && strlen (name) > 0)
+                gdu_details_element_set_text (section->priv->name_element, name);
+        else
+                gdu_details_element_set_text (section->priv->name_element, "â??");
 
-        if (component_objpath == NULL) {
-                g_warning ("%s: no component selected", __FUNCTION__);
-                goto out;
-        }
+        s = g_strdup_printf ("%d", num_raid_devices);
+        gdu_details_element_set_text (section->priv->active_components_element, s);
+        g_free (s);
 
-        pool = gdu_device_get_pool (device);
+        if (d != NULL) {
+                if (gdu_device_is_partition_table (d)) {
+                        const gchar *scheme;
+
+                        scheme = gdu_device_partition_table_get_scheme (d);
+                        if (g_strcmp0 (scheme, "apm") == 0) {
+                                s = g_strdup (_("Apple Partition Map"));
+                        } else if (g_strcmp0 (scheme, "mbr") == 0) {
+                                s = g_strdup (_("Master Boot Record"));
+                        } else if (g_strcmp0 (scheme, "gpt") == 0) {
+                                s = g_strdup (_("GUID Partition Table"));
+                        } else {
+                                /* Translators: 'scheme' refers to a partition table format here, like 'mbr' or 'gpt' */
+                                s = g_strdup_printf (_("Unknown Scheme: %s"), scheme);
+                        }
+                        gdu_details_element_set_text (section->priv->partitioning_element, s);
+                        g_free (s);
+                } else {
+                        gdu_details_element_set_text (section->priv->partitioning_element,
+                                                      _("Not Partitioned"));
+                }
 
-        slave_device = gdu_pool_get_by_object_path (pool, component_objpath);
-        if (slave_device == NULL) {
-                g_warning ("%s: no device for component objpath %s", __FUNCTION__, component_objpath);
-                goto out;
-        }
+                s = gdu_util_get_size_for_display (gdu_device_get_size (d),
+                                                   FALSE,
+                                                   TRUE);
+                gdu_details_element_set_text (section->priv->capacity_element, s);
+                g_free (s);
 
-        slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, slave_device);
-        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED) {
-                /* yay, add this to the array */
-                gdu_device_op_linux_md_add_component (device,
-                                                      component_objpath,
-                                                      add_component_callback,
-                                                      g_object_ref (section));
+                show_format_button = TRUE;
+                show_check_button = TRUE;
+                show_edit_components_button = TRUE;
+                show_md_stop_button = TRUE;
+        } else {
+                gdu_details_element_set_text (section->priv->partitioning_element, "â??");
+                /* TODO: maybe try and compute the size when not running */
+                gdu_details_element_set_text (section->priv->capacity_element, "â??");
+                show_md_start_button = TRUE;
         }
 
+ out:
+        update_state_and_action_elements (section);
+        update_components_list (section);
 
-out:
-        g_free (component_objpath);
-        if (device != NULL)
-                g_object_unref (device);
-        if (pool != NULL)
-                g_object_unref (pool);
-        if (slave_device != NULL)
-                g_object_unref (slave_device);
+        gdu_button_element_set_visible (section->priv->md_start_button, show_md_start_button);
+        gdu_button_element_set_visible (section->priv->md_stop_button, show_md_stop_button);
+        gdu_button_element_set_visible (section->priv->format_button, show_format_button);
+        gdu_button_element_set_visible (section->priv->edit_components_button, show_edit_components_button);
+        gdu_button_element_set_visible (section->priv->check_button, show_check_button);
+
+        if (d != NULL)
+                g_object_unref (d);
+        g_list_foreach (slaves, (GFunc) g_object_unref, NULL);
+        g_list_free (slaves);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
-remove_component_callback (GduDevice *device,
-                           GError *error,
-                           gpointer user_data)
+md_stop_op_callback (GduDevice *device,
+                     GError    *error,
+                     gpointer   user_data)
 {
-        GduSection *section = GDU_SECTION (user_data);
+        GduShell *shell = GDU_SHELL (user_data);
+
         if (error != NULL) {
-                gdu_shell_raise_error (gdu_section_get_shell (section),
-                                       gdu_section_get_presentable (section),
-                                       error,
-                                       _("Error removing component"));
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+                                                         device,
+                                                         _("Error stopping RAID Array"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
         }
-        g_object_unref (section);
+        g_object_unref (shell);
 }
 
 static void
-on_detach_clicked (GtkButton *button,
-                   gpointer   user_data)
+on_md_stop_button_clicked (GduButtonElement *button_element,
+                           gpointer          user_data)
 {
-        GtkTreePath *path;
         GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
-        GduDevice *device;
-        GduPresentable *presentable;
-        GduLinuxMdDrive *linux_md_drive;
-        GduDevice *slave_device;
-        GduPool *pool;
-        GduLinuxMdDriveSlaveFlags slave_flags;
-        char *component_objpath;
-        GduPresentable *slave_presentable;
-
-        device = NULL;
-        slave_device = NULL;
-        pool = NULL;
-        component_objpath = NULL;
-        slave_presentable = NULL;
+        GduDevice *d;
 
-        presentable = gdu_section_get_presentable (GDU_SECTION (section));
-        if (!GDU_IS_LINUX_MD_DRIVE (presentable)) {
-                g_warning ("%s: is not an linux_md drive", __FUNCTION__);
+        d = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
+        if (d == NULL)
                 goto out;
-        }
 
-        device = gdu_presentable_get_device (presentable);
-        if (device == NULL) {
-                g_warning ("%s: linux_md drive not active", __FUNCTION__);
-                goto out;
-        }
+        gdu_device_op_linux_md_stop (d,
+                                     md_stop_op_callback,
+                                     g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
 
-        linux_md_drive = GDU_LINUX_MD_DRIVE (presentable);
+        g_object_unref (d);
+ out:
+        ;
+}
 
-        gtk_tree_view_get_cursor (GTK_TREE_VIEW (section->priv->linux_md_tree_view), &path, NULL);
-        if (path != NULL) {
-                GtkTreeIter iter;
+/* ---------------------------------------------------------------------------------------------------- */
 
-                if (gtk_tree_model_get_iter (GTK_TREE_MODEL (section->priv->linux_md_tree_store), &iter, path)) {
+static void
+md_start_op_callback (GduDrive   *drive,
+                      gchar      *assembled_drive_object_path,
+                      GError     *error,
+                      gpointer    user_data)
+{
+        GduShell *shell = GDU_SHELL (user_data);
 
-                        gtk_tree_model_get (GTK_TREE_MODEL (section->priv->linux_md_tree_store), &iter,
-                                            MD_LINUX_OBJPATH_COLUMN,
-                                            &component_objpath,
-                                            -1);
-                }
-                gtk_tree_path_free (path);
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+                                               GDU_PRESENTABLE (drive),
+                                               _("Error starting RAID Array"),
+                                               error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
+        } else {
+                g_free (assembled_drive_object_path);
         }
+        g_object_unref (shell);
+}
 
-        if (component_objpath == NULL) {
-                g_warning ("%s: no component selected", __FUNCTION__);
+static void
+on_md_start_button_clicked (GduButtonElement *button_element,
+                            gpointer          user_data)
+{
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
+        GduDrive *drive;
+        gboolean degraded;
+        GtkWindow *toplevel;
+
+        drive = GDU_DRIVE (gdu_section_get_presentable (GDU_SECTION (section)));
+        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
+
+        if (!gdu_drive_can_activate (drive, &degraded)) {
+                GtkWidget *dialog;
+                GError *error;
+                error = g_error_new (GDU_ERROR,
+                                     GDU_ERROR_FAILED,
+                                     _("Not enough components available to start the RAID Array"));
+                dialog = gdu_error_dialog_new (toplevel,
+                                               GDU_PRESENTABLE (drive),
+                                               _("Not enough components available to start the RAID Array"),
+                                               error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
                 goto out;
         }
 
-        pool = gdu_device_get_pool (device);
-
-        slave_device = gdu_pool_get_by_object_path (pool, component_objpath);
-        if (slave_device == NULL) {
-                g_warning ("%s: no device for component objpath %s", __FUNCTION__, component_objpath);
-                goto out;
+        if (degraded) {
+                GtkWidget *dialog;
+                gint response;
+
+                dialog = gdu_confirmation_dialog_new (toplevel,
+                                                      GDU_PRESENTABLE (drive),
+                                                      _("Are you sure you want the RAID Array degraded?"),
+                                                      _("_Start"));
+                gtk_widget_show_all (dialog);
+                response = gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_hide (dialog);
+                gtk_widget_destroy (dialog);
+                if (response != GTK_RESPONSE_OK)
+                        goto out;
         }
 
-        slave_presentable = gdu_pool_get_volume_by_device (pool, slave_device);
-        if (slave_presentable == NULL) {
-                g_warning ("%s: no volume for component objpath %s", __FUNCTION__, component_objpath);
-                goto out;
-        }
+        gdu_drive_activate (drive,
+                            md_start_op_callback,
+                            g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
 
-        slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, slave_device);
-        if (!(slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED)) {
-                char *primary;
-                char *secondary;
-                gboolean do_erase;
-                char *array_name;
-                char *component_name;
-
-                array_name = gdu_presentable_get_name (presentable);
-                component_name = gdu_presentable_get_name (slave_presentable);
-
-                /* confirmation dialog */
-                primary = g_strconcat ("<b><big>", _("Are you sure you want to remove the component from the array ?"), "</big></b>", NULL);
-
-                secondary = g_strdup_printf (_("The data on component \"%s\" of the RAID Array \"%s\" will be "
-                                               "irrevocably erased and the RAID Array might be degraded. "
-                                               "Make sure important data is backed up. "
-                                               "This action cannot be undone."),
-                                             component_name,
-                                             array_name);
-
-                do_erase = gdu_util_delete_confirmation_dialog (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))),
-                                                                "",
-                                                                primary,
-                                                                secondary,
-                                                                _("_Remove Component"));
-                if (do_erase) {
-                        /* yay, remove this component from the array */
-                        gdu_device_op_linux_md_remove_component (device,
-                                                                 component_objpath,
-                                                                 remove_component_callback,
-                                                                 g_object_ref (section));
-                }
+ out:
+        ;
+}
 
-                g_free (primary);
-                g_free (secondary);
-                g_free (array_name);
-                g_free (component_name);
-        }
+/* ---------------------------------------------------------------------------------------------------- */
 
+typedef struct {
+        GduShell *shell;
+        GduLinuxMdDrive *array;
+        GduDevice *slave;
+} RemoveComponentData;
 
-out:
-        g_free (component_objpath);
-        if (device != NULL)
-                g_object_unref (device);
-        if (pool != NULL)
-                g_object_unref (pool);
-        if (slave_device != NULL)
-                g_object_unref (slave_device);
-        if (slave_presentable != NULL)
-                g_object_unref (slave_presentable);
+static void
+remove_component_data_free (RemoveComponentData *data)
+{
+        g_object_unref (data->shell);
+        g_object_unref (data->array);
+        g_object_unref (data->slave);
+        g_free (data);
 }
 
 static void
-on_check_clicked (GtkButton *button,
-                  gpointer   user_data)
+remove_component_delete_partition_op_callback (GduDevice  *device,
+                                               GError     *error,
+                                               gpointer    user_data)
 {
-        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
-        GduPresentable *presentable;
-        GduDevice *device;
+        RemoveComponentData *data = user_data;
 
-        presentable = gdu_section_get_presentable (GDU_SECTION (section));
-        if (!GDU_IS_LINUX_MD_DRIVE (presentable)) {
-                g_warning ("%s: is not an linux_md drive", __FUNCTION__);
-                goto out;
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (data->shell)),
+                                                         device,
+                                                         _("Error deleting partition for component in RAID Array"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
         }
 
-        device = gdu_presentable_get_device (presentable);
-        if (device == NULL) {
-                g_warning ("%s: linux_md drive not active", __FUNCTION__);
-                goto out;
-        }
+        remove_component_data_free (data);
+}
 
-        gdu_device_op_linux_md_check (device,
-                                      NULL,
-                                      NULL,
-                                      NULL); /* TODO: report result back? */
+static void
+remove_component_op_callback (GduDevice  *device,
+                              GError     *error,
+                              gpointer    user_data)
+{
+        RemoveComponentData *data = user_data;
 
- out:
-        if (device != NULL)
-                g_object_unref (device);
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (data->shell)),
+                                                         device,
+                                                         _("Error removing component from RAID Array"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
+
+                remove_component_data_free (data);
+        } else {
+                /* if the device is a partition, also remove the partition */
+                if (gdu_device_is_partition (data->slave)) {
+                        gdu_device_op_partition_delete (data->slave,
+                                                        remove_component_delete_partition_op_callback,
+                                                        data);
+                } else {
+                        remove_component_data_free (data);
+                }
+        }
 }
 
 static void
-on_repair_clicked (GtkButton *button,
-                   gpointer   user_data)
+on_components_dialog_remove_button_clicked (GduEditLinuxMdDialog *_dialog,
+                                            GduDevice            *slave_device,
+                                            gpointer              user_data)
 {
         GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
-        GduPresentable *presentable;
+        GduLinuxMdDrive *linux_md_drive;
         GduDevice *device;
-        gchar *options[2];
+        GduLinuxMdDriveSlaveFlags slave_flags;
+        GtkWindow *toplevel;
+        GtkWidget *dialog;
+        gint response;
+        RemoveComponentData *data;
+
+        device = NULL;
 
-        options[0] = "repair";
-        options[1] = NULL;
+        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
 
-        presentable = gdu_section_get_presentable (GDU_SECTION (section));
-        if (!GDU_IS_LINUX_MD_DRIVE (presentable)) {
-                g_warning ("%s: is not an linux_md drive", __FUNCTION__);
+        linux_md_drive = GDU_LINUX_MD_DRIVE (gdu_section_get_presentable (GDU_SECTION (section)));
+        device = gdu_presentable_get_device (GDU_PRESENTABLE (linux_md_drive));
+        if (device == NULL)
+                goto out;
+
+        slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, slave_device);
+        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED)
                 goto out;
-        }
 
-        device = gdu_presentable_get_device (presentable);
-        if (device == NULL) {
-                g_warning ("%s: linux_md drive not active", __FUNCTION__);
+        /* TODO: more details in this dialog - e.g. "The RAID array may degrade" etc etc */
+        dialog = gdu_confirmation_dialog_new_for_volume (toplevel,
+                                                         slave_device,
+                                                         _("Are you sure you want the remove the component?"),
+                                                         _("_Remove"));
+        gtk_widget_show_all (dialog);
+        response = gtk_dialog_run (GTK_DIALOG (dialog));
+        gtk_widget_hide (dialog);
+        gtk_widget_destroy (dialog);
+        if (response != GTK_RESPONSE_OK)
                 goto out;
-        }
 
-        gdu_device_op_linux_md_check (device,
-                                      options,
-                                      NULL,
-                                      NULL); /* TODO: report result back? */
+        data = g_new0 (RemoveComponentData, 1);
+        data->shell = g_object_ref (gdu_section_get_shell (GDU_SECTION (section)));
+        data->array = g_object_ref (linux_md_drive);
+        data->slave = g_object_ref (slave_device);
+
+        gdu_device_op_linux_md_remove_component (device,
+                                                 gdu_device_get_object_path (slave_device),
+                                                 remove_component_op_callback,
+                                                 data);
 
  out:
         if (device != NULL)
                 g_object_unref (device);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+attach_component_op_callback (GduDevice  *device,
+                              GError     *error,
+                              gpointer    user_data)
+{
+        GduShell *shell = GDU_SHELL (user_data);
+
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+                                                         device,
+                                                         _("Error adding component to RAID Array"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
+        }
+        g_object_unref (shell);
+}
+
 static void
-linux_md_buttons_update (GduSectionLinuxMdDrive *section)
+on_components_dialog_attach_button_clicked (GduEditLinuxMdDialog *_dialog,
+                                            GduDevice            *slave_device,
+                                            gpointer              user_data)
 {
-        GtkTreePath *path;
-        char *component_objpath;
-        gboolean show_add_new_to_array_button;
-        gboolean show_attach_to_array_button;
-        gboolean show_detach_from_array_button;
-        GduPresentable *presentable;
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
         GduLinuxMdDrive *linux_md_drive;
         GduDevice *device;
-        GduDevice *slave_device;
-        GduPool *pool;
         GduLinuxMdDriveSlaveFlags slave_flags;
 
-        component_objpath = NULL;
         device = NULL;
-        slave_device = NULL;
-        pool = NULL;
-        show_add_new_to_array_button = FALSE;
-        show_attach_to_array_button = FALSE;
-        show_detach_from_array_button = FALSE;
-
-        gtk_tree_view_get_cursor (GTK_TREE_VIEW (section->priv->linux_md_tree_view), &path, NULL);
-        if (path != NULL) {
-                GtkTreeIter iter;
-
-                if (gtk_tree_model_get_iter (GTK_TREE_MODEL (section->priv->linux_md_tree_store), &iter, path)) {
-
-                        gtk_tree_model_get (GTK_TREE_MODEL (section->priv->linux_md_tree_store), &iter,
-                                            MD_LINUX_OBJPATH_COLUMN,
-                                            &component_objpath,
-                                            -1);
-                }
-                gtk_tree_path_free (path);
-        }
 
-        presentable = gdu_section_get_presentable (GDU_SECTION (section));
-        if (!GDU_IS_LINUX_MD_DRIVE (presentable)) {
-                g_warning ("%s: is not an linux_md drive", __FUNCTION__);
+        linux_md_drive = GDU_LINUX_MD_DRIVE (gdu_section_get_presentable (GDU_SECTION (section)));
+        device = gdu_presentable_get_device (GDU_PRESENTABLE (linux_md_drive));
+        if (device == NULL)
                 goto out;
-        }
-
-        linux_md_drive = GDU_LINUX_MD_DRIVE (presentable);
-
-        /* can only add/remove components on an active drive */
-        device = gdu_presentable_get_device (presentable);
-
-        if (!gdu_drive_is_active (GDU_DRIVE (presentable))) {
-                goto out;
-        }
-
-        /* can always add a new component when the drive is running */
-        show_add_new_to_array_button = TRUE;
-
-        pool = gdu_device_get_pool (device);
-
-        if (component_objpath != NULL) {
-
-                slave_device = gdu_pool_get_by_object_path (pool, component_objpath);
-                if (slave_device == NULL) {
-                        g_warning ("%s: no device for component objpath %s", __FUNCTION__, component_objpath);
-                        goto out;
-                }
 
-                slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, slave_device);
-
-                if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED) {
-                        /* yay, we can attach this slave to the array */
-                        show_attach_to_array_button = TRUE;
-                } else {
-                        /* yay, we can remove this to the array */
-                        show_detach_from_array_button = TRUE;
-                }
+        slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, slave_device);
+        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED) {
+                gdu_device_op_linux_md_add_component (device,
+                                                      gdu_device_get_object_path (slave_device),
+                                                      attach_component_op_callback,
+                                                      g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
         }
 
-out:
-        gtk_widget_set_sensitive (section->priv->attach_button, show_attach_to_array_button);
-        gtk_widget_set_sensitive (section->priv->detach_button, show_detach_from_array_button);
-        gtk_widget_set_sensitive (section->priv->add_button, show_add_new_to_array_button);
-
-        g_free (component_objpath);
+ out:
         if (device != NULL)
                 g_object_unref (device);
-        if (pool != NULL)
-                g_object_unref (pool);
-        if (slave_device != NULL)
-                g_object_unref (slave_device);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+        GduShell *shell;
+        GduLinuxMdDrive *linux_md_drive;
+} AddComponentData;
+
 static void
-linux_md_tree_changed (GtkTreeSelection *selection, gpointer user_data)
+add_component_data_free (AddComponentData *data)
 {
-        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
-        linux_md_buttons_update (section);
+        if (data->shell != NULL)
+                g_object_unref (data->shell);
+        if (data->linux_md_drive != NULL)
+                g_object_unref (data->linux_md_drive);
+        g_free (data);
 }
 
 static void
-update (GduSectionLinuxMdDrive *section)
+add_component_cb (GduDevice  *device,
+                  GError     *error,
+                  gpointer    user_data)
 {
-        char *s;
-        GduDevice *device;
-        GduPresentable *presentable;
-        GduLinuxMdDrive *linux_md_drive;
-        GList *l;
-        GList *slaves;
-        GduDevice *component;
-        const char *uuid;
-        const char *name;
-        const gchar *home_host;
-        const char *level;
-        int num_raid_devices;
-        int num_slaves;
-        char *level_str;
-        guint64 component_size;
-        guint64 raid_size;
-        char *raid_size_str;
-        char *components_str;
-        char *state_str;
-
-        slaves = NULL;
-        device = NULL;
-        level_str = NULL;
-        raid_size_str = NULL;
-        components_str = NULL;
-        state_str = NULL;
-
-        presentable = gdu_section_get_presentable (GDU_SECTION (section));
-        linux_md_drive = GDU_LINUX_MD_DRIVE (presentable);
-        device = gdu_presentable_get_device (presentable);
-
-        slaves = gdu_linux_md_drive_get_slaves (linux_md_drive);
-        num_slaves = g_list_length (slaves);
-
-        if (num_slaves == 0) {
-                /* This happens for 'clear' arrays or for arrays with stale symlinks
-                 * to devices that has been yanked.
-                 *
-                 * - Ideally Linux MD / mdadm wouldn't have stale symlinks in sysfs but
-                 *   that is not how things currently work (2.6.29).
-                 *
-                 * - Also sometimes when stopping an array the md device is still around
-                 *
-                 * So we only offer to stop such arrays since the software beneath us
-                 * is unstable. In an ideal world we wouldn't show them.
-                 */
-
-                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_name_label), "-");
-                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_home_host_label), "-");
-                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_type_label), "-");
-                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_size_label), "-");
-                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_components_label), "-");
-                gtk_label_set_markup (GTK_LABEL (section->priv->linux_md_state_label), "-");
-
-                gtk_widget_set_sensitive (GTK_WIDGET (section), FALSE);
-                goto out;
-        }
-
-        gtk_widget_set_sensitive (GTK_WIDGET (section), TRUE);
+        GduShell *shell = GDU_SHELL (user_data);
 
-        component = GDU_DEVICE (slaves->data);
-
-        if (!gdu_device_is_linux_md_component (component)) {
-                g_warning ("%s: slave of linux_md drive is not a linux md component", __FUNCTION__);
-                goto out;
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+                                                         device,
+                                                         _("Error adding component to RAID Array"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
         }
+        g_object_unref (shell);
+}
 
-        uuid = gdu_device_linux_md_component_get_uuid (component);
-        name = gdu_device_linux_md_component_get_name (component);
-        if (name == NULL || strlen (name) == 0) {
-                name = "-";
-        }
-        home_host = gdu_device_linux_md_component_get_home_host (component);
-        if (home_host == NULL || strlen (home_host) == 0) {
-                home_host = "-";
-        }
-        level = gdu_device_linux_md_component_get_level (component);
-        num_raid_devices = gdu_device_linux_md_component_get_num_raid_devices (component);
-        component_size = gdu_device_get_size (component);
-
-        /*g_warning ("linux_md drive:\n"
-                   "uuid=%s\n"
-                   "name=%s\n"
-                   "level=%s\n"
-                   "num_raid_devices=%d\n"
-                   "num_slaves=%d\n"
-                   "device=%p",
-                   uuid, name, level, num_raid_devices, num_slaves, device);*/
-
-        raid_size = gdu_presentable_get_size (presentable);
-
-        if (strcmp (level, "raid0") == 0) {
-                level_str = g_strdup (C_("RAID component type", "Striped (RAID-0)"));
-        } else if (strcmp (level, "raid1") == 0) {
-                level_str = g_strdup (C_("RAID component type", "Mirrored (RAID-1)"));
-        } else if (strcmp (level, "raid4") == 0) {
-                level_str = g_strdup (C_("RAID component type", "RAID-4"));
-        } else if (strcmp (level, "raid5") == 0) {
-                level_str = g_strdup (C_("RAID component type", "RAID-5"));
-        } else if (strcmp (level, "raid6") == 0) {
-                level_str = g_strdup (C_("RAID component type", "RAID-6"));
-        } else if (strcmp (level, "linear") == 0) {
-                level_str = g_strdup (C_("RAID component type", "Linear (Just a Bunch Of Disks)"));
-        } else {
-                level_str = g_strdup (level);
-        }
+static void
+add_component_create_part_cb (GduDevice  *device,
+                              gchar      *created_device_object_path,
+                              GError     *error,
+                              gpointer    user_data)
+{
+        AddComponentData *data = user_data;
 
-        s = gdu_util_get_size_for_display (component_size,
-                                           FALSE,
-                                           FALSE);
-        if (strcmp (level, "linear") == 0) {
-                /* Translators: %d is the number of components in the RAID */
-                components_str = g_strdup_printf (ngettext ("%d Component", "%d Components", num_raid_devices), num_raid_devices);
-        } else {
-                /* Translators: %d is the number of components in the RAID,
-                 * %s is the size of each component, formatted like '45 GB'
-                 */
-                components_str = g_strdup_printf (ngettext ("%d Component (%s)", "%d Components (%s each)", num_raid_devices), num_raid_devices, s);
-        }
-        g_free (s);
- 
-        if (raid_size == 0) {
-                raid_size_str = g_strdup_printf ("-");
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (data->shell)),
+                                                         device,
+                                                         _("Error creating partition for RAID component"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
         } else {
-                raid_size_str = gdu_util_get_size_for_display (raid_size,
-                                                               FALSE,
-                                                               TRUE);
+                GduDevice *array_device;
+                array_device = gdu_presentable_get_device (GDU_PRESENTABLE (data->linux_md_drive));
+                gdu_device_op_linux_md_add_component (array_device,
+                                                      created_device_object_path,
+                                                      add_component_cb,
+                                                      g_object_ref (data->shell));
+                g_free (created_device_object_path);
+                g_object_unref (array_device);
         }
 
-        if (!gdu_drive_is_active (GDU_DRIVE (linux_md_drive))) {
-                if (device != NULL) {
-                        state_str = g_strdup (C_("RAID status", "Not running, partially assembled"));
-                } else {
-                        gboolean can_activate;
-                        gboolean degraded;
+        if (data != NULL)
+                add_component_data_free (data);
+}
 
-                        can_activate = gdu_drive_can_activate (GDU_DRIVE (linux_md_drive), &degraded);
 
-                        if (can_activate && !degraded) {
-                                state_str = g_strdup (C_("RAID status", "Not running"));
-                        } else if (can_activate && degraded) {
-                                state_str = g_strdup (C_("RAID status", "Not running, can only start degraded"));
-                        } else {
-                                state_str = g_strdup (C_("RAID status", "Not running, not enough components to start"));
-                        }
-                }
-        } else {
-                gboolean is_degraded;
-                const char *sync_action;
-                double sync_percentage;
-                guint64 sync_speed;
-                char *sync_speed_str;
-                GString *str;
+static void
+on_components_dialog_new_button_clicked (GduEditLinuxMdDialog *_dialog,
+                                         gpointer              user_data)
+{
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
+        GduLinuxMdDrive *linux_md_drive;
+        GduDevice *device;
+        GtkWidget *dialog;
+        gint response;
+        GtkWindow *toplevel;
+        GduDrive *drive;
+        guint64 size;
+        gboolean whole_disk_is_uninitialized;
+        guint64 largest_segment;
+        GduPresentable *p;
+        GduDevice *d;
+        AddComponentData *data;
 
-                is_degraded = gdu_device_linux_md_is_degraded (device);
-                sync_action = gdu_device_linux_md_get_sync_action (device);
-                sync_percentage = gdu_device_linux_md_get_sync_percentage (device);
-                sync_speed = gdu_device_linux_md_get_sync_speed (device);
+        device = NULL;
+        drive = NULL;
+        p = NULL;
+        d = NULL;
+        dialog = NULL;
 
-                str = g_string_new (NULL);
-                if (is_degraded) {
-                        g_string_append (str, "<span foreground='red'><b>");
-                        g_string_append (str, C_("RAID status", "Degraded"));
-                        g_string_append (str, "</b></span>");
-                }
-                else
-                        g_string_append (str, C_("RAID status", "Running"));
+        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
 
-                if (strcmp (sync_action, "idle") != 0) {
-                        if (strcmp (sync_action, "reshape") == 0) {
-                                g_string_append (str, ", ");
-                                g_string_append (str, C_("RAID status", "Reshaping"));
-                        } else if (strcmp (sync_action, "resync") == 0) {
-                                g_string_append (str, ", ");
-                                g_string_append (str, C_("RAID status", "Resyncing"));
-                        } else if (strcmp (sync_action, "repair") == 0) {
-                                g_string_append (str, ", ");
-                                g_string_append (str, C_("RAID status", "Repairing"));
-                        } else if (strcmp (sync_action, "recover") == 0) {
-                                g_string_append (str, ", ");
-                                g_string_append (str, C_("RAID status", "Recovering"));
-                        } else if (strcmp (sync_action, "check") == 0) {
-                                g_string_append (str, ", ");
-                                g_string_append (str, C_("RAID status", "Checking"));
-                        }
+        linux_md_drive = GDU_LINUX_MD_DRIVE (gdu_section_get_presentable (GDU_SECTION (section)));
+        device = gdu_presentable_get_device (GDU_PRESENTABLE (linux_md_drive));
+        if (device == NULL)
+                goto out;
 
-                        sync_speed_str = gdu_util_get_speed_for_display (sync_speed);
-                        /* Translators: this string tells about an ongoing synchronization.
-                         * %3.01f is replaced by the percentage of completion
-                         * %s is replaced by the speed of the operation
-                         */
-                        g_string_append_printf (str, C_("RAID status", " @ %3.01f%% (%s)"), sync_percentage, sync_speed_str);
-                        g_free (sync_speed_str);
+        dialog = gdu_add_component_linux_md_dialog_new (toplevel, linux_md_drive);
+        gtk_widget_show_all (dialog);
+        response = gtk_dialog_run (GTK_DIALOG (dialog));
+        gtk_widget_hide (dialog);
+        if (response != GTK_RESPONSE_APPLY)
+                goto out;
+
+        drive = gdu_add_component_linux_md_dialog_get_drive (GDU_ADD_COMPONENT_LINUX_MD_DIALOG (dialog));
+        size = gdu_add_component_linux_md_dialog_get_size (GDU_ADD_COMPONENT_LINUX_MD_DIALOG (dialog));
+
+        g_warn_if_fail (gdu_drive_has_unallocated_space (drive,
+                                                         &whole_disk_is_uninitialized,
+                                                         &largest_segment,
+                                                         &p));
+        g_assert (p != NULL);
+        g_assert_cmpint (size, <=, largest_segment);
+
+        d = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
+
+        if (GDU_IS_VOLUME_HOLE (p)) {
+                guint64 offset;
+                const gchar *scheme;
+                const gchar *type;
+                const gchar *name;
+                gchar *label;
+
+                offset = gdu_presentable_get_offset (p);
+
+                /*g_debug ("Creating partition for component of "
+                         "size %" G_GUINT64_FORMAT " bytes at offset %" G_GUINT64_FORMAT " on %s",
+                         size,
+                         offset,
+                         gdu_device_get_device_file (d));*/
+
+                scheme = gdu_device_partition_table_get_scheme (d);
+                type = "";
+                label = NULL;
+                name = gdu_device_linux_md_get_name (device);
+
+                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 */
+                        if (name != NULL && strlen (name) > 0)
+                                label = g_strdup_printf ("RAID: %s", name);
+                        else
+                                label = g_strdup ("RAID Component");
+                } else if (g_strcmp0 (scheme, "apt") == 0) {
+                        type = "Apple_Unix_SVR2";
+                        if (name != NULL && strlen (name) > 0)
+                                label = g_strdup_printf ("RAID: %s", name);
+                        else
+                                label = g_strdup ("RAID Component");
                 }
 
-                state_str = g_string_free (str, FALSE);
+                data = g_new0 (AddComponentData, 1);
+                data->shell = g_object_ref (gdu_section_get_shell (GDU_SECTION (section)));
+                data->linux_md_drive = g_object_ref (linux_md_drive);
+
+                gdu_device_op_partition_create (d,
+                                                offset,
+                                                size,
+                                                type,
+                                                label != NULL ? label : "",
+                                                NULL,
+                                                "",
+                                                "",
+                                                "",
+                                                FALSE,
+                                                add_component_create_part_cb,
+                                                data);
+                g_free (label);
+        } else {
+                g_error ("TODO: handle adding component on non-partitioned drive");
         }
 
-        gtk_label_set_text (GTK_LABEL (section->priv->linux_md_name_label), name);
-        gtk_label_set_text (GTK_LABEL (section->priv->linux_md_home_host_label), home_host);
-        gtk_label_set_text (GTK_LABEL (section->priv->linux_md_type_label), level_str);
-        gtk_label_set_text (GTK_LABEL (section->priv->linux_md_size_label), raid_size_str);
-        gtk_label_set_text (GTK_LABEL (section->priv->linux_md_components_label), components_str);
-        gtk_label_set_markup (GTK_LABEL (section->priv->linux_md_state_label), state_str);
-
-        /* only build a new model if rebuilding the section */
-        //if (reset_section) {
-        {
-                GtkTreeStore *store;
-
-                if (section->priv->linux_md_tree_store != NULL)
-                        g_object_unref (section->priv->linux_md_tree_store);
-
-                store = gtk_tree_store_new (MD_LINUX_N_COLUMNS,
-                                            GDK_TYPE_PIXBUF,
-                                            G_TYPE_STRING,
-                                            G_TYPE_STRING,
-                                            G_TYPE_INT,
-                                            G_TYPE_STRING);
-                section->priv->linux_md_tree_store = store;
-
-                gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
-                                                      MD_LINUX_OBJPATH_COLUMN,
-                                                      GTK_SORT_ASCENDING);
-
-                /* add all slaves */
-                for (l = slaves; l != NULL; l = l->next) {
-                        GduDevice *sd = GDU_DEVICE (l->data);
-                        GdkPixbuf *pixbuf;
-                        char *name;
-                        GtkTreeIter iter;
-                        GduPool *pool;
-                        GduPresentable *p;
-                        GduLinuxMdDriveSlaveFlags slave_flags;
-                        GPtrArray *slave_state;
-                        char *slave_state_str;
-                        char *s;
-
-                        pool = gdu_device_get_pool (sd);
-                        p = gdu_pool_get_volume_by_device (pool, sd);
-                        g_object_unref (pool);
-
-                        if (p == NULL) {
-                                g_warning ("Cannot find volume for device");
-                                continue;
-                        }
+ out:
+        if (dialog != NULL)
+                gtk_widget_destroy (dialog);
+        if (drive != NULL)
+                g_object_unref (drive);
+        if (p != NULL)
+                g_object_unref (p);
+        if (device != NULL)
+                g_object_unref (device);
+        if (d != NULL)
+                g_object_unref (d);
+}
 
-                        s = gdu_presentable_get_name (p);
-                        name = g_strdup_printf ("%s (%s)", s, gdu_device_get_device_file (sd));
-                        g_free (s);
-                        pixbuf = gdu_util_get_pixbuf_for_presentable (p, GTK_ICON_SIZE_MENU);
-
-                        slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, sd);
-                        slave_state = g_ptr_array_new ();
-                        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED)
-                                g_ptr_array_add (slave_state, "-");
-                        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_FAULTY) {
-                                s = g_strconcat ("<span foreground='red'><b>", C_("Linux MD slave state", "Faulty"), "</b></span>", NULL);
-                                g_ptr_array_add (slave_state, s);
-                                g_free (s);
-                        }
-                        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_IN_SYNC)
-                                g_ptr_array_add (slave_state, (gpointer) C_("Linux MD slave state", "In Sync"));
-                        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_WRITEMOSTLY)
-                                g_ptr_array_add (slave_state, (gpointer) C_("Linux MD slave state", "Writemostly"));
-                        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_BLOCKED)
-                                g_ptr_array_add (slave_state, (gpointer) C_("Linux MD slave state", "Blocked"));
-                        if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_SPARE)
-                                g_ptr_array_add (slave_state, (gpointer) C_("Linux MD slave state", "Spare"));
-                        g_ptr_array_add (slave_state, NULL);
-                        slave_state_str = g_strjoinv (", ", (gchar **) slave_state->pdata);
-                        g_ptr_array_free (slave_state, TRUE);
-
-                        gtk_tree_store_append (store, &iter, NULL);
-                        gtk_tree_store_set (store,
-                                            &iter,
-                                            MD_LINUX_ICON_COLUMN, pixbuf,
-                                            MD_LINUX_NAME_COLUMN, name,
-                                            MD_LINUX_STATE_STRING_COLUMN, slave_state_str,
-                                            MD_LINUX_STATE_COLUMN, slave_state,
-                                            MD_LINUX_OBJPATH_COLUMN, gdu_device_get_object_path (sd),
-                                            -1);
-
-                        g_free (name);
-                        g_free (slave_state_str);
-                        if (pixbuf != NULL)
-                                g_object_unref (pixbuf);
-
-                        g_object_unref (p);
-                }
+/* ---------------------------------------------------------------------------------------------------- */
 
-                gtk_tree_view_set_model (GTK_TREE_VIEW (section->priv->linux_md_tree_view),
-                                         GTK_TREE_MODEL (store));
+static void
+on_edit_components_button_clicked (GduButtonElement *button_element,
+                                   gpointer          user_data)
+{
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
+        GduPresentable *p;
+        GtkWindow *toplevel;
+        GtkWidget *dialog;
 
-        }
+        p = gdu_section_get_presentable (GDU_SECTION (section));
+        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
 
-        linux_md_buttons_update (section);
+        dialog = gdu_edit_linux_md_dialog_new (toplevel, GDU_LINUX_MD_DRIVE (p));
 
-out:
-        g_free (state_str);
-        g_free (level_str);
-        g_free (raid_size_str);
-        g_free (components_str);
-        g_list_foreach (slaves, (GFunc) g_object_unref, NULL);
-        g_list_free (slaves);
-        if (device != NULL)
-                g_object_unref (device);
+        g_signal_connect (dialog,
+                          "new-button-clicked",
+                          G_CALLBACK (on_components_dialog_new_button_clicked),
+                          section);
+        g_signal_connect (dialog,
+                          "attach-button-clicked",
+                          G_CALLBACK (on_components_dialog_attach_button_clicked),
+                          section);
+        g_signal_connect (dialog,
+                          "remove-button-clicked",
+                          G_CALLBACK (on_components_dialog_remove_button_clicked),
+                          section);
+
+        gtk_widget_show_all (dialog);
+        gtk_window_present (GTK_WINDOW (dialog));
+        gtk_dialog_run (GTK_DIALOG (dialog));
+        gtk_widget_destroy (dialog);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-gdu_section_linux_md_drive_finalize (GduSectionLinuxMdDrive *section)
+md_check_op_callback (GduDevice *device,
+                      guint      num_errors,
+                      GError    *error,
+                      gpointer   user_data)
 {
-        if (G_OBJECT_CLASS (parent_class)->finalize)
-                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (section));
+        GduShell *shell = GDU_SHELL (user_data);
+
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+                                                         device,
+                                                         _("Error checking RAID Array"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
+        } else {
+                /* TODO: report result back? */
+        }
+        g_object_unref (shell);
 }
 
 static void
-gdu_section_linux_md_drive_class_init (GduSectionLinuxMdDriveClass *klass)
+on_check_button_clicked (GduButtonElement *button_element,
+                         gpointer          user_data)
 {
-        GObjectClass *obj_class = (GObjectClass *) klass;
-        GduSectionClass *section_class = (GduSectionClass *) klass;
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
+        const gchar *options[] = {"repair", NULL};
+        GduDevice *d;
 
-        parent_class = g_type_class_peek_parent (klass);
+        d = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
+        if (d == NULL)
+                goto out;
 
-        obj_class->finalize = (GObjectFinalizeFunc) gdu_section_linux_md_drive_finalize;
-        section_class->update = (gpointer) update;
+        gdu_device_op_linux_md_check (d,
+                                      (gchar **) options,
+                                      md_check_op_callback,
+                                      g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
 
-        g_type_class_add_private (klass, sizeof (GduSectionLinuxMdDrivePrivate));
+        g_object_unref (d);
+ out:
+        ;
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
-gdu_section_linux_md_drive_init (GduSectionLinuxMdDrive *section)
+gdu_section_linux_md_drive_constructed (GObject *object)
 {
-        int row;
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (object);
+        GtkWidget *align;
         GtkWidget *label;
         GtkWidget *table;
-        GtkWidget *button_box;
-        GtkWidget *scrolled_window;
-        GtkWidget *tree_view;
-        GtkWidget *button;
-        GtkTreeSelection *selection;
-        GtkCellRenderer *renderer;
-        GtkTreeViewColumn *column;
-        char *s;
-
-        section->priv = G_TYPE_INSTANCE_GET_PRIVATE (section, GDU_TYPE_SECTION_LINUX_MD_DRIVE, GduSectionLinuxMdDrivePrivate);
-
-        gtk_box_set_spacing (GTK_BOX (section), 8);
-
-        table = gtk_table_new (4, 2, FALSE);
-        gtk_box_pack_start (GTK_BOX (section), table, FALSE, FALSE, 0);
-
-        row = 0;
-
-        /* name */
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
-        s = g_strconcat ("<b>", _("Array Name:"), "</b>", NULL);
-        gtk_label_set_markup (GTK_LABEL (label), s);
-        g_free (s);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        section->priv->linux_md_name_label = label;
+        GtkWidget *vbox;
+        GtkWidget *vbox2;
+        gchar *s;
+        GduPresentable *p;
+        GduDevice *d;
+        GPtrArray *elements;
+        GduDetailsElement *element;
+        GduButtonElement *button_element;
 
-        row++;
+        p = gdu_section_get_presentable (GDU_SECTION (section));
+        d = gdu_presentable_get_device (p);
 
-        /* home host */
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
-        s = g_strconcat ("<b>", _("Home Host:"), "</b>", NULL);
-        gtk_label_set_markup (GTK_LABEL (label), s);
-        g_free (s);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        section->priv->linux_md_home_host_label = label;
+        gtk_box_set_spacing (GTK_BOX (section), 12);
 
-        row++;
+        /*------------------------------------- */
 
-        /* size */
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
-        s = g_strconcat ("<b>", _("Array Size:"), "</b>", NULL);
-        gtk_label_set_markup (GTK_LABEL (label), s);
-        g_free (s);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        section->priv->linux_md_size_label = label;
-
-        row++;
-
-        /* type (level) */
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
-        s = g_strconcat ("<b>", _("RAID Type:"), "</b>", NULL);
+        s = g_strconcat ("<b>", _("RAID Array"), "</b>", NULL);
         gtk_label_set_markup (GTK_LABEL (label), s);
         g_free (s);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        section->priv->linux_md_type_label = label;
+        gtk_box_pack_start (GTK_BOX (section), label, FALSE, FALSE, 0);
+
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+        gtk_box_pack_start (GTK_BOX (section), align, FALSE, FALSE, 0);
+
+        vbox = gtk_vbox_new (FALSE, 6);
+        gtk_container_add (GTK_CONTAINER (align), vbox);
+
+        elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+        element = gdu_details_element_new (_("Level:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->level_element = element;
+
+        element = gdu_details_element_new (_("Metadata Version:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->metadata_version_element = element;
+
+        element = gdu_details_element_new (_("Name:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->name_element = element;
+
+        element = gdu_details_element_new (_("Partitioning:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->partitioning_element = element;
+
+        element = gdu_details_element_new (_("State:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->state_element = element;
+
+        element = gdu_details_element_new (_("Capacity:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->capacity_element = element;
+
+        element = gdu_details_element_new (_("Action:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->action_element = element;
+
+        element = gdu_details_element_new (_("Active Components:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->active_components_element = element;
+
+        /* Ensure this is in the last row and the first column */
+        element = gdu_details_element_new (_("Components:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+
+        table = gdu_details_table_new (2, elements);
+        g_ptr_array_unref (elements);
+        gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+
+        /* -------------------------------------------------------------------------------- */
+
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 6, 36, 0);
+        gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+        vbox2 = gtk_vbox_new (TRUE, 4);
+        gtk_container_add (GTK_CONTAINER (align), vbox2);
+        section->priv->components_vbox = vbox2;
+
+        /* -------------------------------------------------------------------------------- */
+
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+        gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+        elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+        button_element = gdu_button_element_new ("gdu-raid-array-start",
+                                                 _("St_art RAID Array"),
+                                                 _("Bring up the RAID Array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_md_start_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->md_start_button = button_element;
+
+        button_element = gdu_button_element_new ("gdu-raid-array-stop",
+                                                 _("St_op RAID Array"),
+                                                 _("Tear down the RAID Array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_md_stop_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->md_stop_button = button_element;
+
+        button_element = gdu_button_element_new ("nautilus-gdu",
+                                                 _("Format/Erase RAI_D Array"),
+                                                 _("Erase or partition the array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (gdu_section_drive_on_format_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->format_button = button_element;
+
+        button_element = gdu_button_element_new ("gdu-check-disk",
+                                                 _("Chec_k Array"),
+                                                 _("Check and repair the array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_check_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->check_button = button_element;
+
+        button_element = gdu_button_element_new (GTK_STOCK_EDIT,
+                                                 _("Edit Com_ponents"),
+                                                 _("Create and remove components"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_edit_components_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->edit_components_button = button_element;
+
+        table = gdu_button_table_new (2, elements);
+        g_ptr_array_unref (elements);
+        gtk_container_add (GTK_CONTAINER (align), table);
+
+        /* -------------------------------------------------------------------------------- */
+
+        gtk_widget_show_all (GTK_WIDGET (section));
+
+        if (d != NULL)
+                g_object_unref (d);
+
+        if (G_OBJECT_CLASS (gdu_section_linux_md_drive_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_section_linux_md_drive_parent_class)->constructed (object);
+}
 
-        row++;
+static void
+gdu_section_linux_md_drive_class_init (GduSectionLinuxMdDriveClass *klass)
+{
+        GObjectClass *gobject_class;
+        GduSectionClass *section_class;
 
-        /* components */
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
-        s = g_strconcat ("<b>", _("Components:"), "</b>", NULL);
-        gtk_label_set_markup (GTK_LABEL (label), s);
-        g_free (s);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        section->priv->linux_md_components_label = label;
+        gobject_class = G_OBJECT_CLASS (klass);
+        section_class = GDU_SECTION_CLASS (klass);
 
-        row++;
+        gobject_class->finalize    = gdu_section_linux_md_drive_finalize;
+        gobject_class->constructed = gdu_section_linux_md_drive_constructed;
+        section_class->update      = gdu_section_linux_md_drive_update;
 
-        /* components */
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
-        s = g_strconcat ("<b>", _("State:"), "</b>", NULL);
-        gtk_label_set_markup (GTK_LABEL (label), s);
-        g_free (s);
-        gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
-                          GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
-        section->priv->linux_md_state_label = label;
-
-        row++;
-
-        tree_view = gtk_tree_view_new ();
-        section->priv->linux_md_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, GTK_POLICY_AUTOMATIC);
-        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
-        gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
-        gtk_box_pack_start (GTK_BOX (section), scrolled_window, TRUE, TRUE, 0);
-
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
-        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
-        g_signal_connect (selection, "changed", (GCallback) linux_md_tree_changed, section);
-
-        button_box = gtk_hbutton_box_new ();
-        gtk_button_box_set_layout (GTK_BUTTON_BOX (button_box), GTK_BUTTONBOX_START);
-        gtk_box_set_spacing (GTK_BOX (button_box), 6);
-        gtk_box_set_homogeneous (GTK_BOX (button_box), FALSE);
-        gtk_box_pack_start (GTK_BOX (section), button_box, FALSE, FALSE, 0);
-
-        button = gtk_button_new_with_mnemonic (_("A_ttach"));
-        gtk_button_set_image (GTK_BUTTON (button),
-                              gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON));
-        gtk_container_add (GTK_CONTAINER (button_box), button);
-        section->priv->attach_button = button;
-        g_signal_connect (button, "clicked", G_CALLBACK (on_attach_clicked), section);
-        gtk_widget_set_tooltip_text (button, _("Attaches the stale component to the RAID array. "
-                                               "After attachment, data from the array will be "
-                                               "synchronized on the component."));
-
-        button = gtk_button_new_with_mnemonic (_("_Detach"));
-        gtk_button_set_image (GTK_BUTTON (button),
-                              gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_BUTTON));
-        gtk_container_add (GTK_CONTAINER (button_box), button);
-        section->priv->detach_button = button;
-        g_signal_connect (button, "clicked", G_CALLBACK (on_detach_clicked), section);
-        gtk_widget_set_tooltip_text (button, _("Detaches the running component from the RAID array. Data on "
-                                               "the component will be erased and the component will be ready "
-                                               "for other use."));
-
-        button = gtk_button_new_with_mnemonic (_("_Add..."));
-        gtk_button_set_image (GTK_BUTTON (button),
-                              gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_BUTTON));
-        gtk_container_add (GTK_CONTAINER (button_box), button);
-        section->priv->add_button = button;
-        g_signal_connect (button, "clicked", G_CALLBACK (on_add_clicked), section);
-        gtk_widget_set_tooltip_text (button, _("Adds a new component to the running RAID array. Use this "
-                                               "when replacing a failed component or adding a hot spare."));
-
-        /* Translators: this is a verb, as in 'check for consistency' */
-        button = gtk_button_new_with_mnemonic (_("Chec_k"));
-        gtk_container_add (GTK_CONTAINER (button_box), button);
-        section->priv->add_button = button;
-        g_signal_connect (button, "clicked", G_CALLBACK (on_check_clicked), section);
-        gtk_widget_set_tooltip_text (button, _("Starts checking the RAID array for redundancy"));
-
-        /* Translators: this is a verb, as in 'repair this RAID array' */
-        button = gtk_button_new_with_mnemonic (_("_Repair"));
-        gtk_container_add (GTK_CONTAINER (button_box), button);
-        section->priv->add_button = button;
-        g_signal_connect (button, "clicked", G_CALLBACK (on_repair_clicked), section);
-        gtk_widget_set_tooltip_text (button, _("Starts repairing the RAID array"));
-
-        /* add renderers for tree view */
-        column = gtk_tree_view_column_new ();
-        gtk_tree_view_column_set_title (column, _("RAID Component"));
-        renderer = gtk_cell_renderer_pixbuf_new ();
-        gtk_tree_view_column_pack_start (column, renderer, FALSE);
-        gtk_tree_view_column_set_attributes (column, renderer,
-                                             "pixbuf", MD_LINUX_ICON_COLUMN,
-                                             NULL);
-        renderer = gtk_cell_renderer_text_new ();
-        gtk_tree_view_column_pack_start (column, renderer, TRUE);
-        gtk_tree_view_column_set_attributes (column, renderer,
-                                             "text", MD_LINUX_NAME_COLUMN,
-                                             NULL);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
-
-        column = gtk_tree_view_column_new ();
-        gtk_tree_view_column_set_title (column, _("State"));
-        renderer = gtk_cell_renderer_text_new ();
-        gtk_tree_view_column_pack_start (column, renderer, FALSE);
-        gtk_tree_view_column_set_attributes (column, renderer,
-                                             "markup", MD_LINUX_STATE_STRING_COLUMN,
-                                             NULL);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
-
-        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), TRUE);
+        g_type_class_add_private (klass, sizeof (GduSectionLinuxMdDrivePrivate));
+}
 
+static void
+gdu_section_linux_md_drive_init (GduSectionLinuxMdDrive *section)
+{
+        section->priv = G_TYPE_INSTANCE_GET_PRIVATE (section, GDU_TYPE_SECTION_LINUX_MD_DRIVE, GduSectionLinuxMdDrivePrivate);
 }
 
 GtkWidget *
 gdu_section_linux_md_drive_new (GduShell       *shell,
-                                GduPresentable *presentable)
+                       GduPresentable *presentable)
 {
         return GTK_WIDGET (g_object_new (GDU_TYPE_SECTION_LINUX_MD_DRIVE,
                                          "shell", shell,
diff --git a/src/palimpsest/gdu-section-volumes.c b/src/palimpsest/gdu-section-volumes.c
index d271694..04005fe 100644
--- a/src/palimpsest/gdu-section-volumes.c
+++ b/src/palimpsest/gdu-section-volumes.c
@@ -1277,6 +1277,49 @@ on_fsck_button_clicked (GduButtonElement *button_element,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
+on_usage_element_activated (GduDetailsElement *element,
+                            gpointer           user_data)
+{
+        GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+        GduPresentable *v;
+        GduDevice *d;
+        GduLinuxMdDrive *linux_md_drive;
+        GduPool *pool;
+
+        v = NULL;
+        d = NULL;
+        linux_md_drive = NULL;
+
+        v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+        if (v == NULL)
+                goto out;
+
+        d = gdu_presentable_get_device (v);
+        if (d == NULL)
+                goto out;
+
+        pool = gdu_device_get_pool (d);
+
+        linux_md_drive = gdu_pool_get_linux_md_drive_by_uuid (pool, gdu_device_linux_md_component_get_uuid (d));
+        if (linux_md_drive == NULL)
+                goto out;
+
+        gdu_shell_select_presentable (gdu_section_get_shell (GDU_SECTION (section)), GDU_PRESENTABLE (linux_md_drive));
+
+ out:
+        if (linux_md_drive != NULL)
+                g_object_unref (linux_md_drive);
+        if (pool != NULL)
+                g_object_unref (pool);
+        if (d != NULL)
+                g_object_unref (d);
+        if (v != NULL)
+                g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
 gdu_section_volumes_update (GduSection *_section)
 {
         GduSectionVolumes *section = GDU_SECTION_VOLUMES (_section);
@@ -1358,6 +1401,10 @@ gdu_section_volumes_update (GduSection *_section)
 
         section->priv->usage_element = gdu_details_element_new (_("Usage:"), NULL, NULL);
         g_ptr_array_add (elements, section->priv->usage_element);
+        g_signal_connect (section->priv->usage_element,
+                          "activated",
+                          G_CALLBACK (on_usage_element_activated),
+                          section);
 
         section->priv->device_element = gdu_details_element_new (_("Device:"), NULL, NULL);
         g_ptr_array_add (elements, section->priv->device_element);
@@ -1365,11 +1412,13 @@ gdu_section_volumes_update (GduSection *_section)
         section->priv->partition_type_element = gdu_details_element_new (_("Partition Type:"), NULL, NULL);
         g_ptr_array_add (elements, section->priv->partition_type_element);
 
-        section->priv->partition_label_element = gdu_details_element_new (_("Partition Label:"), NULL, NULL);
-        g_ptr_array_add (elements, section->priv->partition_label_element);
+        if (d != NULL && gdu_device_is_partition (d)) {
+                section->priv->partition_label_element = gdu_details_element_new (_("Partition Label:"), NULL, NULL);
+                g_ptr_array_add (elements, section->priv->partition_label_element);
 
-        section->priv->partition_flags_element = gdu_details_element_new (_("Partition Flags:"), NULL, NULL);
-        g_ptr_array_add (elements, section->priv->partition_flags_element);
+                section->priv->partition_flags_element = gdu_details_element_new (_("Partition Flags:"), NULL, NULL);
+                g_ptr_array_add (elements, section->priv->partition_flags_element);
+        }
 
         section->priv->capacity_element = gdu_details_element_new (_("Capacity:"), NULL, NULL);
         g_ptr_array_add (elements, section->priv->capacity_element);
@@ -1394,8 +1443,10 @@ gdu_section_volumes_update (GduSection *_section)
         /* ---------------------------------------------------------------------------------------------------- */
         /* reset all elements */
 
-        if (section->priv->usage_element != NULL)
+        if (section->priv->usage_element != NULL) {
                 gdu_details_element_set_text (section->priv->usage_element, "â??");
+                gdu_details_element_set_action_text (section->priv->usage_element, NULL);
+        }
         if (section->priv->capacity_element != NULL) {
                 if (v != NULL) {
                         s = gdu_util_get_size_for_display (gdu_presentable_get_size (v), FALSE, TRUE);
@@ -1477,8 +1528,6 @@ gdu_section_volumes_update (GduSection *_section)
                         }
                 } else {
                         gdu_details_element_set_text (section->priv->partition_type_element, "â??");
-                        gdu_details_element_set_text (section->priv->partition_flags_element, "â??");
-                        gdu_details_element_set_text (section->priv->partition_label_element, "â??");
                 }
         }
         if (section->priv->device_element != NULL) {
@@ -1561,6 +1610,11 @@ gdu_section_volumes_update (GduSection *_section)
                         show_luks_forget_passphrase_button = TRUE;
                 show_luks_change_passphrase_button = TRUE;
 
+        } else if (d != NULL && gdu_device_is_linux_md_component (d)) {
+
+                gdu_details_element_set_text (section->priv->usage_element, _("RAID Component"));
+                gdu_details_element_set_action_text (section->priv->usage_element, _("Go to array"));
+
         } else if (g_strcmp0 (id_usage, "") == 0 &&
                    d != NULL && gdu_device_is_partition (d) &&
                    g_strcmp0 (gdu_device_partition_get_scheme (d), "mbr") == 0 &&
@@ -1608,6 +1662,7 @@ gdu_section_volumes_update (GduSection *_section)
         gdu_button_element_set_visible (section->priv->luks_unlock_button, show_luks_unlock_button);
         gdu_button_element_set_visible (section->priv->luks_forget_passphrase_button, show_luks_forget_passphrase_button);
         gdu_button_element_set_visible (section->priv->luks_change_passphrase_button, show_luks_change_passphrase_button);
+
         if (d != NULL)
                 g_object_unref (d);
         if (v != NULL)
@@ -1709,7 +1764,7 @@ gdu_section_volumes_constructed (GObject *object)
 
         button_element = gdu_button_element_new ("nautilus-gdu",
                                                  _("Fo_rmat Volume"),
-                                                 _("Format the volume"));
+                                                 _("Erase or format the volume"));
         g_signal_connect (button_element,
                           "clicked",
                           G_CALLBACK (on_format_button_clicked),
@@ -1719,7 +1774,7 @@ gdu_section_volumes_constructed (GObject *object)
 
         button_element = gdu_button_element_new ("gdu-check-disk",
                                                  _("_Check Filesystem"),
-                                                 _("Check the filesystem for errors"));
+                                                 _("Check and repair the filesystem"));
         g_signal_connect (button_element,
                           "clicked",
                           G_CALLBACK (on_fsck_button_clicked),
@@ -1851,3 +1906,11 @@ gdu_section_volumes_new (GduShell       *shell,
                                          "presentable", presentable,
                                          NULL));
 }
+
+gboolean
+gdu_section_volumes_select_volume (GduSectionVolumes *section,
+                                   GduPresentable    *volume)
+{
+        g_return_val_if_fail (GDU_IS_SECTION_VOLUMES (section), FALSE);
+        return gdu_volume_grid_select (GDU_VOLUME_GRID (section->priv->grid), volume);
+}
diff --git a/src/palimpsest/gdu-section-volumes.h b/src/palimpsest/gdu-section-volumes.h
index d2aa63e..cf299aa 100644
--- a/src/palimpsest/gdu-section-volumes.h
+++ b/src/palimpsest/gdu-section-volumes.h
@@ -51,8 +51,10 @@ struct _GduSectionVolumesClass
         GduSectionClass parent_class;
 };
 
-GType            gdu_section_volumes_get_type (void);
-GtkWidget       *gdu_section_volumes_new      (GduShell       *shell,
-                                               GduPresentable *presentable);
+GType            gdu_section_volumes_get_type      (void);
+GtkWidget       *gdu_section_volumes_new           (GduShell       *shell,
+                                                    GduPresentable *presentable);
+gboolean         gdu_section_volumes_select_volume (GduSectionVolumes *section,
+                                                    GduPresentable    *volume);
 
 #endif /* GDU_SECTION_VOLUMES_H */
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index 7e006a2..4e4bde2 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -80,6 +80,8 @@ struct _GduShellPrivate
 
 static GObjectClass *parent_class = NULL;
 
+static GduSection *get_section_by_type (GduShell *shell, GType section_type);
+
 G_DEFINE_TYPE (GduShell, gdu_shell, G_TYPE_OBJECT);
 
 static void
@@ -138,8 +140,58 @@ gdu_shell_get_selected_presentable (GduShell *shell)
 void
 gdu_shell_select_presentable (GduShell *shell, GduPresentable *presentable)
 {
-        gdu_pool_tree_view_select_presentable (GDU_POOL_TREE_VIEW (shell->priv->tree_view), presentable);
-        gtk_widget_grab_focus (shell->priv->tree_view);
+        gboolean selected;
+
+        if (GDU_IS_DRIVE (presentable)) {
+                gdu_pool_tree_view_select_presentable (GDU_POOL_TREE_VIEW (shell->priv->tree_view), presentable);
+                gtk_widget_grab_focus (shell->priv->tree_view);
+                selected = TRUE;
+        } else if (GDU_IS_VOLUME (presentable)) {
+                GduDevice *device;
+                GduPresentable *p_to_select;
+
+                p_to_select = NULL;
+                device = gdu_presentable_get_device (presentable);
+                if (device != NULL) {
+                        if (gdu_device_is_partition (device)) {
+                                GduDevice *drive_device;
+                                drive_device = gdu_pool_get_by_object_path (shell->priv->pool,
+                                                                            gdu_device_partition_get_slave (device));
+                                if (drive_device != NULL) {
+                                        p_to_select = gdu_pool_get_drive_by_device (shell->priv->pool, drive_device);
+                                        g_object_unref (drive_device);
+                                }
+                        } else {
+                                p_to_select = gdu_pool_get_drive_by_device (shell->priv->pool, device);
+                        }
+                        g_object_unref (device);
+                }
+
+                if (p_to_select != NULL) {
+                        GduSection *volumes_section;
+
+                        gdu_pool_tree_view_select_presentable (GDU_POOL_TREE_VIEW (shell->priv->tree_view),
+                                                               p_to_select);
+                        gtk_widget_grab_focus (shell->priv->tree_view);
+
+                        volumes_section = get_section_by_type (shell, GDU_TYPE_SECTION_VOLUMES);
+                        g_warn_if_fail (volumes_section != NULL);
+                        if (volumes_section != NULL) {
+                                g_warn_if_fail (gdu_section_volumes_select_volume (GDU_SECTION_VOLUMES (volumes_section),
+                                                                                   presentable));
+                        }
+
+                        selected = TRUE;
+                        g_object_unref (p_to_select);
+                }
+        } else {
+        }
+
+        if (!selected) {
+                g_warning ("%s: %s: Unhandled presentable %s",
+                           G_STRLOC, G_STRFUNC,
+                           gdu_presentable_get_id (presentable));
+        }
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -508,12 +560,9 @@ compute_sections_to_show (GduShell *shell)
 
         if (GDU_IS_LINUX_MD_DRIVE (shell->priv->presentable_now_showing)) {
 
-                sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_DRIVE);
+                sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_LINUX_MD_DRIVE);
                 sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_VOLUMES);
 
-                sections_to_show = g_list_append (sections_to_show,
-                                                  (gpointer) GDU_TYPE_SECTION_LINUX_MD_DRIVE);
-
 
         } else if (GDU_IS_DRIVE (shell->priv->presentable_now_showing) && device != NULL) {
 
@@ -839,6 +888,28 @@ gdu_shell_update (GduShell *shell)
                 g_object_unref (device);
 }
 
+static GduSection *
+get_section_by_type (GduShell *shell, GType section_type)
+{
+        GList *children;
+        GList *l;
+        GduSection *ret;
+
+        ret = NULL;
+        children = gtk_container_get_children (GTK_CONTAINER (shell->priv->sections_vbox));
+        for (l = children; l != NULL; l = l->next) {
+                GduSection *section = GDU_SECTION (l->data);
+
+                if (g_type_is_a (G_OBJECT_TYPE (section), section_type)) {
+                        ret = section;
+                        break;
+                }
+        }
+        g_list_free (children);
+
+        return ret;
+}
+
 static void
 presentable_changed (GduPresentable *presentable, gpointer user_data)
 {



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