[gnome-disk-utility] Add dialog for erasing multiple disks at the same time



commit 63635e3e2a62e62cbeda29bbc04b819efe0f2fa7
Author: David Zeuthen <zeuthen gmail com>
Date:   Fri Oct 12 17:49:35 2012 -0400

    Add dialog for erasing multiple disks at the same time
    
    Signed-off-by: David Zeuthen <zeuthen gmail com>

 data/ui/Makefile.am                     |    1 +
 data/ui/erase-multiple-disks-dialog.ui  |  109 +++++++++++
 po/POTFILES.in                          |    2 +
 src/disks/Makefile.am                   |    1 +
 src/disks/gduerasemultipledisksdialog.c |  322 +++++++++++++++++++++++++++++++
 src/disks/gduerasemultipledisksdialog.h |   23 +++
 src/disks/gduwindow.c                   |   31 +--
 7 files changed, 469 insertions(+), 20 deletions(-)
---
diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am
index 7aa2db8..4b9118c 100644
--- a/data/ui/Makefile.am
+++ b/data/ui/Makefile.am
@@ -27,6 +27,7 @@ ui_DATA = 				\
 	md-raid-disks-dialog.ui		\
 	create-raid-array-dialog.ui	\
 	select-disk-dialog.ui		\
+	erase-multiple-disks-dialog.ui	\
 	$(NULL)
 
 EXTRA_DIST = 				\
diff --git a/data/ui/erase-multiple-disks-dialog.ui b/data/ui/erase-multiple-disks-dialog.ui
new file mode 100644
index 0000000..19038da
--- /dev/null
+++ b/data/ui/erase-multiple-disks-dialog.ui
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="erase-multiple-disks-dialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Erase Multiple Disks</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label" translatable="yes">_Erase...</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="row_spacing">10</property>
+            <property name="column_spacing">10</property>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">Erase _Type</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">erase-combobox</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkComboBox" id="erase-combobox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="id_column">0</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button1</action-widget>
+      <action-widget response="-5">button2</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9fc6022..94c084d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,6 +19,7 @@ data/org.gnome.Disks.gschema.xml.in.in
 [type: gettext/glade]data/ui/edit-fstab-dialog.ui
 [type: gettext/glade]data/ui/edit-gpt-partition-dialog.ui
 [type: gettext/glade]data/ui/edit-partition-dialog.ui
+[type: gettext/glade]data/ui/erase-multiple-disks-dialog.ui
 [type: gettext/glade]data/ui/filesystem-create.ui
 [type: gettext/glade]data/ui/format-disk-dialog.ui
 [type: gettext/glade]data/ui/format-volume-dialog.ui
@@ -40,6 +41,7 @@ src/disks/gducrypttabdialog.c
 src/disks/gdudevicetreemodel.c
 src/disks/gdudisksettingsdialog.c
 src/disks/gduestimator.c
+src/disks/gduerasemultipledisksdialog.c
 src/disks/gdufilesystemdialog.c
 src/disks/gduformatdiskdialog.c
 src/disks/gduformatvolumedialog.c
diff --git a/src/disks/Makefile.am b/src/disks/Makefile.am
index fbffb2d..54854ba 100644
--- a/src/disks/Makefile.am
+++ b/src/disks/Makefile.am
@@ -50,6 +50,7 @@ gnome_disks_SOURCES = 							\
 	gdumdraiddisksdialog.h		gdumdraiddisksdialog.c		\
 	gducreateraidarraydialog.h	gducreateraidarraydialog.c	\
 	gduselectdiskdialog.h		gduselectdiskdialog.c		\
+	gduerasemultipledisksdialog.h	gduerasemultipledisksdialog.c	\
 	$(enum_built_sources)						\
 	$(NULL)
 
