[gnome-disk-utility/new-ui] Implement Linux MD RAID handling for the new-ui branch
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility/new-ui] Implement Linux MD RAID handling for the new-ui branch
- Date: Sat, 31 Oct 2009 19:49:18 +0000 (UTC)
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), °raded);
- 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, °raded)) {
+ 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), °raded);
- 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]