[gnome-disk-utility/new-ui] Implement the "Create Partition" dialog



commit 6eb9e7baa184eea71c3713e7833207f3147d5ff9
Author: David Zeuthen <davidz redhat com>
Date:   Mon Oct 26 20:59:02 2009 -0400

    Implement the "Create Partition" dialog

 src/gdu-gtk/Makefile.am                   |    2 +
 src/gdu-gtk/gdu-create-partition-dialog.c |  246 +++++++++++++++++++++++++++
 src/gdu-gtk/gdu-create-partition-dialog.h |   69 ++++++++
 src/gdu-gtk/gdu-format-dialog.c           |   57 ++++++-
 src/gdu-gtk/gdu-format-dialog.h           |    2 +
 src/gdu-gtk/gdu-gtk-enums.h               |    2 +
 src/gdu-gtk/gdu-gtk-types.h               |    1 +
 src/gdu-gtk/gdu-gtk.h                     |    1 +
 src/gdu-gtk/gdu-size-widget.c             |   42 +++--
 src/gdu/gdu-drive.c                       |   77 +++++++++
 src/gdu/gdu-drive.h                       |    4 +
 src/palimpsest/gdu-section-volumes.c      |  262 ++++++++++++++++++++++++++++-
 12 files changed, 740 insertions(+), 25 deletions(-)
---
diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index edf227c..2710b75 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -48,6 +48,7 @@ libgdu_gtkinclude_HEADERS =              				\
 	gdu-edit-partition-dialog.h					\
 	gdu-format-dialog.h						\
 	gdu-partition-dialog.h						\
+	gdu-create-partition-dialog.h					\
 	$(NULL)
 
 libgdu_gtk_la_SOURCES =                 	               				\
@@ -73,6 +74,7 @@ libgdu_gtk_la_SOURCES =                 	               				\
 	gdu-edit-partition-dialog.h		gdu-edit-partition-dialog.c		\
 	gdu-format-dialog.h			gdu-format-dialog.c			\
 	gdu-partition-dialog.h			gdu-partition-dialog.c			\
+	gdu-create-partition-dialog.h		gdu-create-partition-dialog.c		\
 	$(NULL)
 
 libgdu_gtk_la_CPPFLAGS = 				\