diff --git a/src/disks/gduerasemultipledisksdialog.c b/src/disks/gduerasemultipledisksdialog.c
new file mode 100644
index 0000000..d427852
--- /dev/null
+++ b/src/disks/gduerasemultipledisksdialog.c
@@ -0,0 +1,322 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2012 Red Hat, Inc.
+ *
+ * Licensed under GPL version 2 or later.
+ *
+ * Author: David Zeuthen <zeuthen gmail com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gduapplication.h"
+#include "gduwindow.h"
+#include "gduerasemultipledisksdialog.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+enum
+{
+  MODEL_COLUMN_ID,
+  MODEL_COLUMN_MARKUP,
+  MODEL_COLUMN_SEPARATOR,
+  MODEL_COLUMN_SENSITIVE,
+  MODEL_N_COLUMNS,
+};
+
+typedef struct
+{
+  volatile gint ref_count;
+
+  GduWindow *window;
+  GList *blocks;
+
+  GtkBuilder *builder;
+  GtkWidget *dialog;
+  GtkWidget *erase_combobox;
+} DialogData;
+
+
+static DialogData *
+dialog_data_ref (DialogData *data)
+{
+  g_atomic_int_inc (&data->ref_count);
+  return data;
+}
+
+static void
+dialog_data_unref (DialogData *data)
+{
+  if (g_atomic_int_dec_and_test (&data->ref_count))
+    {
+      g_object_unref (data->window);
+      g_list_free_full (data->blocks, g_object_unref);
+      if (data->dialog != NULL)
+        {
+          gtk_widget_hide (data->dialog);
+          gtk_widget_destroy (data->dialog);
+        }
+      if (data->builder != NULL)
+        g_object_unref (data->builder);
+      g_free (data);
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update (DialogData *data)
+{
+}
+
+static void
+on_property_changed (GObject     *object,
+                     GParamSpec  *pspec,
+                     gpointer     user_data)
+{
+  DialogData *data = user_data;
+  update (data);
+}
+
+static gboolean
+separator_func (GtkTreeModel *model,
+                GtkTreeIter *iter,
+                gpointer data)
+{
+  gboolean is_separator;
+  gtk_tree_model_get (model, iter,
+                      MODEL_COLUMN_SEPARATOR, &is_separator,
+                      -1);
+  return is_separator;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+populate (DialogData *data)
+{
+  GtkListStore *model;
+  GtkCellRenderer *renderer;
+  gchar *s;
+
+  model = gtk_list_store_new (MODEL_N_COLUMNS,
+                              G_TYPE_STRING,
+                              G_TYPE_STRING,
+                              G_TYPE_BOOLEAN,
+                              G_TYPE_BOOLEAN);
+  gtk_combo_box_set_model (GTK_COMBO_BOX (data->erase_combobox), GTK_TREE_MODEL (model));
+  g_object_unref (model);
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (data->erase_combobox), renderer, FALSE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (data->erase_combobox), renderer,
+                                  "markup", MODEL_COLUMN_MARKUP,
+                                  "sensitive", MODEL_COLUMN_SENSITIVE,
+                                  NULL);
+
+  gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (data->erase_combobox),
+                                        separator_func,
+                                        data,
+                                        NULL); /* GDestroyNotify */
+
+  /* Quick */
+  s = g_strdup_printf ("%s <span size=\"small\">(%s)</span>",
+                       _("Don't overwrite existing data"),
+                       _("Quick"));
+  gtk_list_store_insert_with_values (model, NULL /* out_iter */, G_MAXINT, /* position */
+                                     MODEL_COLUMN_ID, "",
+                                     MODEL_COLUMN_MARKUP, s,
+                                     MODEL_COLUMN_SENSITIVE, TRUE,
+                                     -1);
+  g_free (s);
+
+  /* Full */
+  s = g_strdup_printf ("%s <span size=\"small\">(%s)</span>",
+                       _("Overwrite existing data with zeroes"),
+                       _("Slow"));
+  gtk_list_store_insert_with_values (model, NULL /* out_iter */, G_MAXINT, /* position */
+                                     MODEL_COLUMN_ID, "zero",
+                                     MODEL_COLUMN_MARKUP, s,
+                                     MODEL_COLUMN_SENSITIVE, TRUE,
+                                     -1);
+  g_free (s);
+
+  /* TODO: include 7-pass and 35-pass (DoD 5220-22 M) */
+
+  s = g_strdup_printf ("%s <span size=\"small\">(%s)</span>",
+                       _("ATA Secure Erase / Enhanced Secure Erase"),
+                       _("If Available, Slow"));
+  gtk_list_store_insert_with_values (model, NULL /* out_iter */, G_MAXINT, /* position */
+                                     MODEL_COLUMN_ID, "secure-erase",
+                                     MODEL_COLUMN_MARKUP, s,
+                                     MODEL_COLUMN_SENSITIVE, TRUE,
+                                     -1);
+  g_free (s);
+
+
+  gtk_combo_box_set_active_id (GTK_COMBO_BOX (data->erase_combobox), "");
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+format_cb (GObject      *source_object,
+           GAsyncResult *res,
+           gpointer      user_data)
+{
+  DialogData *data = user_data;
+  UDisksBlock *block = UDISKS_BLOCK (source_object);
+  GError *error;
+
+  error = NULL;
+  if (!udisks_block_call_format_finish (block,
+                                        res,
+                                        &error))
+    {
+      gchar *s = g_strdup_printf (_("Error erasing device %s"), udisks_block_get_preferred_device (block));
+      gdu_utils_show_error (GTK_WINDOW (data->window), s, error);
+      g_free (s);
+      g_clear_error (&error);
+    }
+  dialog_data_unref (data);
+}
+
+static void
+erase_devices (DialogData  *data,
+               const gchar *erase_type)
+{
+  GList *l;
+
+  for (l = data->blocks; l != NULL; l = l->next)
+    {
+      UDisksBlock *block = l->data;
+      GVariantBuilder options_builder;
+
+      /* Fall back to 'zero' if secure erase is not available */
+      if (g_strcmp0 (erase_type, "secure-erase") == 0)
+        {
+          UDisksDrive *drive = NULL;
+          UDisksDriveAta *ata = NULL;
+
+          /* assume not available, then adjust below if available */
+          erase_type = "zero";
+
+          drive = udisks_client_get_drive_for_block (gdu_window_get_client (data->window), block);
+          if (drive != NULL)
+            {
+              GDBusObject *drive_object;
+              drive_object = g_dbus_interface_get_object (G_DBUS_INTERFACE (drive));
+              if (drive_object != NULL)
+                ata = udisks_object_get_drive_ata (UDISKS_OBJECT (drive_object));
+            }
+
+          if (ata != NULL)
+            {
+              if (!udisks_drive_ata_get_security_frozen (ata))
+                {
+                  if (udisks_drive_ata_get_security_enhanced_erase_unit_minutes (ata) > 0)
+                    erase_type = "ata-secure-erase-enhanced";
+                  else if (udisks_drive_ata_get_security_erase_unit_minutes (ata) > 0)
+                    erase_type = "ata-secure-erase";
+                }
+            }
+          g_clear_object (&ata);
+          g_clear_object (&drive);
+        }
+
+      g_variant_builder_init (&options_builder, G_VARIANT_TYPE_VARDICT);
+      if (strlen (erase_type) > 0)
+        g_variant_builder_add (&options_builder, "{sv}", "erase", g_variant_new_string (erase_type));
+      udisks_block_call_format (block,
+                                "empty",
+                                g_variant_builder_end (&options_builder),
+                                NULL, /* GCancellable */
+                                format_cb,
+                                dialog_data_ref (data));
+    }
+}
+
+void
+gdu_erase_multiple_disks_dialog_show (GduWindow *window,
+                                      GList     *blocks)
+{
+  DialogData *data;
+
+  data = g_new0 (DialogData, 1);
+  data->ref_count = 1;
+  data->window = g_object_ref (window);
+  data->blocks = g_list_copy_deep (blocks, (GCopyFunc) g_object_ref, NULL);
+  data->dialog = GTK_WIDGET (gdu_application_new_widget (gdu_window_get_application (window),
+                                                         "erase-multiple-disks-dialog.ui",
+                                                         "erase-multiple-disks-dialog",
+                                                         &data->builder));
+  data->erase_combobox = GTK_WIDGET (gtk_builder_get_object (data->builder, "erase-combobox"));
+  g_signal_connect (data->erase_combobox, "notify::active", G_CALLBACK (on_property_changed), data);
+
+  gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (window));
+  gtk_dialog_set_default_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_OK);
+
+  populate (data);
+  update (data);
+
+  gtk_widget_show_all (data->dialog);
+  gtk_widget_grab_focus (data->erase_combobox);
+
+  while (TRUE)
+    {
+      gint response;
+
+      response = gtk_dialog_run (GTK_DIALOG (data->dialog));
+      if (response != GTK_RESPONSE_OK)
+        {
+          goto out;
+        }
+      else /* response == GTK_RESPONSE_OK */
+        {
+          const gchar *primary_message;
+          GString *str;
+          const gchar *erase_type;
+
+          erase_type = gtk_combo_box_get_active_id (GTK_COMBO_BOX (data->erase_combobox));
+
+          primary_message = _("Are you sure you want to erase the disks?");
+          if (g_strcmp0 (erase_type, "") == 0)
+            {
+              /* Translators: warning used for erasure of multiple disks */
+              str = g_string_new (_("All data on the selected disks will be lost but may still be recoverable by data recovery services"));
+              g_string_append (str, "\n\n");
+              g_string_append (str, _("<b>Tip</b>: If you are planning to recycle, sell or give away your old computer or disk, you should use a more thorough erase type to keep your private information from falling into the wrong hands"));
+            }
+          else
+            {
+              /* Translators: warning used when overwriting data on multiple disks */
+              str = g_string_new (_("All data on the selected disks will be overwritten and will likely not be recoverable by data recovery services"));
+            }
+
+          if (g_strcmp0 (erase_type, "secure-erase") == 0)
+            {
+              g_string_append (str, "\n\n");
+              g_string_append (str, _("<b>WARNING</b>: The Secure Erase command may take a very long time to complete, can't be canceled and may not work properly with some hardware. In the worst case, your drive may be rendered unusable or your system may crash or lock up. Before proceeding, please read the article about <a href='https://ata.wiki.kernel.org/index.php/ATA_Secure_Erase'>ATA Secure Erase</a> and make sure you understand the risks"));
+            }
+
+          if (!gdu_utils_show_confirmation (GTK_WINDOW (data->dialog),
+                                            primary_message,
+                                            str->str,
+                                            _("_Erase"),
+                                            NULL, NULL))
+            {
+              g_string_free (str, TRUE);
+              continue;
+            }
+          g_string_free (str, TRUE);
+          gtk_widget_hide (data->dialog);
+          erase_devices (data, erase_type);
+          goto out;
+        }
+    }
+
+ out:
+  dialog_data_unref (data);
+}
diff --git a/src/disks/gduerasemultipledisksdialog.h b/src/disks/gduerasemultipledisksdialog.h
new file mode 100644
index 0000000..f7fa898
--- /dev/null
+++ b/src/disks/gduerasemultipledisksdialog.h
@@ -0,0 +1,23 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2008-2012 Red Hat, Inc.
+ *
+ * Licensed under GPL version 2 or later.
+ *
+ * Author: David Zeuthen <zeuthen gmail com>
+ */
+
+#ifndef __GDU_ERASE_MULTIPLE_DISKS_DIALOG_H__
+#define __GDU_ERASE_MULTIPLE_DISKS_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "gdutypes.h"
+
+G_BEGIN_DECLS
+
+void     gdu_erase_multiple_disks_dialog_show (GduWindow  *window,
+                                               GList      *blocks);
+
+G_END_DECLS
+
+#endif /* __GDU_ERASE_MULTIPLE_DISKS_DIALOG_H__ */
diff --git a/src/disks/gduwindow.c b/src/disks/gduwindow.c
index 127d8a3..546c443 100644
--- a/src/disks/gduwindow.c
+++ b/src/disks/gduwindow.c
@@ -39,6 +39,7 @@
 #include "gdudisksettingsdialog.h"
 #include "gdumdraiddisksdialog.h"
 #include "gducreateraidarraydialog.h"
