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