diff --git a/src/gdu-gtk/gdu-create-partition-dialog.c b/src/gdu-gtk/gdu-create-partition-dialog.c
new file mode 100644
index 0000000..4a6d7b4
--- /dev/null
+++ b/src/gdu-gtk/gdu-create-partition-dialog.c
@@ -0,0 +1,246 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  format-window.c
+ *
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: Tomas Bzatek <tbzatek redhat com>
+ *          David Zeuthen <davidz redhat com>
+ *
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gdu/gdu.h>
+#include <gdu-gtk/gdu-gtk.h>
+
+#include "gdu-format-dialog.h"
+
+struct GduCreatePartitionDialogPrivate
+{
+        guint64 max_size;
+        GtkWidget *size_widget;
+        GduPresentable *drive;
+};
+
+enum
+{
+        PROP_0,
+        PROP_SIZE,
+        PROP_MAX_SIZE,
+        PROP_DRIVE
+};
+
+static void gdu_create_partition_dialog_constructed (GObject *object);
+
+G_DEFINE_TYPE (GduCreatePartitionDialog, gdu_create_partition_dialog, GDU_TYPE_FORMAT_DIALOG)
+
+static void
+gdu_create_partition_dialog_finalize (GObject *object)
+{
+        //GduCreatePartitionDialog *dialog = GDU_CREATE_PARTITION_DIALOG (object);
+
+        if (G_OBJECT_CLASS (gdu_create_partition_dialog_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_create_partition_dialog_parent_class)->finalize (object);
+}
+
+static void
+gdu_create_partition_dialog_get_property (GObject    *object,
+                                          guint       property_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+        GduCreatePartitionDialog *dialog = GDU_CREATE_PARTITION_DIALOG (object);
+
+        switch (property_id) {
+        case PROP_SIZE:
+                g_value_set_uint64 (value, gdu_create_partition_dialog_get_size (dialog));
+                break;
+
+        case PROP_MAX_SIZE:
+                g_value_set_uint64 (value, dialog->priv->max_size);
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_create_partition_dialog_set_property (GObject      *object,
+                                          guint         property_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec)
+{
+        GduCreatePartitionDialog *dialog = GDU_CREATE_PARTITION_DIALOG (object);
+
+        switch (property_id) {
+        case PROP_MAX_SIZE:
+                dialog->priv->max_size = g_value_get_uint64 (value);
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_create_partition_dialog_class_init (GduCreatePartitionDialogClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        g_type_class_add_private (klass, sizeof (GduCreatePartitionDialogPrivate));
+
+        object_class->get_property = gdu_create_partition_dialog_get_property;
+        object_class->set_property = gdu_create_partition_dialog_set_property;
+        object_class->constructed  = gdu_create_partition_dialog_constructed;
+        object_class->finalize     = gdu_create_partition_dialog_finalize;
+
+        g_object_class_install_property (object_class,
+                                         PROP_MAX_SIZE,
+                                         g_param_spec_uint64 ("max-size",
+                                                              _("Maximum Partition Size"),
+                                                              _("The maximum possible partition size"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_SIZE,
+                                         g_param_spec_uint64 ("size",
+                                                              _("Partition Size"),
+                                                              _("The requested partition size"),
+                                                              0,
+                                                              G_MAXUINT64,
+                                                              0,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+}
+
+static void
+gdu_create_partition_dialog_init (GduCreatePartitionDialog *dialog)
+{
+        dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
+                                                    GDU_TYPE_CREATE_PARTITION_DIALOG,
+                                                    GduCreatePartitionDialogPrivate);
+}
+
+GtkWidget *
+gdu_create_partition_dialog_new (GtkWindow            *parent,
+                                 GduPresentable       *presentable,
+                                 guint64               max_size,
+                                 GduFormatDialogFlags  flags)
+{
+        return GTK_WIDGET (g_object_new (GDU_TYPE_CREATE_PARTITION_DIALOG,
+                                         "transient-for", parent,
+                                         "presentable", presentable,
+                                         "max-size", max_size,
+                                         "affirmative-button-mnemonic", _("C_reate"),
+                                         "flags", flags,
+                                         NULL));
+}
+
+GtkWidget *
+gdu_create_partition_dialog_new_for_drive (GtkWindow            *parent,
+                                           GduDevice            *device,
+                                           guint64               max_size,
+                                           GduFormatDialogFlags  flags)
+{
+        return GTK_WIDGET (g_object_new (GDU_TYPE_CREATE_PARTITION_DIALOG,
+                                         "transient-for", parent,
+                                         "drive-device", device,
+                                         "max-size", max_size,
+                                         "affirmative-button-mnemonic", _("C_reate"),
+                                         "flags", flags,
+                                         NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+guint64
+gdu_create_partition_dialog_get_size (GduCreatePartitionDialog *dialog)
+{
+        g_return_val_if_fail (GDU_IS_CREATE_PARTITION_DIALOG (dialog), 0);
+        return gdu_size_widget_get_size (GDU_SIZE_WIDGET (dialog->priv->size_widget));
+}
+
+guint64
+gdu_create_partition_dialog_get_max_size (GduCreatePartitionDialog *dialog)
+{
+        g_return_val_if_fail (GDU_IS_CREATE_PARTITION_DIALOG (dialog), 0);
+        return dialog->priv->max_size;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_create_partition_dialog_constructed (GObject *object)
+{
+        GduCreatePartitionDialog *dialog = GDU_CREATE_PARTITION_DIALOG (object);
+        gchar *s;
+        gchar *s2;
+        GtkWidget *table;
+        GtkWidget *label;
+        GtkWidget *size_widget;
+        guint row;
+
+        table = gdu_format_dialog_get_table (GDU_FORMAT_DIALOG (dialog));
+        g_object_get (table,
+                      "n-rows", &row,
+                      NULL);
+
+        /*  add partition size widget before other widgets in the for GduFormatDialog  */
+        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), _("_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 (0, 0, dialog->priv->max_size);
+        gdu_size_widget_set_size (GDU_SIZE_WIDGET (size_widget), dialog->priv->max_size);
+        gtk_table_attach (GTK_TABLE (table), size_widget, 1, 2, row, row + 1,
+                          GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
+        gtk_label_set_mnemonic_widget (GTK_LABEL (label), size_widget);
+        dialog->priv->size_widget = size_widget;
+        row++;
+
+        /* run constructed() for parent class (GduFormatDialog) */
+        if (G_OBJECT_CLASS (gdu_create_partition_dialog_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_create_partition_dialog_parent_class)->constructed (object);
+
+        /* adjust window title */
+        s2 = gdu_presentable_get_vpd_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
+        /* Translators: The %s is the name of the drive */
+        s = g_strdup_printf (_("Create partition on %s"), s2);
+        gtk_window_set_title (GTK_WINDOW (dialog), s);
+        g_free (s);
+
+
+        g_free (s2);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu-gtk/gdu-create-partition-dialog.h b/src/gdu-gtk/gdu-create-partition-dialog.h
new file mode 100644
index 0000000..fc01dbb
--- /dev/null
+++ b/src/gdu-gtk/gdu-create-partition-dialog.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ *  Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Author: David Zeuthen <davidz redhat com>
+ *
+ */
+
+#ifndef __GDU_CREATE_PARTITION_DIALOG_H
+#define __GDU_CREATE_PARTITION_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_CREATE_PARTITION_DIALOG            gdu_create_partition_dialog_get_type()
+#define GDU_CREATE_PARTITION_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDU_TYPE_CREATE_PARTITION_DIALOG, GduCreatePartitionDialog))
+#define GDU_CREATE_PARTITION_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDU_TYPE_CREATE_PARTITION_DIALOG, GduCreatePartitionDialogClass))
+#define GDU_IS_CREATE_PARTITION_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDU_TYPE_CREATE_PARTITION_DIALOG))
+#define GDU_IS_CREATE_PARTITION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDU_TYPE_CREATE_PARTITION_DIALOG))
+#define GDU_CREATE_PARTITION_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDU_TYPE_CREATE_PARTITION_DIALOG, GduCreatePartitionDialogClass))
+
+typedef struct GduCreatePartitionDialogClass   GduCreatePartitionDialogClass;
+typedef struct GduCreatePartitionDialogPrivate GduCreatePartitionDialogPrivate;
+
+struct GduCreatePartitionDialog
+{
+        GduFormatDialog parent;
+
+        /*< private >*/
+        GduCreatePartitionDialogPrivate *priv;
+};
+
+struct GduCreatePartitionDialogClass
+{
+        GduFormatDialogClass parent_class;
+};
+
+GType       gdu_create_partition_dialog_get_type       (void) G_GNUC_CONST;
+GtkWidget  *gdu_create_partition_dialog_new            (GtkWindow                *parent,
+                                                        GduPresentable           *presentable,
+                                                        guint64                   max_size,
+                                                        GduFormatDialogFlags      flags);
+GtkWidget  *gdu_create_partition_dialog_new_for_drive  (GtkWindow                *parent,
+                                                        GduDevice                *device,
+                                                        guint64                   max_size,
+                                                        GduFormatDialogFlags      flags);
+guint64     gdu_create_partition_dialog_get_size       (GduCreatePartitionDialog *dialog);
+guint64     gdu_create_partition_dialog_get_max_size   (GduCreatePartitionDialog *dialog);
+
+G_END_DECLS
+
+#endif  /* __GDU_CREATE_PARTITION_DIALOG_H */
+
diff --git a/src/gdu-gtk/gdu-format-dialog.c b/src/gdu-gtk/gdu-format-dialog.c
index 07ca3b1..c9ad5ac 100644
--- a/src/gdu-gtk/gdu-format-dialog.c
+++ b/src/gdu-gtk/gdu-format-dialog.c
@@ -34,6 +34,9 @@
 struct GduFormatDialogPrivate
 {
         GduFormatDialogFlags flags;
+        gchar *affirmative_button_mnemonic;
+
+        GtkWidget *table;
 
         GtkWidget *fs_label_entry;
         GtkWidget *fs_type_combo_box;
@@ -58,6 +61,7 @@ enum
         PROP_FS_LABEL,
         PROP_ENCRYPT,
         PROP_TAKE_OWNERSHIP,
+        PROP_AFFIRMATIVE_BUTTON_MNEMONIC,
 };
 
 static void gdu_format_dialog_constructed (GObject *object);
@@ -71,6 +75,7 @@ gdu_format_dialog_finalize (GObject *object)
 
         g_free (dialog->priv->fs_type);
         g_strfreev (dialog->priv->fs_options);
+        g_free (dialog->priv->affirmative_button_mnemonic);
 
         if (dialog->priv->removed_signal_handler_id > 0) {
                 g_signal_handler_disconnect (gdu_dialog_get_presentable (GDU_DIALOG (dialog)),
@@ -133,6 +138,10 @@ gdu_format_dialog_set_property (GObject      *object,
                 dialog->priv->flags = g_value_get_flags (value);
                 break;
 
+        case PROP_AFFIRMATIVE_BUTTON_MNEMONIC:
+                dialog->priv->affirmative_button_mnemonic = g_value_dup_string (value);
+                break;
+
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
                 break;
@@ -219,12 +228,29 @@ gdu_format_dialog_class_init (GduFormatDialogClass *klass)
                                                                G_PARAM_STATIC_NAME |
                                                                G_PARAM_STATIC_NICK |
                                                                G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
+                                         PROP_AFFIRMATIVE_BUTTON_MNEMONIC,
+                                         g_param_spec_string ("affirmative-button-mnemonic",
+                                                              _("Affirmative Button Mnemonic"),
+                                                              _("The mnemonic label for the affirmative button"),
+                                                              /* Translators: Format is used as a verb here */
+                                                              _("_Format"),
+                                                              G_PARAM_WRITABLE |
+                                                              G_PARAM_CONSTRUCT_ONLY |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
 }
 
 static void
 gdu_format_dialog_init (GduFormatDialog *dialog)
 {
-        dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog, GDU_TYPE_FORMAT_DIALOG, GduFormatDialogPrivate);
+        dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
+                                                    GDU_TYPE_FORMAT_DIALOG,
+                                                    GduFormatDialogPrivate);
+
+        dialog->priv->table = gtk_table_new (2, 2, FALSE);
 }
 
 GtkWidget *
@@ -300,6 +326,14 @@ gdu_format_dialog_get_take_ownership  (GduFormatDialog *dialog)
         return dialog->priv->take_ownership;
 }
 
+GtkWidget *
+gdu_format_dialog_get_table (GduFormatDialog *dialog)
+{
+        g_return_val_if_fail (GDU_IS_FORMAT_DIALOG (dialog), NULL);
+        return dialog->priv->table;
+}
+
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
@@ -369,7 +403,8 @@ update (GduFormatDialog *dialog)
         }
 
         if (! (dialog->priv->flags & GDU_FORMAT_DIALOG_FLAGS_SIMPLE)) {
-                if (g_strcmp0 (dialog->priv->fs_type, "empty") == 0) {
+                if (g_strcmp0 (dialog->priv->fs_type, "empty") == 0 ||
+                    g_strcmp0 (dialog->priv->fs_type, "msdos_extended_partition") == 0) {
                         gtk_widget_hide (dialog->priv->encrypt_check_button);
                         dialog->priv->encrypt = FALSE;
                 } else {
@@ -468,8 +503,7 @@ gdu_format_dialog_constructed (GObject *object)
 
         gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
         gtk_dialog_add_button (GTK_DIALOG (dialog),
-                               /* Translators: Format is used as a verb here */
-                               _("_Format"),
+                               dialog->priv->affirmative_button_mnemonic,
                                GTK_RESPONSE_OK);
 
         if (dialog->priv->flags & GDU_FORMAT_DIALOG_FLAGS_DISK_UTILITY_BUTTON) {
@@ -501,9 +535,10 @@ gdu_format_dialog_constructed (GObject *object)
         vbox2 = gtk_vbox_new (FALSE, 6);
         gtk_container_add (GTK_CONTAINER (align), vbox2);
 
-        row = 0;
-
-        table = gtk_table_new (2, 2, FALSE);
+        table = dialog->priv->table;
+        g_object_get (table,
+                      "n-rows", &row,
+                      NULL);
         gtk_table_set_col_spacings (GTK_TABLE (table), 12);
         gtk_table_set_row_spacings (GTK_TABLE (table), 6);
         gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
@@ -532,7 +567,13 @@ gdu_format_dialog_constructed (GObject *object)
                 dialog->priv->encrypt = FALSE;
                 dialog->priv->take_ownership = FALSE;
         } else {
-                combo_box = gdu_util_fstype_combo_box_create (gdu_dialog_get_pool (GDU_DIALOG (dialog)), NULL);
+                const gchar *include_extended_partitions_for_scheme;
+
+                include_extended_partitions_for_scheme = NULL;
+                if (dialog->priv->flags & GDU_FORMAT_DIALOG_FLAGS_ALLOW_MSDOS_EXTENDED)
+                        include_extended_partitions_for_scheme = "mbr";
+                combo_box = gdu_util_fstype_combo_box_create (gdu_dialog_get_pool (GDU_DIALOG (dialog)),
+                                                              include_extended_partitions_for_scheme);
                 gdu_util_fstype_combo_box_select (combo_box, "ext4");
                 dialog->priv->fs_type = g_strdup ("ext4");
                 dialog->priv->fs_options = NULL;
diff --git a/src/gdu-gtk/gdu-format-dialog.h b/src/gdu-gtk/gdu-format-dialog.h
index 67c3ee2..29f4b9c 100644
--- a/src/gdu-gtk/gdu-format-dialog.h
+++ b/src/gdu-gtk/gdu-format-dialog.h
@@ -70,6 +70,8 @@ gchar     **gdu_format_dialog_get_fs_options     (GduFormatDialog *dialog);
 gboolean    gdu_format_dialog_get_encrypt        (GduFormatDialog *dialog);
 gboolean    gdu_format_dialog_get_take_ownership (GduFormatDialog *dialog);
 
+GtkWidget  *gdu_format_dialog_get_table          (GduFormatDialog *dialog);
+
 G_END_DECLS
 
 #endif  /* __GDU_FORMAT_DIALOG_H */
diff --git a/src/gdu-gtk/gdu-gtk-enums.h b/src/gdu-gtk/gdu-gtk-enums.h
index e5968d0..d062e1b 100644
--- a/src/gdu-gtk/gdu-gtk-enums.h
+++ b/src/gdu-gtk/gdu-gtk-enums.h
@@ -79,6 +79,7 @@ typedef enum {
  * @GDU_FORMAT_DIALOG_FLAGS_NONE: No flags set.
  * @GDU_FORMAT_DIALOG_FLAGS_SIMPLE: Show a simple form of the dialog.
  * @GDU_FORMAT_DIALOG_FLAGS_DISK_UTILITY_BUTTON: Show a "Disk Utility" button.
+ * @GDU_FORMAT_DIALOG_FLAGS_ALLOW_MSDOS_EXTENDED: Allow selection MS-DOS extended partition instead of a file system.
  *
  * Flags used when creating a #GduFormatDialog.
  */
@@ -86,6 +87,7 @@ typedef enum {
         GDU_FORMAT_DIALOG_FLAGS_NONE = 0,
         GDU_FORMAT_DIALOG_FLAGS_SIMPLE = (1<<0),
         GDU_FORMAT_DIALOG_FLAGS_DISK_UTILITY_BUTTON = (1<<1),
+        GDU_FORMAT_DIALOG_FLAGS_ALLOW_MSDOS_EXTENDED = (1<<2)
 } GduFormatDialogFlags;
 
 #endif /* GDU_GTK_ENUMS_H */
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index 200616f..fa183d0 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -55,6 +55,7 @@ typedef struct GduDialog                   GduDialog;
 typedef struct GduEditPartitionDialog      GduEditPartitionDialog;
 typedef struct GduFormatDialog             GduFormatDialog;
 typedef struct GduPartitionDialog          GduPartitionDialog;
+typedef struct GduCreatePartitionDialog    GduCreatePartitionDialog;
 
 
 G_END_DECLS
diff --git a/src/gdu-gtk/gdu-gtk.h b/src/gdu-gtk/gdu-gtk.h
index bc5945e..5c40c09 100644
--- a/src/gdu-gtk/gdu-gtk.h
+++ b/src/gdu-gtk/gdu-gtk.h
@@ -47,6 +47,7 @@
 #include <gdu-gtk/gdu-edit-partition-dialog.h>
 #include <gdu-gtk/gdu-format-dialog.h>
 #include <gdu-gtk/gdu-partition-dialog.h>
+#include <gdu-gtk/gdu-create-partition-dialog.h>
 #undef __GDU_GTK_INSIDE_GDU_GTK_H
 
 G_BEGIN_DECLS
diff --git a/src/gdu-gtk/gdu-size-widget.c b/src/gdu-gtk/gdu-size-widget.c
index 20bced3..3f66aba 100644
--- a/src/gdu-gtk/gdu-size-widget.c
+++ b/src/gdu-gtk/gdu-size-widget.c
@@ -150,19 +150,6 @@ on_hscale_value_changed (GtkRange  *range,
         }
 }
 
-static void
-gdu_size_widget_init (GduSizeWidget *widget)
-{
-        widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (widget,
-                                                    GDU_TYPE_SIZE_WIDGET,
-                                                    GduSizeWidgetPrivate);
-
-        widget->priv->hscale = gtk_hscale_new_with_range (0,
-                                                          10,
-                                                          1);
-        gtk_scale_set_draw_value (GTK_SCALE (widget->priv->hscale), TRUE);
-}
-
 static gboolean
 on_query_tooltip (GtkWidget  *w,
                   gint        x,
@@ -225,9 +212,34 @@ gdu_size_widget_constructed (GObject *object)
 }
 
 static void
+gdu_size_widget_init (GduSizeWidget *widget)
+{
+        widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (widget,
+                                                    GDU_TYPE_SIZE_WIDGET,
+                                                    GduSizeWidgetPrivate);
+
+        widget->priv->hscale = gtk_hscale_new_with_range (0,
+                                                          10,
+                                                          1);
+        gtk_scale_set_draw_value (GTK_SCALE (widget->priv->hscale), TRUE);
+}
+
+static gboolean
+gdu_size_widget_mnemonic_activate (GtkWidget *_widget,
+                                   gboolean   group_cycling)
+{
+        GduSizeWidget *widget = GDU_SIZE_WIDGET (_widget);
+        return gtk_widget_mnemonic_activate (widget->priv->hscale, group_cycling);
+}
+
+static void
 gdu_size_widget_class_init (GduSizeWidgetClass *klass)
 {
-        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+        GObjectClass *gobject_class;
+        GtkWidgetClass *widget_class;
+
+        gobject_class = G_OBJECT_CLASS (klass);
+        widget_class = GTK_WIDGET_CLASS (klass);
 
         g_type_class_add_private (klass, sizeof (GduSizeWidgetPrivate));
 
@@ -236,6 +248,8 @@ gdu_size_widget_class_init (GduSizeWidgetClass *klass)
         gobject_class->constructed         = gdu_size_widget_constructed;
         gobject_class->finalize            = gdu_size_widget_finalize;
 
+        widget_class->mnemonic_activate    = gdu_size_widget_mnemonic_activate;
+
         g_object_class_install_property (gobject_class,
                                          PROP_SIZE,
                                          g_param_spec_uint64 ("size",
diff --git a/src/gdu/gdu-drive.c b/src/gdu/gdu-drive.c
index 05492a7..e9e40a1 100644
--- a/src/gdu/gdu-drive.c
+++ b/src/gdu/gdu-drive.c
@@ -239,6 +239,83 @@ gdu_drive_has_unallocated_space (GduDrive        *drive,
                                              out_presentable);
 }
 
+/**
+ * gdu_drive_count_mbr_partitions:
+ * @drive: A #GduDrive.
+ * @out_num_primary_partitions: Return location for number of primary partitions.
+ * @out_has_extended_partition: Return location for number of extended partitions.
+ *
+ * Counts the number of primary partitions and figures out if there's an extended partition.
+ *
+ * Returns: %TRUE if @out_num_logical_partitions and @out_has_extended_partition is set, %FALSE otherwise.
+ */
+gboolean
+gdu_drive_count_mbr_partitions (GduDrive  *drive,
+                                guint     *out_num_primary_partitions,
+                                gboolean  *out_has_extended_partition)
+{
+        guint num_primary_partitions;
+        gboolean has_extended_partition;
+        gboolean ret;
+        GduDevice *device;
+        GduPool *pool;
+        GList *enclosed_presentables;
+        GList *l;
+
+        ret = FALSE;
+        num_primary_partitions = 0;
+        has_extended_partition = FALSE;
+        pool = NULL;
+        device = NULL;
+
+        device = gdu_presentable_get_device (GDU_PRESENTABLE (drive));
+        if (device == NULL)
+                goto out;
+
+        pool = gdu_presentable_get_pool (GDU_PRESENTABLE (drive));
+
+        if (!gdu_device_is_partition_table (device) ||
+            g_strcmp0 (gdu_device_partition_table_get_scheme (device), "mbr") != 0) {
+                goto out;
+        }
+
+        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 (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) {
+                                has_extended_partition = TRUE;
+                        }
+                        num_primary_partitions++;
+                        g_object_unref (ep_device);
+                }
+        }
+        g_list_foreach (enclosed_presentables, (GFunc) g_object_unref, NULL);
+        g_list_free (enclosed_presentables);
+
+        ret = TRUE;
+
+ out:
+        if (device != NULL)
+                g_object_unref (device);
+        if (pool != NULL)
+                g_object_unref (pool);
+
+        if (out_num_primary_partitions != NULL)
+                *out_num_primary_partitions = num_primary_partitions;
+        if (out_has_extended_partition != NULL)
+                *out_has_extended_partition = has_extended_partition;
+        return ret;
+}
+
+
 static gboolean
 gdu_drive_has_unallocated_space_real (GduDrive        *drive,
                                       gboolean        *out_whole_disk_is_unitialized,
diff --git a/src/gdu/gdu-drive.h b/src/gdu/gdu-drive.h
index 0e5a6fe..00aad86 100644
--- a/src/gdu/gdu-drive.h
+++ b/src/gdu/gdu-drive.h
@@ -92,6 +92,10 @@ gboolean    gdu_drive_has_unallocated_space (GduDrive        *drive,
                                              guint64         *out_largest_segment,
                                              GduPresentable **out_presentable);
 
+gboolean    gdu_drive_count_mbr_partitions  (GduDrive        *drive,
+                                             guint           *out_num_primary_partitions,
+                                             gboolean        *out_has_extended_partition);
+
 G_END_DECLS
 
 #endif /* __GDU_DRIVE_H */
diff --git a/src/palimpsest/gdu-section-volumes.c b/src/palimpsest/gdu-section-volumes.c
index 30cb196..597bfb9 100644
--- a/src/palimpsest/gdu-section-volumes.c
+++ b/src/palimpsest/gdu-section-volumes.c
@@ -837,6 +837,263 @@ on_luks_change_passphrase_button_clicked (GduButtonElement *button_element,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static gboolean
+can_create_partition (GduSectionVolumes *section,
+                      GduVolumeHole     *hole,
+                      gboolean          *out_can_create_extended)
+{
+        GduPresentable *drive;
+        GduDevice *drive_device;
+        gboolean can_create;
+        gboolean can_create_extended;
+        guint num_primary;
+        gboolean has_extended;
+        const gchar *part_scheme;
+        GduPresentable *enclosing_presentable_for_hole;
+
+        can_create = FALSE;
+        can_create_extended = FALSE;
+
+        enclosing_presentable_for_hole = NULL;
+        drive_device = NULL;
+
+        drive = gdu_section_get_presentable (GDU_SECTION (section));
+        drive_device = gdu_presentable_get_device (drive);
+        if (drive_device == NULL)
+                goto out;
+
+        part_scheme = gdu_device_partition_table_get_scheme (drive_device);
+
+        if (g_strcmp0 (part_scheme, "mbr") != 0) {
+                can_create = TRUE;
+                goto out;
+        }
+
+        enclosing_presentable_for_hole = gdu_presentable_get_enclosing_presentable (GDU_PRESENTABLE (hole));
+        if (GDU_IS_DRIVE (enclosing_presentable_for_hole)) {
+                /* hole is in primary partition space */
+                if (gdu_drive_count_mbr_partitions (GDU_DRIVE (drive), &num_primary, &has_extended)) {
+                        if (num_primary < 4) {
+                                can_create = TRUE;
+                                if (!has_extended)
+                                        can_create_extended = TRUE;
+                        }
+                }
+        } else {
+                /* hole is in an extended partition */
+                can_create = TRUE;
+        }
+
+ out:
+        if (enclosing_presentable_for_hole != NULL)
+                g_object_unref (enclosing_presentable_for_hole);
+
+        if (drive_device != NULL)
+                g_object_unref (drive_device);
+
+        if (out_can_create_extended)
+                *out_can_create_extended = can_create_extended;
+
+        return can_create;
+}
+
+
+typedef struct {
+        GduShell *shell;
+        GduPresentable *presentable;
+        char *encrypt_passphrase;
+        gboolean save_in_keyring;
+        gboolean save_in_keyring_session;
+} CreatePartitionData;
+
+static void
+create_partition_data_free (CreatePartitionData *data)
+{
+        if (data->shell != NULL)
+                g_object_unref (data->shell);
+        if (data->presentable != NULL)
+                g_object_unref (data->presentable);
+        if (data->encrypt_passphrase != NULL) {
+                memset (data->encrypt_passphrase, '\0', strlen (data->encrypt_passphrase));
+                g_free (data->encrypt_passphrase);
+        }
+        g_free (data);
+}
+
+static void
+partition_create_op_callback (GduDevice  *device,
+                              gchar      *created_device_object_path,
+                              GError     *error,
+                              gpointer    user_data)
+{
+        CreatePartitionData *data = user_data;
+
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (data->shell)),
+                                                         device,
+                                                         _("Error creating partition"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
+        } else {
+                g_debug ("Created %s", created_device_object_path);
+
+                if (data->encrypt_passphrase != NULL) {
+                        GduDevice *cleartext_device;
+                        GduPool *pool;
+
+                        pool = gdu_device_get_pool (device);
+                        cleartext_device = gdu_pool_get_by_object_path (pool, created_device_object_path);
+                        if (cleartext_device != NULL) {
+                                const gchar *cryptotext_device_object_path;
+
+                                cryptotext_device_object_path = gdu_device_luks_cleartext_get_slave (cleartext_device);
+                                if (cryptotext_device_object_path != NULL) {
+                                        GduDevice *cryptotext_device;
+
+                                        cryptotext_device = gdu_pool_get_by_object_path (pool,
+                                                                                         cryptotext_device_object_path);
+                                        if (cryptotext_device != NULL) {
+                                                /* now set the passphrase if requested */
+                                                if (data->save_in_keyring || data->save_in_keyring_session) {
+                                                        gdu_util_save_secret (cryptotext_device,
+                                                                              data->encrypt_passphrase,
+                                                                              data->save_in_keyring_session);
+                                                }
+                                                g_object_unref (cryptotext_device);
+                                        }
+                                }
+                                g_object_unref (cleartext_device);
+                        }
+                }
+
+                g_free (created_device_object_path);
+        }
+
+        if (data != NULL)
+                create_partition_data_free (data);
+}
+
+static void
+on_partition_create_button_clicked (GduButtonElement *button_element,
+                                    gpointer          user_data)
+{
+        GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+        GduPresentable *v;
+        GduPresentable *drive;
+        GduDevice *drive_device;
+        GtkWindow *toplevel;
+        GtkWidget *dialog;
+        gint response;
+        GduFormatDialogFlags flags;
+        const gchar *part_scheme;
+        gboolean can_create_extended;
+
+        v = NULL;
+        drive_device = NULL;
+        dialog = NULL;
+
+        v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+        if (v == NULL || !GDU_IS_VOLUME_HOLE (v))
+                goto out;
+
+        drive = gdu_section_get_presentable (GDU_SECTION (section));
+        drive_device = gdu_presentable_get_device (drive);
+        if (drive_device == NULL)
+                goto out;
+
+        part_scheme = gdu_device_partition_table_get_scheme (drive_device);
+
+        flags = GDU_FORMAT_DIALOG_FLAGS_NONE;
+        if (!can_create_partition (section, GDU_VOLUME_HOLE (v), &can_create_extended))
+                goto out;
+        if (can_create_extended)
+                flags |= GDU_FORMAT_DIALOG_FLAGS_ALLOW_MSDOS_EXTENDED;
+
+        toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
+        dialog = gdu_create_partition_dialog_new_for_drive (toplevel,
+                                                            drive_device,
+                                                            gdu_presentable_get_size (v),
+                                                            flags);
+        gtk_widget_show_all (dialog);
+        response = gtk_dialog_run (GTK_DIALOG (dialog));
+        gtk_widget_hide (dialog);
+        if (response == GTK_RESPONSE_OK) {
+                CreatePartitionData *data;
+                gchar *fs_type;
+                gchar *fs_label;
+                gboolean fs_take_ownership;
+                guint64 offset;
+                guint64 size;
+                gchar *part_type;
+
+                data = g_new0 (CreatePartitionData, 1);
+                data->shell = g_object_ref (gdu_section_get_shell (GDU_SECTION (section)));
+                data->presentable = g_object_ref (v);
+
+                if (gdu_format_dialog_get_encrypt (GDU_FORMAT_DIALOG (dialog))) {
+                        data->encrypt_passphrase = gdu_util_dialog_ask_for_new_secret (GTK_WIDGET (toplevel),
+                                                                                       &data->save_in_keyring,
+                                                                                       &data->save_in_keyring_session);
+                        if (data->encrypt_passphrase == NULL) {
+                                create_partition_data_free (data);
+                                goto out;
+                        }
+                }
+
+                fs_type = gdu_format_dialog_get_fs_type (GDU_FORMAT_DIALOG (dialog));
+                fs_label = gdu_format_dialog_get_fs_label (GDU_FORMAT_DIALOG (dialog));
+                fs_take_ownership = gdu_format_dialog_get_take_ownership (GDU_FORMAT_DIALOG (dialog));
+
+                offset = gdu_presentable_get_offset (v);
+                size = gdu_create_partition_dialog_get_size (GDU_CREATE_PARTITION_DIALOG (dialog));
+
+                if (strcmp (fs_type, "msdos_extended_partition") == 0) {
+                        part_type = g_strdup ("0x05");
+                        g_free (fs_type);
+                        g_free (fs_label);
+                        fs_type = g_strdup ("");
+                        fs_label = g_strdup ("");
+                        fs_take_ownership = FALSE;
+                } else {
+                        part_type = gdu_util_get_default_part_type_for_scheme_and_fstype (part_scheme,
+                                                                                          fs_type,
+                                                                                          size);
+                }
+
+                gdu_device_op_partition_create (drive_device,
+                                                offset,
+                                                size,
+                                                part_type,
+                                                "",   /* empty partition label for now */
+                                                NULL, /* no flags for the partition */
+                                                fs_type,
+                                                fs_label,
+                                                data->encrypt_passphrase,
+                                                fs_take_ownership,
+                                                partition_create_op_callback,
+                                                data);
+
+                g_free (fs_type);
+                g_free (fs_label);
+                g_free (part_type);
+        }
+ out:
+        if (dialog != NULL)
+                gtk_widget_destroy (dialog);
+
+        if (drive_device != NULL)
+                g_object_unref (drive_device);
+        if (v != NULL)
+                g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 gdu_section_volumes_update (GduSection *_section)
 {
@@ -1111,7 +1368,8 @@ gdu_section_volumes_update (GduSection *_section)
                                               gdu_device_get_device_file (drive_device));
                 g_object_unref (drive_device);
 
-                show_partition_create_button = TRUE;
+                if (can_create_partition (section, GDU_VOLUME_HOLE (v), NULL))
+                        show_partition_create_button = TRUE;
                 show_format_button = FALSE;
         }
 
@@ -1270,12 +1528,10 @@ gdu_section_volumes_constructed (GObject *object)
         button_element = gdu_button_element_new (GTK_STOCK_ADD,
                                                  _("_Create Partition"),
                                                  _("Create a new partition"));
-#if 0
         g_signal_connect (button_element,
                           "clicked",
                           G_CALLBACK (on_partition_create_button_clicked),
                           section);
-#endif
         g_ptr_array_add (button_elements, button_element);
         section->priv->partition_create_button = button_element;
 



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