+#include "gduerasemultipledisksdialog.h"
 
 struct _GduWindow
 {
@@ -922,24 +923,6 @@ on_device_tree_selection_toolbar_done_button_clicked (GtkButton *button,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-#if 0
-static void
-on_device_tree_menu_item_erase_disks (GtkMenuItem *menu_item,
-                                      gpointer   user_data)
-{
-  GduWindow *window = GDU_WINDOW (user_data);
-  g_print ("TODO: erase multiple disks %p\n", window);
-}
-
-static void
-on_device_tree_menu_item_create_raid_array (GtkMenuItem *menu_item,
-                                            gpointer   user_data)
-{
-}
-#endif
-
-/* ---------------------------------------------------------------------------------------------------- */
-
 gboolean
 gdu_window_select_object (GduWindow    *window,
                           UDisksObject *object)
@@ -4461,11 +4444,13 @@ update_for_multi_selection (GduWindow *window, ShowFlags *show_flags)
   g_free (s);
 
   /* visibility - TODO: use ShowFlags instead */
-  if (window->in_selection_mode && num_disks > 0)
+  if (window->in_selection_mode && num_blocks > 0)
     {
       guint64 disk_size;
       gtk_widget_show (window->overlay_toolbar);
+
       gtk_widget_show (window->overlay_toolbar_erase_button);
+
       /* RAID requires at all disks are the same size */
       if (gdu_util_is_same_size (selected_blocks, &disk_size))
         {
@@ -4495,7 +4480,13 @@ on_overlay_toolbar_erase_button_clicked (GtkButton *menu_item,
                                          gpointer   user_data)
 {
   GduWindow *window = GDU_WINDOW (user_data);
-  g_print ("TODO: erase multiple %p\n", window);
+  GList *selected_blocks;
+
+  selected_blocks = gdu_device_tree_model_get_selected_blocks (window->model);
+  /* exit multiple selection mode */
+  device_tree_selection_toolbar_select_done_toggle (window, FALSE);
+  gdu_erase_multiple_disks_dialog_show (window, selected_blocks);
+  g_list_free_full (selected_blocks, g_object_unref);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */



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