[gnome-disk-utility/new-ui] Start reworking the UI
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility/new-ui] Start reworking the UI
- Date: Wed, 2 Sep 2009 16:42:55 +0000 (UTC)
commit 1dd2a25631274a3d976522d4763eb0d91397ec75
Author: David Zeuthen <davidz redhat com>
Date: Wed Sep 2 12:37:44 2009 -0400
Start reworking the UI
src/gdu-gtk/Makefile.am | 6 +
src/gdu-gtk/gdu-ata-smart-dialog.c | 663 +++++---------
src/gdu-gtk/gdu-create-linux-md-dialog.c | 7 +-
src/gdu-gtk/gdu-details-element.c | 556 +++++++++++
src/gdu-gtk/gdu-details-element.h | 99 ++
src/gdu-gtk/gdu-details-table.c | 477 ++++++++++
src/gdu-gtk/gdu-details-table.h | 66 ++
src/gdu-gtk/gdu-gtk-types.h | 19 +-
src/gdu-gtk/gdu-gtk.h | 3 +
src/gdu-gtk/gdu-pool-tree-model.c | 69 ++-
src/gdu-gtk/gdu-pool-tree-model.h | 1 +
src/gdu-gtk/gdu-size-widget.c | 4 +-
src/gdu-gtk/gdu-volume-grid.c | 1321 +++++++++++++++++++++++++++
src/gdu-gtk/gdu-volume-grid.h | 67 ++
src/gdu/gdu-drive.c | 4 +-
src/gdu/gdu-linux-md-drive.c | 2 +-
src/gdu/gdu-presentable.c | 61 ++
src/gdu/gdu-presentable.h | 5 +
src/gdu/gdu-util.c | 58 +-
src/gdu/gdu-util.h | 5 +-
src/gdu/gdu-volume-hole.c | 2 +-
src/gdu/gdu-volume.c | 2 +-
src/palimpsest/Makefile.am | 2 +
src/palimpsest/gdu-section-drive.c | 605 ++++++++++++
src/palimpsest/gdu-section-drive.h | 58 ++
src/palimpsest/gdu-section-linux-md-drive.c | 9 +-
src/palimpsest/gdu-section-volumes.c | 601 ++++++++++++
src/palimpsest/gdu-section-volumes.h | 58 ++
src/palimpsest/gdu-section.c | 6 +-
src/palimpsest/gdu-section.h | 12 +-
src/palimpsest/gdu-shell.c | 66 ++-
31 files changed, 4390 insertions(+), 524 deletions(-)
---
diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index 3eba71e..9da383f 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -37,6 +37,9 @@ libgdu_gtkinclude_HEADERS = \
gdu-create-linux-md-dialog.h \
gdu-ata-smart-dialog.h \
gdu-spinner.h \
+ gdu-volume-grid.h \
+ gdu-details-table.h \
+ gdu-details-element.h \
$(NULL)
libgdu_gtk_la_SOURCES = \
@@ -51,6 +54,9 @@ libgdu_gtk_la_SOURCES = \
gdu-create-linux-md-dialog.h gdu-create-linux-md-dialog.c \
gdu-ata-smart-dialog.h gdu-ata-smart-dialog.c \
gdu-spinner.h gdu-spinner.c \
+ gdu-volume-grid.h gdu-volume-grid.c \
+ gdu-details-table.h gdu-details-table.c \
+ gdu-details-element.h gdu-details-element.c \
$(NULL)
libgdu_gtk_la_CPPFLAGS = \
diff --git a/src/gdu-gtk/gdu-ata-smart-dialog.c b/src/gdu-gtk/gdu-ata-smart-dialog.c
index 164faa2..94d4ac2 100644
--- a/src/gdu-gtk/gdu-ata-smart-dialog.c
+++ b/src/gdu-gtk/gdu-ata-smart-dialog.c
@@ -32,6 +32,8 @@
#include "gdu-ata-smart-dialog.h"
#include "gdu-spinner.h"
#include "gdu-pool-tree-model.h"
+#include "gdu-details-table.h"
+#include "gdu-details-element.h"
/* ---------------------------------------------------------------------------------------------------- */
@@ -47,25 +49,17 @@ struct GduAtaSmartDialogPrivate
GduPoolTreeModel *pool_tree_model;
GtkWidget *drive_combo_box;
- GtkWidget *updated_label;
- GtkWidget *updating_spinner;
- GtkWidget *updating_label;
- GtkWidget *update_link_label;
-
- GtkWidget *self_test_result_label;
- GtkWidget *self_test_progress_bar;
- GtkWidget *self_test_run_link_label;
- GtkWidget *self_test_cancel_link_label;
-
- GtkWidget *model_label;
- GtkWidget *firmware_label;
- GtkWidget *serial_label;
- GtkWidget *power_on_hours_label;
- GtkWidget *temperature_label;
- GtkWidget *sectors_label;
- GtkWidget *self_assessment_label;
- GtkWidget *overall_assessment_image;
- GtkWidget *overall_assessment_label;
+ GduDetailsElement *updated_element;
+ GduDetailsElement *self_test_element;
+ GduDetailsElement *model_element;
+ GduDetailsElement *firmware_element;
+ GduDetailsElement *serial_element;
+ GduDetailsElement *powered_on_element;
+ GduDetailsElement *temperature_element;
+ GduDetailsElement *bad_sectors_element;
+ GduDetailsElement *self_assessment_element;
+ GduDetailsElement *overall_assessment_element;
+
GtkWidget *no_warn_check_button;
GtkWidget *tree_view;
@@ -82,6 +76,9 @@ enum
PROP_DRIVE,
};
+static gboolean is_self_test_running (GduDevice *device,
+ SkSmartSelfTest *out_test_type);
+
/* ---------------------------------------------------------------------------------------------------- */
#define _GDU_TYPE_SK_ATTR (_gdu_type_sk_attr_get_type ())
@@ -1129,9 +1126,8 @@ refresh_cb (GduDevice *device,
static void
-on_activate_link_update_smart_data (GtkLabel *label,
- const gchar *uri,
- gpointer user_data)
+on_updated_element_activated (GduDetailsElement *element,
+ gpointer user_data)
{
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
@@ -1139,8 +1135,6 @@ on_activate_link_update_smart_data (GtkLabel *label,
refresh_cb,
dialog);
- g_signal_stop_emission_by_name (label, "activate-link");
-
dialog->priv->is_updating = TRUE;
update_dialog (dialog);
}
@@ -1157,23 +1151,6 @@ cancel_self_test_cb (GduDevice *device,
g_error_free (error);
}
-
-static void
-on_activate_link_cancel_self_test (GtkLabel *link_label,
- const gchar *uri,
- gpointer user_data)
-{
- GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
-
- g_signal_stop_emission_by_name (link_label, "activate-link");
-
- gdu_device_op_cancel_job (dialog->priv->device,
- cancel_self_test_cb,
- dialog);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static void
run_self_test_cb (GduDevice *device,
GError *error,
@@ -1186,9 +1163,8 @@ run_self_test_cb (GduDevice *device,
static void
-on_activate_link_run_self_test (GtkLabel *link_label,
- const gchar *uri,
- gpointer user_data)
+on_self_tests_element_activated (GduDetailsElement *element,
+ gpointer user_data)
{
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
GtkWidget *test_dialog;
@@ -1203,7 +1179,12 @@ on_activate_link_run_self_test (GtkLabel *link_label,
gint response;
const gchar *test;
- g_signal_stop_emission_by_name (link_label, "activate-link");
+ if (is_self_test_running (dialog->priv->device, NULL)) {
+ gdu_device_op_cancel_job (dialog->priv->device,
+ cancel_self_test_cb,
+ dialog);
+ goto out;
+ }
test_dialog = gtk_dialog_new_with_buttons (NULL,
GTK_WINDOW (dialog),
@@ -1479,14 +1460,10 @@ gdu_ata_smart_dialog_constructed (GObject *object)
GtkWidget *align;
GtkWidget *vbox;
GtkWidget *vbox2;
- GtkWidget *hbox;
- GtkWidget *image;
GtkWidget *table;
GtkWidget *label;
GtkWidget *tree_view;
GtkWidget *scrolled_window;
- GtkWidget *spinner;
- GtkWidget *progress_bar;
GtkWidget *check_button;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
@@ -1498,6 +1475,8 @@ gdu_ata_smart_dialog_constructed (GObject *object)
GtkTreeIter iter = {0};
const gchar *tooltip_markup;
gboolean rtl;
+ GPtrArray *elements;
+ GduDetailsElement *element;
rtl = (gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_RTL);
@@ -1518,6 +1497,7 @@ gdu_ata_smart_dialog_constructed (GObject *object)
pool = gdu_device_get_pool (dialog->priv->device);
dialog->priv->pool_tree_model = gdu_pool_tree_model_new (pool,
+ NULL,
GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES);
g_object_unref (pool);
@@ -1593,342 +1573,102 @@ gdu_ata_smart_dialog_constructed (GObject *object)
vbox2 = gtk_vbox_new (FALSE, 6);
gtk_container_add (GTK_CONTAINER (align), vbox2);
- table = gtk_table_new (4, 2, FALSE);
- 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);
-
- row = 0;
-
- /* ------------------------------ */
- /* updated */
-
- /* Translators: Tooltip for the Updated item in the status table */
- tooltip_markup = _("Time since SMART data was last read â?? SMART data is updated every 30 minutes unless "
- "the disk is sleeping");
+ elements = g_ptr_array_new_with_free_func (g_object_unref);
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Updated:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- hbox = gtk_hbox_new (FALSE, 0);
-
- /* Translators: Used in the status table when data is currently being updated */
- label = gtk_label_new (_("Updating..."));
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- dialog->priv->updating_label = label;
-
- spinner = gdu_spinner_new ();
- gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 6);
- dialog->priv->updating_spinner = spinner;
-
- label = gdu_time_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->updated_label = label;
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
-
- label = gtk_label_new (NULL);
- s = g_strdup_printf (rtl ? "<a href=\"update-now\" title=\"%s\">%s</a> â?? " :
- " â?? <a href=\"update-now\" title=\"%s\">%s</a>",
- /* Translators: Tooltip for the "Update Now" hyperlink */
- _("Reads SMART data from the disk, waking it up if necessary"),
- /* Translators: Text used in the hyperlink in the status table to update the SMART status */
- _("Update now"));
- gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
- gtk_label_set_markup (GTK_LABEL (label), s);
- g_free (s);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->update_link_label = label;
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- g_signal_connect (label,
- "activate-link",
- G_CALLBACK (on_activate_link_update_smart_data),
+ element = gdu_details_element_new (_("Updated:"),
+ NULL,
+ /* Translators: Tooltip for the 'Updated' item in the status table */
+ _("Time since SMART data was last read â?? SMART data is updated every "
+ "30 minutes unless the disk is sleeping"));
+ g_signal_connect (element,
+ "activated",
+ G_CALLBACK (on_updated_element_activated),
dialog);
+ g_ptr_array_add (elements, element);
+ dialog->priv->updated_element = element;
- gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
- row++;
-
- /* control visibility (see update_dialog()) */
- gtk_widget_set_no_show_all (dialog->priv->updated_label, TRUE);
- gtk_widget_set_no_show_all (dialog->priv->updating_label, TRUE);
- gtk_widget_set_no_show_all (dialog->priv->updating_spinner, TRUE);
- gtk_widget_set_no_show_all (dialog->priv->update_link_label, TRUE);
-
- /* ------------------------------ */
- /* self-tests */
-
- /* Translators: Tooltip for the Self-tests item in the status table */
- tooltip_markup = _("The result of the last self-test that ran on the disk");
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Self-tests:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- hbox = gtk_hbox_new (FALSE, 0);
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- dialog->priv->self_test_result_label = label;
-
-
- progress_bar = gtk_progress_bar_new ();
- gtk_box_pack_start (GTK_BOX (hbox), progress_bar, FALSE, FALSE, 0);
- dialog->priv->self_test_progress_bar = progress_bar;
-
- label = gtk_label_new (NULL);
- s = g_strdup_printf (rtl ? "<a href=\"run-self-test\" title=\"%s\">%s</a> â?? " :
- " â?? <a href=\"run-self-test\" title=\"%s\">%s</a>",
- /* Translators: Tooltip for the "Run self-test" hyperlink */
- _("Initiates a self-test on the drive"),
- /* Translators: Text used in the hyperlink in the status table to run a self-test */
- _("Run self-test"));
- gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
- gtk_label_set_markup (GTK_LABEL (label), s);
- g_free (s);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- dialog->priv->self_test_run_link_label = label;
- g_signal_connect (label,
- "activate-link",
- G_CALLBACK (on_activate_link_run_self_test),
- dialog);
-
- label = gtk_label_new (NULL);
- gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
- s = g_strdup_printf (rtl ? "<a href=\"cancel-self-test\" title=\"%s\">%s</a> â?? " :
- " â?? <a href=\"cancel-self-test\" title=\"%s\">%s</a>",
- /* Translators: Tooptip for the "Cancel" hyperlink */
- _("Cancels the currently running test"),
- /* Translators: Text used in the hyperlink in the status table to cancel a self-test */
- _("Cancel"));
- gtk_label_set_markup (GTK_LABEL (label), s);
- g_free (s);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
- dialog->priv->self_test_cancel_link_label = label;
- g_signal_connect (label,
- "activate-link",
- G_CALLBACK (on_activate_link_cancel_self_test),
+ element = gdu_details_element_new (_("Self-tests:"),
+ NULL,
+ /* Translators: Tooltip for the 'Self-tests' item in the status table */
+ _("The result of the last self-test that ran on the disk"));
+ g_signal_connect (element,
+ "activated",
+ G_CALLBACK (on_self_tests_element_activated),
dialog);
+ g_ptr_array_add (elements, element);
+ dialog->priv->self_test_element = element;
- gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- row++;
-
- /* control visibility (see update_dialog()) */
- gtk_widget_set_no_show_all (dialog->priv->self_test_result_label, TRUE);
- gtk_widget_set_no_show_all (dialog->priv->self_test_progress_bar, TRUE);
- gtk_widget_set_no_show_all (dialog->priv->self_test_run_link_label, TRUE);
- gtk_widget_set_no_show_all (dialog->priv->self_test_cancel_link_label, TRUE);
-
- /* ------------------------------ */
- /* model */
-
- /* Translators: Tooltip for the "Model Name:" item in the status table */
- tooltip_markup = _("The name of the model of the disk");
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Model Name:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ element = gdu_details_element_new (_("Model:"),
+ NULL,
+ /* Translators: Tooltip for the 'Model' item in the status table */
+ _("The name of the model of the disk"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->model_element = element;
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->model_label = label;
-
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- row++;
-
- /* ------------------------------ */
- /* firmware */
-
- /* Translators: Tooltip for the "Firmware Version:" item in the status table */
- tooltip_markup = _("The firmware version of the disk");
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Firmware Version:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ element = gdu_details_element_new (_("Firmware Version:"),
+ NULL,
+ /* Translators: Tooltip for the 'Firmware Version' item in the
+ * status table */
+ _("The firmware version of the disk"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->firmware_element = element;
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->firmware_label = label;
-
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- row++;
-
- /* ------------------------------ */
- /* serial */
-
- /* Translators: Tooltip for the "Serial:" item in the status table */
- tooltip_markup = _("The serial number of the disk");
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Serial Number:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->serial_label = label;
-
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- row++;
-
- /* ------------------------------ */
- /* power on hours */
-
- /* Translators: Tooltip for the "Powered On:" item in the status table */
- tooltip_markup = _("The amount of elapsed time the disk has been in a powered-up state");
+ element = gdu_details_element_new (_("Serial Number:"),
+ NULL,
+ /* Translators: Tooltip for the 'Serial Number' item in the status table */
+ _("The serial number of the disk"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->serial_element = element;
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Powered On:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->power_on_hours_label = label;
-
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- row++;
-
- /* ------------------------------ */
- /* temperature */
-
- /* Translators: Tooltip for the "Temperature:" item in the status table */
- tooltip_markup = _("The temperature of the disk");
+ element = gdu_details_element_new (_("Powered On:"),
+ NULL,
+ /* Translators: Tooltip for the 'Powered On' item in the status table */
+ _("The amount of elapsed time the disk has been in a powered-up state"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->powered_on_element = element;
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Temperature:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->temperature_label = label;
+ element = gdu_details_element_new (_("Temperature:"),
+ NULL,
+ /* Translators: Tooltip for the 'Temperature' item in the status table */
+ _("The temperature of the disk"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->temperature_element = element;
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- row++;
-
- /* ------------------------------ */
- /* bad sectors */
-
- /* Translators: Tooltip for the "Bad Sectors" item in the status table */
- tooltip_markup = _("The sum of pending and reallocated bad sectors");
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Bad Sectors:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->sectors_label = label;
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
- row++;
+ element = gdu_details_element_new (_("Bad Sectors:"),
+ NULL,
+ /* Translators: Tooltip for the 'Bad Sectors' item in the status table */
+ _("The sum of pending and reallocated bad sectors"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->bad_sectors_element = element;
- /* ------------------------------ */
- /* self assessment */
-
- /* Translators: Tooltip for the "Self Assessment" item in the status table */
- tooltip_markup = _("The assessment from the disk itself whether it is about to fail");
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Self Assessment:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ element = gdu_details_element_new (_("Self Assessment:"),
+ NULL,
+ /* Translators: Tooltip for the 'Self Assesment' item in the status table */
+ _("The assessment from the disk itself whether it is about to fail"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->self_assessment_element = element;
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->self_assessment_label = label;
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
- row++;
-
- /* ------------------------------ */
- /* overall assessment */
-
- /* Translators: Tooltip for the "Overall Assessment" in the status table */
- tooltip_markup = _("An overall assessment of the health of the disk");
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
/* Translators: Item name in the status table */
- gtk_label_set_markup (GTK_LABEL (label), _("Overall Assessment:"));
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
-
- hbox = gtk_hbox_new (FALSE, 2);
- image = gtk_image_new_from_icon_name ("gdu-smart-unknown",
- GTK_ICON_SIZE_MENU);
- gtk_widget_set_tooltip_markup (image, tooltip_markup);
- gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
- dialog->priv->overall_assessment_image = image;
-
- label = gtk_label_new (NULL);
- gtk_widget_set_tooltip_markup (label, tooltip_markup);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
- dialog->priv->overall_assessment_label = label;
- gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
-
- gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, row, row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
- row++;
+ element = gdu_details_element_new (_("Overall Assessment:"),
+ NULL,
+ /* Translators: Tooltip for the 'Overall Assessment' item in the
+ * status table */
+ _("An overall assessment of the health of the disk"));
+ g_ptr_array_add (elements, element);
+ dialog->priv->overall_assessment_element = element;
+
+ table = gdu_details_table_new (1, elements);
+ g_ptr_array_unref (elements);
+ gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
/* ------------------------------ */
@@ -2425,7 +2165,7 @@ update_dialog (GduAtaSmartDialog *dialog)
gchar *selftest_text;
gchar *action_text;
gboolean highlight;
- GTimeVal updated;
+ guint64 updated;
gconstpointer blob;
gsize blob_size;
GIcon *status_icon;
@@ -2450,8 +2190,7 @@ update_dialog (GduAtaSmartDialog *dialog)
temperature_text = NULL;
selftest_text = NULL;
action_text = NULL;
- updated.tv_sec = 0;
- dialog->priv->last_updated = 0;
+ updated = 0;
status_icon = NULL;
sk_disk = NULL;
@@ -2494,8 +2233,7 @@ update_dialog (GduAtaSmartDialog *dialog)
goto has_data;
}
- dialog->priv->last_updated = updated.tv_sec = gdu_device_drive_ata_smart_get_time_collected (dialog->priv->device);
- updated.tv_usec = 0;
+ dialog->priv->last_updated = updated = gdu_device_drive_ata_smart_get_time_collected (dialog->priv->device);
s = gdu_util_ata_smart_status_to_desc (gdu_device_drive_ata_smart_get_status (dialog->priv->device),
&highlight,
@@ -2644,25 +2382,110 @@ update_dialog (GduAtaSmartDialog *dialog)
if (status_icon == NULL)
status_icon = g_themed_icon_new ("gdu-smart-unknown");
- gtk_image_set_from_gicon (GTK_IMAGE (dialog->priv->overall_assessment_image),
- status_icon,
- GTK_ICON_SIZE_MENU);
-
- gtk_label_set_markup (GTK_LABEL (dialog->priv->self_assessment_label), self_assessment_text != NULL ? self_assessment_text : "-");
- gtk_label_set_markup (GTK_LABEL (dialog->priv->overall_assessment_label), overall_assessment_text != NULL ? overall_assessment_text : "-");
- gtk_label_set_markup (GTK_LABEL (dialog->priv->sectors_label), bad_sectors_text != NULL ? bad_sectors_text : "-");
- gtk_label_set_markup (GTK_LABEL (dialog->priv->power_on_hours_label), powered_on_text != NULL ? powered_on_text : "-");
- gtk_label_set_markup (GTK_LABEL (dialog->priv->temperature_label), temperature_text != NULL ? temperature_text : "-");
- gtk_label_set_markup (GTK_LABEL (dialog->priv->model_label), model_text != NULL ? model_text : "-");
- gtk_label_set_markup (GTK_LABEL (dialog->priv->firmware_label), firmware_text != NULL ? firmware_text : "-");
- gtk_label_set_markup (GTK_LABEL (dialog->priv->serial_label), serial_text != NULL ? serial_text : "-");
- if (updated.tv_sec == 0) {
- gdu_time_label_set_time (GDU_TIME_LABEL (dialog->priv->updated_label), NULL);
- gtk_label_set_markup (GTK_LABEL (dialog->priv->updated_label), "-");
+ gdu_details_element_set_icon (dialog->priv->overall_assessment_element, status_icon);
+
+ gdu_details_element_set_text (dialog->priv->self_assessment_element,
+ self_assessment_text != NULL ? self_assessment_text : "-");
+ gdu_details_element_set_text (dialog->priv->overall_assessment_element,
+ overall_assessment_text != NULL ? overall_assessment_text : "-");
+ gdu_details_element_set_text (dialog->priv->bad_sectors_element,
+ bad_sectors_text != NULL ? bad_sectors_text : "-");
+ gdu_details_element_set_text (dialog->priv->powered_on_element,
+ powered_on_text != NULL ? powered_on_text : "-");
+ gdu_details_element_set_text (dialog->priv->temperature_element,
+ temperature_text != NULL ? temperature_text : "-");
+ gdu_details_element_set_text (dialog->priv->model_element,
+ model_text != NULL ? model_text : "-");
+ gdu_details_element_set_text (dialog->priv->firmware_element,
+ firmware_text != NULL ? firmware_text : "-");
+ gdu_details_element_set_text (dialog->priv->serial_element,
+ serial_text != NULL ? serial_text : "-");
+ if (dialog->priv->is_updating) {
+ gdu_details_element_set_is_spinning (dialog->priv->updated_element, TRUE);
+ gdu_details_element_set_text (dialog->priv->updated_element, "Updating");
+ gdu_details_element_set_time (dialog->priv->updated_element, 0);
+ gdu_details_element_set_action_text (dialog->priv->updated_element, NULL);
+ gdu_details_element_set_action_tooltip (dialog->priv->updated_element, NULL);
+ } else {
+ gdu_details_element_set_is_spinning (dialog->priv->updated_element, FALSE);
+ if (updated > 0) {
+ gdu_details_element_set_time (dialog->priv->updated_element, updated);
+ gdu_details_element_set_text (dialog->priv->updated_element, NULL);
+ } else {
+ gdu_details_element_set_time (dialog->priv->updated_element, 0);
+ gdu_details_element_set_text (dialog->priv->updated_element, "-");
+ }
+ gdu_details_element_set_action_text (dialog->priv->updated_element,
+ /* Translators: Text used in the hyperlink in the status table
+ * to update the SMART status */
+ _("Update Now"));
+ gdu_details_element_set_action_tooltip (dialog->priv->updated_element,
+ /* Translators: Tooltip for the "Update Now" hyperlink */
+ _("Reads SMART data from the disk, waking it up if necessary"));
+ }
+
+ if (dialog->priv->device != NULL && is_self_test_running (dialog->priv->device, &test_type)) {
+ gdouble fraction;
+ const gchar *test_type_str;
+
+ switch (test_type) {
+ case SK_SMART_SELF_TEST_SHORT:
+ /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
+ test_type_str = _("Short self-test in progress: ");
+ break;
+ case SK_SMART_SELF_TEST_EXTENDED:
+ /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
+ test_type_str = _("Extended self-test in progress: ");
+ break;
+ case SK_SMART_SELF_TEST_CONVEYANCE:
+ /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
+ test_type_str = _("Conveyance self-test in progress: ");
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (gdu_device_job_is_cancellable (dialog->priv->device)) {
+ gdu_details_element_set_action_text (dialog->priv->self_test_element,
+ /* Translators: Text used in the hyperlink in the status
+ * table to cancel a self-test */
+ _("Cancel Test"));
+ gdu_details_element_set_action_tooltip (dialog->priv->self_test_element,
+ /* Translators: Tooptip for the "Cancel" hyperlink */
+ _("Cancels the currently running test"));
+ } else {
+ gdu_details_element_set_action_text (dialog->priv->self_test_element, NULL);
+ gdu_details_element_set_action_tooltip (dialog->priv->self_test_element, NULL);
+ }
+ gdu_details_element_set_text (dialog->priv->self_test_element, test_type_str);
+
+ fraction = gdu_device_job_get_percentage (dialog->priv->device) / 100.0;
+ if (fraction < 0.0)
+ fraction = 0.0;
+ if (fraction > 1.0)
+ fraction = 1.0;
+
+ gdu_details_element_set_progress (dialog->priv->self_test_element, fraction);
} else {
- gdu_time_label_set_time (GDU_TIME_LABEL (dialog->priv->updated_label), &updated);
+ gdu_details_element_set_progress (dialog->priv->self_test_element, -1.0);
+ gdu_details_element_set_text (dialog->priv->self_test_element,
+ selftest_text != NULL ? selftest_text : "-");
+ if (dialog->priv->device != NULL) {
+ /* TODO: check if self-tests are available at all */
+ gdu_details_element_set_action_text (dialog->priv->self_test_element,
+ /* Translators: Text used in the hyperlink in the
+ * status table to run a self-test */
+ _("Run self-test"));
+ gdu_details_element_set_action_tooltip (dialog->priv->self_test_element,
+ /* Translators: Tooltip for the "Run self-test"
+ * hyperlink */
+ _("Initiates a self-test on the drive"));
+ } else {
+ gdu_details_element_set_action_text (dialog->priv->self_test_element, NULL);
+ gdu_details_element_set_action_tooltip (dialog->priv->self_test_element, NULL);
+ }
}
- gtk_label_set_markup (GTK_LABEL (dialog->priv->self_test_result_label), selftest_text != NULL ? selftest_text : "-");
if (sk_disk == NULL) {
gtk_list_store_clear (dialog->priv->attr_list_store);
@@ -2703,76 +2526,6 @@ update_dialog (GduAtaSmartDialog *dialog)
no_warn = get_ata_smart_no_warn (dialog->priv->device);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->no_warn_check_button), no_warn);
- /* control visility of update widgets */
- if (dialog->priv->is_updating) {
- gtk_widget_hide (dialog->priv->updated_label);
- gtk_widget_hide (dialog->priv->update_link_label);
- gtk_widget_show (dialog->priv->updating_spinner);
- gtk_widget_show (dialog->priv->updating_label);
- gdu_spinner_start (GDU_SPINNER (dialog->priv->updating_spinner));
- } else {
- gtk_widget_hide (dialog->priv->updating_spinner);
- gdu_spinner_stop (GDU_SPINNER (dialog->priv->updating_spinner));
- gtk_widget_hide (dialog->priv->updating_label);
- gtk_widget_show (dialog->priv->updated_label);
- if (dialog->priv->device == NULL) {
- gtk_widget_hide (dialog->priv->update_link_label);
- } else {
- gtk_widget_show (dialog->priv->update_link_label);
- }
- }
-
- /* control visibility of self-test widgets */
- if (dialog->priv->device != NULL && is_self_test_running (dialog->priv->device, &test_type)) {
- gdouble fraction;
- const gchar *test_type_str;
-
- fraction = gdu_device_job_get_percentage (dialog->priv->device) / 100.0;
- if (fraction < 0.0)
- fraction = 0.0;
- if (fraction > 1.0)
- fraction = 1.0;
-
- gtk_widget_show (dialog->priv->self_test_result_label);
- gtk_widget_hide (dialog->priv->self_test_run_link_label);
- gtk_widget_show (dialog->priv->self_test_progress_bar);
- if (gdu_device_job_is_cancellable (dialog->priv->device))
- gtk_widget_show (dialog->priv->self_test_cancel_link_label);
- else
- gtk_widget_hide (dialog->priv->self_test_cancel_link_label);
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (dialog->priv->self_test_progress_bar),
- fraction);
-
- switch (test_type) {
- case SK_SMART_SELF_TEST_SHORT:
- /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
- test_type_str = _("Short self-test in progress: ");
- break;
- case SK_SMART_SELF_TEST_EXTENDED:
- /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
- test_type_str = _("Extended self-test in progress: ");
- break;
- case SK_SMART_SELF_TEST_CONVEYANCE:
- /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
- test_type_str = _("Conveyance self-test in progress: ");
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- gtk_label_set_markup (GTK_LABEL (dialog->priv->self_test_result_label),
- test_type_str);
- } else {
- gtk_widget_hide (dialog->priv->self_test_progress_bar);
- gtk_widget_hide (dialog->priv->self_test_cancel_link_label);
- gtk_widget_show (dialog->priv->self_test_result_label);
- if (dialog->priv->device == NULL) {
- gtk_widget_hide (dialog->priv->self_test_run_link_label);
- } else {
- gtk_widget_show (dialog->priv->self_test_run_link_label);
- }
- }
-
if (sk_disk != NULL)
sk_disk_free (sk_disk);
diff --git a/src/gdu-gtk/gdu-create-linux-md-dialog.c b/src/gdu-gtk/gdu-create-linux-md-dialog.c
index ea90378..0f5342d 100644
--- a/src/gdu-gtk/gdu-create-linux-md-dialog.c
+++ b/src/gdu-gtk/gdu-create-linux-md-dialog.c
@@ -731,7 +731,7 @@ notes_data_func (GtkCellLayout *cell_layout,
if (array_size > 1000 * 1000) {
gchar *strsize;
- strsize = gdu_util_get_size_for_display (component_size, FALSE);
+ strsize = gdu_util_get_size_for_display (component_size, FALSE, FALSE);
if (whole_disk_is_uninitialized) {
/* Translators: This is shown in the Details column.
@@ -762,7 +762,7 @@ notes_data_func (GtkCellLayout *cell_layout,
} else {
gchar *strsize;
- strsize = gdu_util_get_size_for_display (largest_segment, FALSE);
+ strsize = gdu_util_get_size_for_display (largest_segment, FALSE, FALSE);
if (whole_disk_is_uninitialized) {
/* Translators: This is shown in the Details column.
@@ -1064,6 +1064,7 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
GtkTreeViewColumn *column;
dialog->priv->model = gdu_pool_tree_model_new (dialog->priv->pool,
+ NULL,
GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES |
GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES);
@@ -1498,7 +1499,7 @@ update (GduCreateLinuxMdDialog *dialog)
if (tip_text == NULL) {
gchar *strsize;
- strsize = gdu_util_get_size_for_display (array_size, FALSE);
+ strsize = gdu_util_get_size_for_display (array_size, FALSE, 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".
diff --git a/src/gdu-gtk/gdu-details-element.c b/src/gdu-gtk/gdu-details-element.c
new file mode 100644
index 0000000..9393149
--- /dev/null
+++ b/src/gdu-gtk/gdu-details-element.c
@@ -0,0 +1,556 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <math.h>
+
+#include "gdu-size-widget.h"
+
+struct GduDetailsElementPrivate
+{
+ gchar *heading;
+ gchar *text;
+ guint64 time;
+ gdouble progress;
+ gchar *tooltip;
+ GIcon *icon;
+ gchar *action_text;
+ gchar *action_uri;
+ gchar *action_tooltip;
+ gboolean is_spinning;
+};
+
+enum
+{
+ PROP_0,
+ PROP_HEADING,
+ PROP_TEXT,
+ PROP_TIME,
+ PROP_PROGRESS,
+ PROP_TOOLTIP,
+ PROP_ICON,
+ PROP_ACTION_TEXT,
+ PROP_ACTION_URI,
+ PROP_ACTION_TOOLTIP,
+ PROP_IS_SPINNING
+};
+
+enum
+{
+ CHANGED_SIGNAL,
+ ACTIVATED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0,};
+
+G_DEFINE_TYPE (GduDetailsElement, gdu_details_element, G_TYPE_OBJECT)
+
+static void
+gdu_details_element_finalize (GObject *object)
+{
+ GduDetailsElement *element = GDU_DETAILS_ELEMENT (object);
+
+ g_free (element->priv->heading);
+ g_free (element->priv->text);
+ g_free (element->priv->tooltip);
+ if (element->priv->icon != NULL)
+ g_object_unref (element->priv->icon);
+ g_free (element->priv->action_text);
+ g_free (element->priv->action_uri);
+ g_free (element->priv->action_tooltip);
+
+ if (G_OBJECT_CLASS (gdu_details_element_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_details_element_parent_class)->finalize (object);
+}
+
+static void
+gdu_details_element_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GduDetailsElement *element = GDU_DETAILS_ELEMENT (object);
+
+ switch (property_id) {
+ case PROP_HEADING:
+ g_value_set_string (value, gdu_details_element_get_heading (element));
+ break;
+
+ case PROP_TEXT:
+ g_value_set_string (value, gdu_details_element_get_text (element));
+ break;
+
+ case PROP_TIME:
+ g_value_set_uint64 (value, gdu_details_element_get_time (element));
+ break;
+
+ case PROP_PROGRESS:
+ g_value_set_double (value, gdu_details_element_get_progress (element));
+ break;
+
+ case PROP_TOOLTIP:
+ g_value_set_string (value, gdu_details_element_get_tooltip (element));
+ break;
+
+ case PROP_ICON:
+ g_value_take_object (value, gdu_details_element_get_icon (element));
+ break;
+
+ case PROP_ACTION_TEXT:
+ g_value_set_string (value, gdu_details_element_get_action_text (element));
+ break;
+
+ case PROP_ACTION_URI:
+ g_value_set_string (value, gdu_details_element_get_action_uri (element));
+ break;
+
+ case PROP_ACTION_TOOLTIP:
+ g_value_set_string (value, gdu_details_element_get_action_tooltip (element));
+ break;
+
+ case PROP_IS_SPINNING:
+ g_value_set_boolean (value, gdu_details_element_get_is_spinning (element));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdu_details_element_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GduDetailsElement *element = GDU_DETAILS_ELEMENT (object);
+
+ switch (property_id) {
+
+ case PROP_HEADING:
+ gdu_details_element_set_heading (element, g_value_get_string (value));
+ break;
+
+ case PROP_TEXT:
+ gdu_details_element_set_text (element, g_value_get_string (value));
+ break;
+
+ case PROP_TIME:
+ gdu_details_element_set_time (element, g_value_get_uint64 (value));
+ break;
+
+ case PROP_PROGRESS:
+ gdu_details_element_set_progress (element, g_value_get_double (value));
+ break;
+
+ case PROP_TOOLTIP:
+ gdu_details_element_set_tooltip (element, g_value_get_string (value));
+ break;
+
+ case PROP_ICON:
+ gdu_details_element_set_icon (element, g_value_get_object (value));
+ break;
+
+ case PROP_ACTION_TEXT:
+ gdu_details_element_set_action_text (element, g_value_get_string (value));
+ break;
+
+ case PROP_ACTION_URI:
+ gdu_details_element_set_action_uri (element, g_value_get_string (value));
+ break;
+
+ case PROP_ACTION_TOOLTIP:
+ gdu_details_element_set_action_tooltip (element, g_value_get_string (value));
+ break;
+
+ case PROP_IS_SPINNING:
+ gdu_details_element_set_is_spinning (element, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdu_details_element_init (GduDetailsElement *element)
+{
+ element->priv = G_TYPE_INSTANCE_GET_PRIVATE (element,
+ GDU_TYPE_DETAILS_ELEMENT,
+ GduDetailsElementPrivate);
+
+}
+
+static void
+gdu_details_element_class_init (GduDetailsElementClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GduDetailsElementPrivate));
+
+ gobject_class->get_property = gdu_details_element_get_property;
+ gobject_class->set_property = gdu_details_element_set_property;
+ gobject_class->finalize = gdu_details_element_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_HEADING,
+ g_param_spec_string ("heading",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_TIME,
+ g_param_spec_uint64 ("time",
+ NULL,
+ NULL,
+ 0,
+ G_MAXUINT64,
+ 0,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_PROGRESS,
+ g_param_spec_double ("progress",
+ NULL,
+ NULL,
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ -1.0,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_TOOLTIP,
+ g_param_spec_string ("tooltip",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ICON,
+ g_param_spec_object ("icon",
+ NULL,
+ NULL,
+ G_TYPE_ICON,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ACTION_TEXT,
+ g_param_spec_string ("action-text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ACTION_URI,
+ g_param_spec_string ("action-uri",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ACTION_TOOLTIP,
+ g_param_spec_string ("action-tooltip",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+
+ g_object_class_install_property (gobject_class,
+ PROP_IS_SPINNING,
+ g_param_spec_boolean ("is-spinning",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+ GDU_TYPE_DETAILS_ELEMENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GduDetailsElementClass, changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals[ACTIVATED_SIGNAL] = g_signal_new ("activated",
+ GDU_TYPE_DETAILS_ELEMENT,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GduDetailsElementClass, activated),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+GduDetailsElement *
+gdu_details_element_new (const gchar *heading,
+ const gchar *text,
+ const gchar *tooltip)
+{
+ return GDU_DETAILS_ELEMENT (g_object_new (GDU_TYPE_DETAILS_ELEMENT,
+ "heading", heading,
+ "text", text,
+ "tooltip", tooltip,
+ NULL));
+}
+
+const gchar *
+gdu_details_element_get_heading (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+ return element->priv->heading;
+}
+
+const gchar *
+gdu_details_element_get_text (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+ return element->priv->text;
+}
+
+guint64
+gdu_details_element_get_time (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), 0);
+ return element->priv->time;
+}
+
+gdouble
+gdu_details_element_get_progress (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), -1);
+ return element->priv->progress;
+}
+
+const gchar *
+gdu_details_element_get_tooltip (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+ return element->priv->tooltip;
+}
+
+GIcon *
+gdu_details_element_get_icon (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+ return element->priv->icon != NULL ? g_object_ref (element->priv->icon) : NULL;
+}
+
+const gchar *
+gdu_details_element_get_action_text (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+ return element->priv->action_text;
+}
+
+const gchar *
+gdu_details_element_get_action_uri (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+ return element->priv->action_uri;
+}
+
+const gchar *
+gdu_details_element_get_action_tooltip (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), NULL);
+ return element->priv->action_tooltip;
+}
+
+gboolean
+gdu_details_element_get_is_spinning (GduDetailsElement *element)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_ELEMENT (element), FALSE);
+ return element->priv->is_spinning;
+}
+
+void
+gdu_details_element_set_heading (GduDetailsElement *element,
+ const gchar *heading)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (g_strcmp0 (element->priv->heading, heading) != 0) {
+ g_free (element->priv->heading);
+ element->priv->heading = g_strdup (heading);
+ g_object_notify (G_OBJECT (element), "heading");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_text (GduDetailsElement *element,
+ const gchar *text)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (g_strcmp0 (element->priv->text, text) != 0) {
+ g_free (element->priv->text);
+ element->priv->text = g_strdup (text);
+ g_object_notify (G_OBJECT (element), "text");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_time (GduDetailsElement *element,
+ guint64 time)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (element->priv->time != time) {
+ element->priv->time = time;
+ g_object_notify (G_OBJECT (element), "time");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_progress (GduDetailsElement *element,
+ gdouble progress)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (element->priv->progress != progress) {
+ element->priv->progress = progress;
+ g_object_notify (G_OBJECT (element), "progress");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_tooltip (GduDetailsElement *element,
+ const gchar *tooltip)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (g_strcmp0 (element->priv->tooltip, tooltip) != 0) {
+ g_free (element->priv->tooltip);
+ element->priv->tooltip = g_strdup (tooltip);
+ g_object_notify (G_OBJECT (element), "tooltip");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_icon (GduDetailsElement *element,
+ GIcon *icon)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (!g_icon_equal (element->priv->icon, icon)) {
+ if (element->priv->icon != NULL)
+ g_object_unref (element->priv->icon);
+ element->priv->icon = g_object_ref (icon);
+ g_object_notify (G_OBJECT (element), "icon");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_action_text (GduDetailsElement *element,
+ const gchar *action_text)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (g_strcmp0 (element->priv->action_text, action_text) != 0) {
+ g_free (element->priv->action_text);
+ element->priv->action_text = g_strdup (action_text);
+ g_object_notify (G_OBJECT (element), "action-text");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_action_uri (GduDetailsElement *element,
+ const gchar *action_uri)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (g_strcmp0 (element->priv->action_uri, action_uri) != 0) {
+ g_free (element->priv->action_uri);
+ element->priv->action_uri = g_strdup (action_uri);
+ g_object_notify (G_OBJECT (element), "action-uri");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_action_tooltip (GduDetailsElement *element,
+ const gchar *action_tooltip)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (g_strcmp0 (element->priv->action_tooltip, action_tooltip) != 0) {
+ g_free (element->priv->action_tooltip);
+ element->priv->action_tooltip = g_strdup (action_tooltip);
+ g_object_notify (G_OBJECT (element), "action-tooltip");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
+void
+gdu_details_element_set_is_spinning (GduDetailsElement *element,
+ gboolean is_spinning)
+{
+ g_return_if_fail (GDU_IS_DETAILS_ELEMENT (element));
+ if (element->priv->is_spinning != is_spinning) {
+ element->priv->is_spinning = is_spinning;
+ g_object_notify (G_OBJECT (element), "is-spinning");
+ g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+ }
+}
+
diff --git a/src/gdu-gtk/gdu-details-element.h b/src/gdu-gtk/gdu-details-element.h
new file mode 100644
index 0000000..d7ebc43
--- /dev/null
+++ b/src/gdu-gtk/gdu-details-element.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GDU_DETAILS_ELEMENT_H
+#define __GDU_DETAILS_ELEMENT_H
+
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_DETAILS_ELEMENT (gdu_details_element_get_type())
+#define GDU_DETAILS_ELEMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_DETAILS_ELEMENT, GduDetailsElement))
+#define GDU_DETAILS_ELEMENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_DETAILS_ELEMENT, GduDetailsElementClass))
+#define GDU_IS_DETAILS_ELEMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_DETAILS_ELEMENT))
+#define GDU_IS_DETAILS_ELEMENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_DETAILS_ELEMENT))
+#define GDU_DETAILS_ELEMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_DETAILS_ELEMENT, GduDetailsElementClass))
+
+typedef struct GduDetailsElementClass GduDetailsElementClass;
+typedef struct GduDetailsElementPrivate GduDetailsElementPrivate;
+
+struct GduDetailsElement
+{
+ GObject parent;
+
+ /*< private >*/
+ GduDetailsElementPrivate *priv;
+};
+
+struct GduDetailsElementClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*changed) (GduDetailsElement *element);
+
+ /* signals */
+ void (*activated) (GduDetailsElement *element);
+};
+
+GType gdu_details_element_get_type (void) G_GNUC_CONST;
+GduDetailsElement* gdu_details_element_new (const gchar *heading,
+ const gchar *text,
+ const gchar *tooltip);
+
+const gchar *gdu_details_element_get_heading (GduDetailsElement *element);
+GIcon *gdu_details_element_get_icon (GduDetailsElement *element);
+const gchar *gdu_details_element_get_text (GduDetailsElement *element);
+guint64 gdu_details_element_get_time (GduDetailsElement *element);
+gdouble gdu_details_element_get_progress (GduDetailsElement *element);
+const gchar *gdu_details_element_get_tooltip (GduDetailsElement *element);
+const gchar *gdu_details_element_get_action_text (GduDetailsElement *element);
+const gchar *gdu_details_element_get_action_uri (GduDetailsElement *element);
+const gchar *gdu_details_element_get_action_tooltip (GduDetailsElement *element);
+gboolean gdu_details_element_get_is_spinning (GduDetailsElement *element);
+
+void gdu_details_element_set_heading (GduDetailsElement *element,
+ const gchar *heading);
+void gdu_details_element_set_icon (GduDetailsElement *element,
+ GIcon *icon);
+void gdu_details_element_set_text (GduDetailsElement *element,
+ const gchar *text);
+void gdu_details_element_set_time (GduDetailsElement *element,
+ guint64 time);
+void gdu_details_element_set_progress (GduDetailsElement *element,
+ gdouble progress);
+void gdu_details_element_set_tooltip (GduDetailsElement *element,
+ const gchar *tooltip);
+void gdu_details_element_set_action_text (GduDetailsElement *element,
+ const gchar *action_text);
+void gdu_details_element_set_action_uri (GduDetailsElement *element,
+ const gchar *action_uri);
+void gdu_details_element_set_action_tooltip (GduDetailsElement *element,
+ const gchar *action_tooltip);
+void gdu_details_element_set_is_spinning (GduDetailsElement *element,
+ gboolean is_spinning);
+
+G_END_DECLS
+
+#endif /* __GDU_SIZE_WIDGET_H */
+
diff --git a/src/gdu-gtk/gdu-details-table.c b/src/gdu-gtk/gdu-details-table.c
new file mode 100644
index 0000000..2784a0e
--- /dev/null
+++ b/src/gdu-gtk/gdu-details-table.c
@@ -0,0 +1,477 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <math.h>
+
+#include "gdu-size-widget.h"
+
+struct GduDetailsTablePrivate
+{
+ guint num_columns;
+ GPtrArray *elements;
+
+ GPtrArray *column_tables;
+
+ GPtrArray *element_data_array;
+};
+
+enum
+{
+ PROP_0,
+ PROP_NUM_COLUMNS,
+ PROP_ELEMENTS,
+};
+
+static void do_relayout (GduDetailsTable *table);
+
+G_DEFINE_TYPE (GduDetailsTable, gdu_details_table, GTK_TYPE_HBOX)
+
+static void
+gdu_details_table_finalize (GObject *object)
+{
+ GduDetailsTable *table = GDU_DETAILS_TABLE (object);
+
+ if (table->priv->element_data_array != NULL)
+ g_ptr_array_unref (table->priv->element_data_array);
+
+ if (table->priv->column_tables != NULL)
+ g_ptr_array_unref (table->priv->column_tables);
+
+ if (table->priv->elements != NULL)
+ g_ptr_array_unref (table->priv->elements);
+
+ if (G_OBJECT_CLASS (gdu_details_table_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_details_table_parent_class)->finalize (object);
+}
+
+static void
+gdu_details_table_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GduDetailsTable *table = GDU_DETAILS_TABLE (object);
+
+ switch (property_id) {
+ case PROP_NUM_COLUMNS:
+ g_value_set_uint (value, gdu_details_table_get_num_columns (table));
+ break;
+
+ case PROP_ELEMENTS:
+ g_value_take_boxed (value, gdu_details_table_get_elements (table));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdu_details_table_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GduDetailsTable *table = GDU_DETAILS_TABLE (object);
+
+ switch (property_id) {
+ case PROP_NUM_COLUMNS:
+ gdu_details_table_set_num_columns (table, g_value_get_uint (value));
+ break;
+
+ case PROP_ELEMENTS:
+ gdu_details_table_set_elements (table, g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdu_details_table_init (GduDetailsTable *table)
+{
+ table->priv = G_TYPE_INSTANCE_GET_PRIVATE (table,
+ GDU_TYPE_DETAILS_TABLE,
+ GduDetailsTablePrivate);
+
+}
+
+static void
+gdu_details_table_constructed (GObject *object)
+{
+ GduDetailsTable *table = GDU_DETAILS_TABLE (object);
+
+ gtk_box_set_homogeneous (GTK_BOX (table), TRUE);
+ gtk_box_set_spacing (GTK_BOX (table), 12);
+
+ if (G_OBJECT_CLASS (gdu_details_table_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (gdu_details_table_parent_class)->constructed (object);
+}
+
+static void
+gdu_details_table_class_init (GduDetailsTableClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GduDetailsTablePrivate));
+
+ gobject_class->get_property = gdu_details_table_get_property;
+ gobject_class->set_property = gdu_details_table_set_property;
+ gobject_class->constructed = gdu_details_table_constructed;
+ gobject_class->finalize = gdu_details_table_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_NUM_COLUMNS,
+ g_param_spec_uint ("num-columns",
+ NULL,
+ NULL,
+ 1,
+ G_MAXUINT,
+ 2,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ELEMENTS,
+ g_param_spec_boxed ("elements",
+ NULL,
+ NULL,
+ G_TYPE_PTR_ARRAY,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+}
+
+GtkWidget *
+gdu_details_table_new (guint num_columns,
+ GPtrArray *elements)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_DETAILS_TABLE,
+ "num-columns", num_columns,
+ "elements", elements,
+ NULL));
+}
+
+guint
+gdu_details_table_get_num_columns (GduDetailsTable *table)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_TABLE (table), 0);
+ return table->priv->num_columns;
+}
+
+GPtrArray *
+gdu_details_table_get_elements (GduDetailsTable *table)
+{
+ g_return_val_if_fail (GDU_IS_DETAILS_TABLE (table), NULL);
+ return table->priv->elements != NULL ? g_ptr_array_ref (table->priv->elements) : NULL;
+}
+
+void
+gdu_details_table_set_num_columns (GduDetailsTable *table,
+ guint num_columns)
+{
+ g_return_if_fail (GDU_IS_DETAILS_TABLE (table));
+ if (table->priv->num_columns != num_columns) {
+ table->priv->num_columns = num_columns;
+ do_relayout (table);
+ g_object_notify (G_OBJECT (table), "num-columns");
+ }
+}
+
+void
+gdu_details_table_set_elements (GduDetailsTable *table,
+ GPtrArray *elements)
+{
+ g_return_if_fail (GDU_IS_DETAILS_TABLE (table));
+ if (table->priv->elements != NULL)
+ g_ptr_array_unref (table->priv->elements);
+ table->priv->elements = elements != NULL ? g_ptr_array_ref (elements) : NULL;
+ do_relayout (table);
+ g_object_notify (G_OBJECT (table), "elements");
+}
+
+typedef struct {
+ GduDetailsElement *element;
+
+ GtkWidget *heading_label;
+ GtkWidget *spinner;
+ GtkWidget *image;
+ GtkWidget *time_label;
+ GtkWidget *label;
+ GtkWidget *action_hyphen_label;
+ GtkWidget *action_label;
+ GtkWidget *progress_bar;
+} ElementData;
+
+static void on_details_element_changed (GduDetailsElement *element,
+ ElementData *data);
+
+static void on_activate_link (GtkLabel *label,
+ const gchar *uri,
+ gpointer user_data);
+
+static void
+element_data_free (ElementData *data)
+{
+ g_signal_handlers_disconnect_by_func (data->element,
+ G_CALLBACK (on_details_element_changed),
+ data);
+ g_object_unref (data->element);
+ g_signal_handlers_disconnect_by_func (data->action_label,
+ G_CALLBACK (on_activate_link),
+ data);
+ g_object_unref (data->action_label);
+ g_free (data);
+}
+
+static void
+on_details_element_changed (GduDetailsElement *element,
+ ElementData *data)
+{
+ gchar *s;
+ GIcon *icon;
+ const gchar *text;
+ const gchar *action_text;
+ const gchar *action_uri;
+ const gchar *action_tooltip;
+ guint64 time;
+ gdouble progress;
+
+ s = g_strdup_printf ("<span fgcolor='#404040'>%s</span>",
+ gdu_details_element_get_heading (element));
+ gtk_label_set_markup (GTK_LABEL (data->heading_label), s);
+ g_free (s);
+
+ text = gdu_details_element_get_text (element);
+ if (text != NULL) {
+ gtk_label_set_markup (GTK_LABEL (data->label), text);
+ gtk_widget_set_no_show_all (data->label, FALSE);
+ gtk_widget_show (data->label);
+ } else {
+ gtk_widget_set_no_show_all (data->label, TRUE);
+ gtk_widget_hide (data->label);
+ }
+
+ time = gdu_details_element_get_time (element);
+ if (time > 0) {
+ GTimeVal time_val;
+ time_val.tv_sec = time;
+ time_val.tv_usec = 0;
+ gdu_time_label_set_time (GDU_TIME_LABEL (data->time_label), &time_val);
+ gtk_widget_set_no_show_all (data->time_label, FALSE);
+ gtk_widget_show (data->time_label);
+ } else {
+ gtk_widget_set_no_show_all (data->time_label, TRUE);
+ gtk_widget_hide (data->time_label);
+ }
+
+ icon = gdu_details_element_get_icon (element);
+ if (icon != NULL) {
+ gtk_image_set_from_gicon (GTK_IMAGE (data->image),
+ icon,
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_set_no_show_all (data->image, FALSE);
+ gtk_widget_show (data->image);
+ g_object_unref (icon);
+ } else {
+ gtk_widget_set_no_show_all (data->image, TRUE);
+ gtk_widget_hide (data->image);
+ }
+
+ action_text = gdu_details_element_get_action_text (element);
+ action_uri = gdu_details_element_get_action_uri (element);
+ action_tooltip = gdu_details_element_get_action_tooltip (element);
+
+ if (action_text != NULL) {
+ s = g_strdup_printf ("<a href=\"%s\" title=\"%s\">%s</a>",
+ action_uri != NULL ? action_uri : "",
+ action_tooltip != NULL ? action_tooltip : "",
+ action_text);
+ gtk_label_set_markup (GTK_LABEL (data->action_label), s);
+ g_free (s);
+ gtk_widget_set_no_show_all (data->action_label, FALSE);
+ gtk_widget_set_no_show_all (data->action_hyphen_label, FALSE);
+ gtk_widget_show (data->action_label);
+ gtk_widget_show (data->action_hyphen_label);
+ } else {
+ gtk_widget_set_no_show_all (data->action_label, TRUE);
+ gtk_widget_set_no_show_all (data->action_hyphen_label, TRUE);
+ gtk_widget_hide (data->action_label);
+ gtk_widget_hide (data->action_hyphen_label);
+ }
+
+ if (gdu_details_element_get_is_spinning (element)) {
+ gdu_spinner_start (GDU_SPINNER (data->spinner));
+ gtk_widget_set_no_show_all (data->spinner, FALSE);
+ gtk_widget_show (data->spinner);
+ } else {
+ gdu_spinner_stop (GDU_SPINNER (data->spinner));
+ gtk_widget_set_no_show_all (data->spinner, TRUE);
+ gtk_widget_hide (data->spinner);
+ }
+
+ progress = gdu_details_element_get_progress (element);
+ if (progress >= 0.0) {
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (data->progress_bar),
+ progress);
+ gtk_widget_set_no_show_all (data->progress_bar, FALSE);
+ gtk_widget_show (data->progress_bar);
+ } else {
+ gtk_widget_set_no_show_all (data->progress_bar, TRUE);
+ gtk_widget_hide (data->progress_bar);
+ }
+}
+
+static void
+on_activate_link (GtkLabel *label,
+ const gchar *uri,
+ gpointer user_data)
+{
+ ElementData *data = user_data;
+
+ g_signal_emit_by_name (data->element, "activated");
+ g_signal_stop_emission_by_name (label, "activate-link");
+}
+
+static void
+do_relayout (GduDetailsTable *table)
+{
+ GList *children;
+ GList *l;
+ guint n;
+ guint row;
+
+ children = gtk_container_get_children (GTK_CONTAINER (table));
+ for (l = children; l != NULL; l = l->next) {
+ gtk_container_remove (GTK_CONTAINER (table), GTK_WIDGET (l->data));
+ }
+ g_list_free (children);
+
+ if (table->priv->column_tables != NULL)
+ g_ptr_array_unref (table->priv->column_tables);
+
+ if (table->priv->element_data_array != NULL)
+ g_ptr_array_unref (table->priv->element_data_array);
+
+ if (table->priv->num_columns == 0 || table->priv->elements == NULL)
+ goto out;
+
+ table->priv->column_tables = g_ptr_array_new_with_free_func (g_object_unref);
+ table->priv->element_data_array = g_ptr_array_new_with_free_func ((GDestroyNotify) element_data_free);
+
+ for (n = 0; n < table->priv->num_columns; n++) {
+ GtkWidget *column_table;
+
+ column_table = gtk_table_new (1, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (column_table), 12);
+ gtk_table_set_row_spacings (GTK_TABLE (column_table), 6);
+ gtk_box_pack_start (GTK_BOX (table),
+ column_table,
+ TRUE,
+ TRUE,
+ 0);
+
+ g_ptr_array_add (table->priv->column_tables, g_object_ref (column_table));
+ }
+
+ row = -1;
+ for (n = 0; n < table->priv->elements->len; n++) {
+ GduDetailsElement *element = GDU_DETAILS_ELEMENT (table->priv->elements->pdata[n]);
+ guint column_table_number;
+ GtkWidget *column_table;
+ ElementData *data;
+ GtkWidget *hbox;
+
+ column_table_number = n % table->priv->num_columns;
+ if (column_table_number == 0)
+ row++;
+ column_table = table->priv->column_tables->pdata[column_table_number];
+
+ data = g_new0 (ElementData, 1);
+ data->element = g_object_ref (element);
+
+ data->heading_label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (data->heading_label), 0.0, 0.5);
+ gtk_table_attach (GTK_TABLE (column_table),
+ data->heading_label,
+ 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+
+ data->image = gtk_image_new_from_stock ("gtk-missing-image",
+ GTK_ICON_SIZE_MENU);
+ gtk_box_pack_start (GTK_BOX (hbox), data->image, FALSE, FALSE, 0);
+
+ data->spinner = gdu_spinner_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), data->spinner, FALSE, FALSE, 0);
+
+ data->label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (data->label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), data->label, FALSE, FALSE, 0);
+
+ data->time_label = gdu_time_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (data->time_label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), data->time_label, FALSE, FALSE, 0);
+
+ data->progress_bar = gtk_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), data->progress_bar, FALSE, FALSE, 0);
+
+ data->action_hyphen_label = gtk_label_new (" â?? ");
+ gtk_misc_set_alignment (GTK_MISC (data->action_hyphen_label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), data->action_hyphen_label, FALSE, FALSE, 0);
+
+ data->action_label = g_object_ref (gtk_label_new (NULL));
+ gtk_misc_set_alignment (GTK_MISC (data->action_label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), data->action_label, FALSE, FALSE, 0);
+
+ gtk_table_attach (GTK_TABLE (column_table),
+ hbox,
+ 1, 2, row, row + 1,
+ GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+
+ g_ptr_array_add (table->priv->element_data_array, data);
+
+ g_signal_connect (element,
+ "changed",
+ G_CALLBACK (on_details_element_changed),
+ data);
+ g_signal_connect (data->action_label,
+ "activate-link",
+ G_CALLBACK (on_activate_link),
+ data);
+ on_details_element_changed (element, data);
+ }
+ gtk_widget_show_all (GTK_WIDGET (table));
+
+ out:
+ ;
+}
diff --git a/src/gdu-gtk/gdu-details-table.h b/src/gdu-gtk/gdu-details-table.h
new file mode 100644
index 0000000..45fe3ce
--- /dev/null
+++ b/src/gdu-gtk/gdu-details-table.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GDU_DETAILS_TABLE_H
+#define __GDU_DETAILS_TABLE_H
+
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_DETAILS_TABLE (gdu_details_table_get_type())
+#define GDU_DETAILS_TABLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_DETAILS_TABLE, GduDetailsTable))
+#define GDU_DETAILS_TABLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_DETAILS_TABLE, GduDetailsTableClass))
+#define GDU_IS_DETAILS_TABLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_DETAILS_TABLE))
+#define GDU_IS_DETAILS_TABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_DETAILS_TABLE))
+#define GDU_DETAILS_TABLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_DETAILS_TABLE, GduDetailsTableClass))
+
+typedef struct GduDetailsTableClass GduDetailsTableClass;
+typedef struct GduDetailsTablePrivate GduDetailsTablePrivate;
+
+struct GduDetailsTable
+{
+ GtkHBox parent;
+
+ /*< private >*/
+ GduDetailsTablePrivate *priv;
+};
+
+struct GduDetailsTableClass
+{
+ GtkHBoxClass parent_class;
+};
+
+GType gdu_details_table_get_type (void) G_GNUC_CONST;
+GtkWidget* gdu_details_table_new (guint num_columns,
+ GPtrArray *elements);
+guint gdu_details_table_get_num_columns (GduDetailsTable *table);
+GPtrArray *gdu_details_table_get_elements (GduDetailsTable *table);
+void gdu_details_table_set_num_columns (GduDetailsTable *table,
+ guint num_columns);
+void gdu_details_table_set_elements (GduDetailsTable *table,
+ GPtrArray *elements);
+
+G_END_DECLS
+
+#endif /* __GDU_DETAILS_TABLE_H */
+
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index fca5641..cb6c740 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -40,18 +40,13 @@ typedef struct GduGraph GduGraph;
typedef struct GduTimeLabel GduTimeLabel;
typedef struct GduAtaSmartDialog GduAtaSmartDialog;
typedef struct GduSpinner GduSpinner;
-
-struct GduPoolTreeModel;
-typedef struct GduPoolTreeModel GduPoolTreeModel;
-
-struct GduPoolTreeView;
-typedef struct GduPoolTreeView GduPoolTreeView;
-
-struct GduCreateLinuxMdDialog;
-typedef struct GduCreateLinuxMdDialog GduCreateLinuxMdDialog;
-
-struct GduSizeWidget;
-typedef struct GduSizeWidget GduSizeWidget;
+typedef struct GduPoolTreeModel GduPoolTreeModel;
+typedef struct GduPoolTreeView GduPoolTreeView;
+typedef struct GduCreateLinuxMdDialog GduCreateLinuxMdDialog;
+typedef struct GduSizeWidget GduSizeWidget;
+typedef struct GduVolumeGrid GduVolumeGrid;
+typedef struct GduDetailsTable GduDetailsTable;
+typedef struct GduDetailsElement GduDetailsElement;
G_END_DECLS
diff --git a/src/gdu-gtk/gdu-gtk.h b/src/gdu-gtk/gdu-gtk.h
index dccb785..89bce01 100644
--- a/src/gdu-gtk/gdu-gtk.h
+++ b/src/gdu-gtk/gdu-gtk.h
@@ -36,6 +36,9 @@
#include <gdu-gtk/gdu-create-linux-md-dialog.h>
#include <gdu-gtk/gdu-ata-smart-dialog.h>
#include <gdu-gtk/gdu-spinner.h>
+#include <gdu-gtk/gdu-volume-grid.h>
+#include <gdu-gtk/gdu-details-table.h>
+#include <gdu-gtk/gdu-details-element.h>
#undef __GDU_GTK_INSIDE_GDU_GTK_H
G_BEGIN_DECLS
diff --git a/src/gdu-gtk/gdu-pool-tree-model.c b/src/gdu-gtk/gdu-pool-tree-model.c
index a53d0e4..cc554b8 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;
+ GduPresentable *root;
GduPoolTreeModelFlags flags;
};
@@ -38,6 +39,7 @@ G_DEFINE_TYPE (GduPoolTreeModel, gdu_pool_tree_model, GTK_TYPE_TREE_STORE)
enum
{
PROP_0,
+ PROP_ROOT,
PROP_POOL,
PROP_FLAGS,
};
@@ -72,6 +74,11 @@ gdu_pool_tree_model_set_property (GObject *object,
model->priv->pool = g_value_dup_object (value);
break;
+ case PROP_ROOT:
+ if (g_value_get_object (value) != NULL)
+ model->priv->root = g_value_dup_object (value);
+ break;
+
case PROP_FLAGS:
model->priv->flags = g_value_get_flags (value);
break;
@@ -95,6 +102,10 @@ gdu_pool_tree_model_get_property (GObject *object,
g_value_set_object (value, model->priv->pool);
break;
+ case PROP_ROOT:
+ g_value_set_object (value, model->priv->root);
+ break;
+
case PROP_FLAGS:
g_value_set_flags (value, model->priv->flags);
break;
@@ -235,6 +246,22 @@ gdu_pool_tree_model_class_init (GduPoolTreeModelClass *klass)
G_PARAM_CONSTRUCT_ONLY));
/**
+ * GduPoolTreeModel:root:
+ *
+ * %NULL to include all #GduPresentable objects in #GduPoolTreeModel:pool, otherwise only
+ * include presentables that are descendents of this #GduPresentable.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ROOT,
+ g_param_spec_object ("root",
+ NULL,
+ NULL,
+ GDU_TYPE_PRESENTABLE,
+ G_PARAM_WRITABLE |
+ G_PARAM_READABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ /**
* GduPoolTreeModel:flags:
*
* The flags for the model.
@@ -259,10 +286,12 @@ gdu_pool_tree_model_init (GduPoolTreeModel *model)
GduPoolTreeModel *
gdu_pool_tree_model_new (GduPool *pool,
+ GduPresentable *root,
GduPoolTreeModelFlags flags)
{
return GDU_POOL_TREE_MODEL (g_object_new (GDU_TYPE_POOL_TREE_MODEL,
"pool", pool,
+ "root", root,
"flags", flags,
NULL));
}
@@ -381,6 +410,34 @@ should_include_presentable (GduPoolTreeModel *model,
(GDU_IS_VOLUME (presentable) || GDU_IS_VOLUME_HOLE (presentable)))
goto out;
+ if (model->priv->root != NULL) {
+ gboolean is_enclosed_by_root;
+ GduPresentable *p_iter;
+
+ is_enclosed_by_root = FALSE;
+ p_iter = g_object_ref (presentable);
+ do {
+ GduPresentable *p;
+
+ p = gdu_presentable_get_enclosing_presentable (p_iter);
+ g_object_unref (p_iter);
+ if (p == NULL)
+ break;
+
+ if (p == model->priv->root) {
+ is_enclosed_by_root = TRUE;
+ g_object_unref (p);
+ break;
+ }
+
+ p_iter = p;
+
+ } while (TRUE);
+
+ if (!is_enclosed_by_root)
+ 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)))
@@ -418,10 +475,14 @@ add_presentable (GduPoolTreeModel *model,
if (gdu_pool_tree_model_get_iter_for_presentable (model, enclosing_presentable, &iter2)) {
parent_iter = &iter2;
} else {
- /* add parent if it's not already added */
- g_warning ("No parent for %s", gdu_presentable_get_id (enclosing_presentable));
- add_presentable (model, enclosing_presentable, &iter2);
- parent_iter = &iter2;
+ if (should_include_presentable (model, enclosing_presentable)) {
+ /* add parent if it's not already added */
+ g_warning ("No parent for %s", gdu_presentable_get_id (enclosing_presentable));
+ add_presentable (model, enclosing_presentable, &iter2);
+ parent_iter = &iter2;
+ } else {
+ /* parent explicitly excluded */
+ }
}
g_object_unref (enclosing_presentable);
}
diff --git a/src/gdu-gtk/gdu-pool-tree-model.h b/src/gdu-gtk/gdu-pool-tree-model.h
index 970fa5c..81a016c 100644
--- a/src/gdu-gtk/gdu-pool-tree-model.h
+++ b/src/gdu-gtk/gdu-pool-tree-model.h
@@ -55,6 +55,7 @@ struct GduPoolTreeModelClass
GType gdu_pool_tree_model_get_type (void) G_GNUC_CONST;
GduPoolTreeModel *gdu_pool_tree_model_new (GduPool *pool,
+ GduPresentable *root,
GduPoolTreeModelFlags flags);
gboolean gdu_pool_tree_model_get_iter_for_presentable (GduPoolTreeModel *model,
GduPresentable *presentable,
diff --git a/src/gdu-gtk/gdu-size-widget.c b/src/gdu-gtk/gdu-size-widget.c
index 6ed770a..20bced3 100644
--- a/src/gdu-gtk/gdu-size-widget.c
+++ b/src/gdu-gtk/gdu-size-widget.c
@@ -127,7 +127,7 @@ on_hscale_format_value (GtkScale *scale,
{
gchar *ret;
- ret = gdu_util_get_size_for_display ((guint64 ) value, FALSE);
+ ret = gdu_util_get_size_for_display ((guint64 ) value, FALSE, FALSE);
return ret;
}
@@ -175,7 +175,7 @@ on_query_tooltip (GtkWidget *w,
gchar *s;
gchar *s1;
- s1 = gdu_util_get_size_for_display (widget->priv->size, TRUE);
+ s1 = gdu_util_get_size_for_display (widget->priv->size, FALSE, TRUE);
/* TODO: handle this use-case
s = g_strdup_printf ("<b>%s</b>\n"
"\n"
diff --git a/src/gdu-gtk/gdu-volume-grid.c b/src/gdu-gtk/gdu-volume-grid.c
new file mode 100644
index 0000000..4a72223
--- /dev/null
+++ b/src/gdu-gtk/gdu-volume-grid.c
@@ -0,0 +1,1321 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-volume-grid.c
+ *
+ * Copyright (C) 2009 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <math.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <X11/XKBlib.h>
+
+#include <gdu-gtk/gdu-gtk.h>
+
+#include "gdu-volume-grid.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef enum
+{
+ GRID_EDGE_NONE = 0,
+ GRID_EDGE_TOP = (1<<0),
+ GRID_EDGE_BOTTOM = (1<<1),
+ GRID_EDGE_LEFT = (1<<2),
+ GRID_EDGE_RIGHT = (1<<3)
+} GridEdgeFlags;
+
+typedef struct GridElement GridElement;
+
+struct GridElement
+{
+ /* these values are set in recompute_grid() */
+ gdouble size_ratio;
+ GduPresentable *presentable; /* if NULL, it means no media is available */
+ GList *embedded_elements;
+ GridElement *parent;
+ GridElement *prev;
+ GridElement *next;
+
+ /* these values are set in recompute_size() */
+ gint x;
+ gint y;
+ gint width;
+ gint height;
+ GridEdgeFlags edge_flags;
+};
+
+static void
+grid_element_free (GridElement *element)
+{
+ if (element->presentable != NULL)
+ g_object_unref (element->presentable);
+
+ g_list_foreach (element->embedded_elements, (GFunc) grid_element_free, NULL);
+ g_list_free (element->embedded_elements);
+
+ g_free (element);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+struct GduVolumeGridPrivate
+{
+ GduPool *pool;
+ GduDrive *drive;
+ GduDevice *device;
+
+ GList *elements;
+
+ GridElement *selected;
+ GridElement *focused;
+};
+
+enum
+{
+ PROP_0,
+ PROP_DRIVE,
+};
+
+enum
+{
+ CHANGED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE (GduVolumeGrid, gdu_volume_grid, GTK_TYPE_DRAWING_AREA)
+
+static void recompute_grid (GduVolumeGrid *grid);
+
+static void recompute_size (GduVolumeGrid *grid,
+ gint width,
+ gint height);
+
+static GridElement *find_element_for_presentable (GduVolumeGrid *grid,
+ GduPresentable *presentable);
+
+static GridElement *find_element_for_position (GduVolumeGrid *grid,
+ gint x,
+ gint y);
+
+static gboolean gdu_volume_grid_expose_event (GtkWidget *widget,
+ GdkEventExpose *event);
+
+static void on_presentable_added (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data);
+static void on_presentable_removed (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data);
+static void on_presentable_changed (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data);
+static void on_presentable_job_changed (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data);
+
+static void
+gdu_volume_grid_finalize (GObject *object)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (object);
+
+ g_list_foreach (grid->priv->elements, (GFunc) grid_element_free, NULL);
+ g_list_free (grid->priv->elements);
+
+ g_object_unref (grid->priv->drive);
+ if (grid->priv->device != NULL)
+ g_object_unref (grid->priv->device);
+
+ g_signal_handlers_disconnect_by_func (grid->priv->pool,
+ on_presentable_added,
+ grid);
+ g_signal_handlers_disconnect_by_func (grid->priv->pool,
+ on_presentable_removed,
+ grid);
+ g_signal_handlers_disconnect_by_func (grid->priv->pool,
+ on_presentable_changed,
+ grid);
+ g_signal_handlers_disconnect_by_func (grid->priv->pool,
+ on_presentable_job_changed,
+ grid);
+ g_object_unref (grid->priv->pool);
+
+ if (G_OBJECT_CLASS (gdu_volume_grid_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_volume_grid_parent_class)->finalize (object);
+}
+
+static void
+gdu_volume_grid_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (object);
+
+ switch (property_id) {
+ case PROP_DRIVE:
+ g_value_set_object (value, grid->priv->drive);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdu_volume_grid_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (object);
+
+ switch (property_id) {
+ case PROP_DRIVE:
+ grid->priv->drive = GDU_DRIVE (g_value_dup_object (value));
+ grid->priv->pool = gdu_presentable_get_pool (GDU_PRESENTABLE (grid->priv->drive));
+ grid->priv->device = gdu_presentable_get_device (GDU_PRESENTABLE (grid->priv->drive));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdu_volume_grid_constructed (GObject *object)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (object);
+
+ gtk_widget_set_size_request (GTK_WIDGET (grid),
+ -1,
+ 100);
+
+ g_signal_connect (grid->priv->pool,
+ "presentable-added",
+ G_CALLBACK (on_presentable_added),
+ grid);
+ g_signal_connect (grid->priv->pool,
+ "presentable-removed",
+ G_CALLBACK (on_presentable_removed),
+ grid);
+ g_signal_connect (grid->priv->pool,
+ "presentable-changed",
+ G_CALLBACK (on_presentable_changed),
+ grid);
+ g_signal_connect (grid->priv->pool,
+ "presentable-job-changed",
+ G_CALLBACK (on_presentable_job_changed),
+ grid);
+
+ recompute_grid (grid);
+
+ /* select the first element */
+ if (grid->priv->elements != NULL) {
+ GridElement *element = grid->priv->elements->data;
+ grid->priv->selected = element;
+ grid->priv->focused = element;
+ }
+
+ if (G_OBJECT_CLASS (gdu_volume_grid_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (gdu_volume_grid_parent_class)->constructed (object);
+}
+
+static gboolean
+is_ctrl_pressed (void)
+{
+ gboolean ret;
+ XkbStateRec state;
+ Bool status;
+
+ ret = FALSE;
+
+ gdk_error_trap_push ();
+ status = XkbGetState (GDK_DISPLAY (), XkbUseCoreKbd, &state);
+ gdk_error_trap_pop ();
+
+ if (status == Success) {
+ ret = ((state.mods & ControlMask) != 0);
+ }
+
+ return ret;
+}
+
+static gboolean
+gdu_volume_grid_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (widget);
+ gboolean handled;
+ GridElement *target;
+
+ handled = FALSE;
+
+ if (event->type != GDK_KEY_PRESS)
+ goto out;
+
+ switch (event->keyval) {
+ case GDK_Left:
+ case GDK_Right:
+ case GDK_Up:
+ case GDK_Down:
+ target = NULL;
+
+ if (grid->priv->focused == NULL) {
+ g_warning ("TODO: handle nothing being selected/focused");
+ } else {
+ GridElement *element;
+
+ element = grid->priv->focused;
+ if (element != NULL) {
+ if (event->keyval == GDK_Left) {
+ if (element->prev != NULL) {
+ target = element->prev;
+ } else {
+ if (element->parent && element->parent->prev != NULL)
+ target = element->parent->prev;
+ }
+ } else if (event->keyval == GDK_Right) {
+ if (element->next != NULL) {
+ target = element->next;
+ } else {
+ if (element->parent && element->parent->next != NULL)
+ target = element->parent->next;
+ }
+ } else if (event->keyval == GDK_Up) {
+ if (element->parent != NULL) {
+ target = element->parent;
+ }
+ } else if (event->keyval == GDK_Down) {
+ if (element->embedded_elements != NULL) {
+ target = (GridElement *) element->embedded_elements->data;
+ }
+ }
+ }
+ }
+
+ if (target != NULL) {
+ if (is_ctrl_pressed ()) {
+ grid->priv->focused = target;
+ } else {
+ grid->priv->selected = target;
+ grid->priv->focused = target;
+ g_signal_emit (grid,
+ signals[CHANGED_SIGNAL],
+ 0);
+ }
+ gtk_widget_queue_draw (GTK_WIDGET (grid));
+ }
+ handled = TRUE;
+ break;
+
+ case GDK_Return:
+ case GDK_space:
+ if (grid->priv->focused != grid->priv->selected &&
+ grid->priv->focused != NULL) {
+ grid->priv->selected = grid->priv->focused;
+ g_signal_emit (grid,
+ signals[CHANGED_SIGNAL],
+ 0);
+ gtk_widget_queue_draw (GTK_WIDGET (grid));
+ }
+
+ handled = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ out:
+ return handled;
+}
+
+static gboolean
+gdu_volume_grid_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (widget);
+ gboolean handled;
+
+ handled = FALSE;
+
+ if (event->type != GDK_BUTTON_PRESS)
+ goto out;
+
+ if (event->button == 1) {
+ GridElement *element;
+
+ element = find_element_for_position (grid, event->x, event->y);
+ if (element != NULL) {
+ grid->priv->selected = element;
+ grid->priv->focused = element;
+
+ g_signal_emit (grid,
+ signals[CHANGED_SIGNAL],
+ 0);
+
+ gtk_widget_grab_focus (GTK_WIDGET (grid));
+ gtk_widget_queue_draw (GTK_WIDGET (grid));
+ }
+
+ handled = TRUE;
+ }
+
+ out:
+ return handled;
+}
+
+static void
+gdu_volume_grid_realize (GtkWidget *widget)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (widget);
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask = gtk_widget_get_events (widget) |
+ GDK_KEY_PRESS_MASK |
+ GDK_EXPOSURE_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ widget->window = gtk_widget_get_parent_window (widget);
+ g_object_ref (widget->window);
+
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes,
+ attributes_mask);
+ gdk_window_set_user_data (widget->window, grid);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+}
+
+
+static void
+gdu_volume_grid_class_init (GduVolumeGridClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GduVolumeGridPrivate));
+
+ object_class->get_property = gdu_volume_grid_get_property;
+ object_class->set_property = gdu_volume_grid_set_property;
+ object_class->constructed = gdu_volume_grid_constructed;
+ object_class->finalize = gdu_volume_grid_finalize;
+
+ widget_class->realize = gdu_volume_grid_realize;
+ widget_class->key_press_event = gdu_volume_grid_key_press_event;
+ widget_class->button_press_event = gdu_volume_grid_button_press_event;
+ widget_class->expose_event = gdu_volume_grid_expose_event;
+
+ g_object_class_install_property (object_class,
+ PROP_DRIVE,
+ g_param_spec_object ("drive",
+ _("Drive"),
+ _("Drive to show volumes for"),
+ GDU_TYPE_DRIVE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+ GDU_TYPE_VOLUME_GRID,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GduVolumeGridClass, changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+gdu_volume_grid_init (GduVolumeGrid *grid)
+{
+ grid->priv = G_TYPE_INSTANCE_GET_PRIVATE (grid, GDU_TYPE_VOLUME_GRID, GduVolumeGridPrivate);
+
+ GTK_WIDGET_SET_FLAGS (grid, GTK_CAN_FOCUS);
+}
+
+GtkWidget *
+gdu_volume_grid_new (GduDrive *drive)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_VOLUME_GRID,
+ "drive", drive,
+ NULL));
+}
+
+static gint
+presentable_sort_offset (GduPresentable *a, GduPresentable *b)
+{
+ guint64 oa, ob;
+
+ oa = gdu_presentable_get_offset (a);
+ ob = gdu_presentable_get_offset (b);
+
+ if (oa < ob)
+ return -1;
+ else if (oa > ob)
+ return 1;
+ else
+ return 0;
+}
+
+static void
+recompute_size (GduVolumeGrid *grid,
+ gint width,
+ gint height)
+{
+ GList *l;
+ gint x;
+ gint pixels_left;
+
+ x = 0;
+ pixels_left = width;
+ for (l = grid->priv->elements; l != NULL; l = l->next) {
+ GridElement *element = l->data;
+ gint element_width;
+ gboolean is_first;
+ gboolean is_last;
+
+ is_first = (l == grid->priv->elements);
+ is_last = (l->next == NULL);
+
+ if (is_last) {
+ element_width = pixels_left;
+ pixels_left = 0;
+ } else {
+ element_width = element->size_ratio * width;
+ if (element_width > pixels_left)
+ element_width = pixels_left;
+ pixels_left -= element_width;
+ }
+
+ element->x = x;
+ element->y = 0;
+ element->width = element_width;
+ element->height = height;
+ element->edge_flags = GRID_EDGE_TOP | GRID_EDGE_BOTTOM;
+ if (is_first)
+ element->edge_flags |= GRID_EDGE_LEFT;
+ if (is_last)
+ element->edge_flags |= GRID_EDGE_RIGHT;
+
+ x += element_width;
+
+ /* for now we don't recurse - we only handle embedded element for toplevel elements */
+ if (element->embedded_elements != NULL) {
+ gint e_x;
+ gint e_width;
+ gint e_pixels_left;
+ GList *ll;
+
+ element->height = height/3;
+ element->edge_flags &= ~(GRID_EDGE_BOTTOM);
+
+ e_x = element->x;
+ e_width = element->width;
+ e_pixels_left = e_width;
+ for (ll = element->embedded_elements; ll != NULL; ll = ll->next) {
+ GridElement *e_element = ll->data;
+ gint e_element_width;
+ gboolean e_is_first;
+ gboolean e_is_last;
+
+ e_is_first = (ll == element->embedded_elements);
+ e_is_last = (ll->next == NULL);
+
+ if (e_is_last) {
+ e_element_width = e_pixels_left;
+ e_pixels_left = 0;
+ } else {
+ e_element_width = e_element->size_ratio * e_width;
+ if (e_element_width > e_pixels_left)
+ element_width = e_pixels_left;
+ e_pixels_left -= e_element_width;
+ }
+
+ e_element->x = e_x;
+ e_element->y = element->height;
+ e_element->width = e_element_width;
+ e_element->height = height - e_element->y;
+ e_element->edge_flags = GRID_EDGE_BOTTOM;
+ if (is_first && e_is_first)
+ e_element->edge_flags |= GRID_EDGE_LEFT;
+ if (is_last && e_is_last)
+ e_element->edge_flags |= GRID_EDGE_RIGHT;
+
+ e_x += e_element_width;
+
+ }
+ }
+ }
+}
+
+static void
+recompute_grid (GduVolumeGrid *grid)
+{
+ GduPresentable *cur_selected_presentable;
+ GduPresentable *cur_focused_presentable;
+ GList *enclosed_partitions;
+ GList *l;
+ guint64 size;
+ GridElement *element;
+ GridElement *prev_element;
+
+ cur_selected_presentable = NULL;
+ cur_focused_presentable = NULL;
+
+ if (grid->priv->selected != NULL && grid->priv->selected->presentable != NULL)
+ cur_selected_presentable = g_object_ref (grid->priv->selected->presentable);
+
+ if (grid->priv->focused != NULL && grid->priv->focused->presentable != NULL)
+ cur_focused_presentable = g_object_ref (grid->priv->focused->presentable);
+
+ /* first delete old elements */
+ g_list_foreach (grid->priv->elements, (GFunc) grid_element_free, NULL);
+ g_list_free (grid->priv->elements);
+ grid->priv->elements = NULL;
+
+ /* then add new elements */
+ size = gdu_presentable_get_size (GDU_PRESENTABLE (grid->priv->drive));
+ enclosed_partitions = gdu_pool_get_enclosed_presentables (grid->priv->pool,
+ GDU_PRESENTABLE (grid->priv->drive));
+ enclosed_partitions = g_list_sort (enclosed_partitions, (GCompareFunc) presentable_sort_offset);
+ prev_element = NULL;
+ for (l = enclosed_partitions; l != NULL; l = l->next) {
+ GduPresentable *ep = GDU_PRESENTABLE (l->data);
+ GduDevice *ed;
+ guint64 psize;
+
+ ed = gdu_presentable_get_device (ep);
+
+ psize = gdu_presentable_get_size (ep);
+
+ element = g_new0 (GridElement, 1);
+ element->size_ratio = ((gdouble) psize) / size;
+ element->presentable = g_object_ref (ep);
+ element->prev = prev_element;
+ if (prev_element != NULL)
+ prev_element->next = element;
+ prev_element = element;
+
+ grid->priv->elements = g_list_append (grid->priv->elements, element);
+
+ if (ed != NULL && gdu_device_is_partition (ed) &&
+ (g_strcmp0 (gdu_device_partition_get_type (ed), "0x05") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (ed), "0x0f") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (ed), "0x85") == 0)) {
+ GList *enclosed_logical_partitions;
+ GList *ll;
+ GridElement *logical_element;
+ GridElement *logical_prev_element;
+
+ enclosed_logical_partitions = gdu_pool_get_enclosed_presentables (grid->priv->pool, ep);
+ logical_prev_element = NULL;
+ for (ll = enclosed_logical_partitions; ll != NULL; ll = ll->next) {
+ GduPresentable *logical_ep = GDU_PRESENTABLE (ll->data);
+ guint64 lsize;
+
+ lsize = gdu_presentable_get_size (logical_ep);
+
+ logical_element = g_new0 (GridElement, 1);
+ logical_element->size_ratio = ((gdouble) lsize) / psize;
+ logical_element->presentable = g_object_ref (logical_ep);
+ logical_element->parent = element;
+ logical_element->prev = logical_prev_element;
+ if (logical_prev_element != NULL)
+ logical_prev_element->next = logical_element;
+ logical_prev_element = logical_element;
+
+ element->embedded_elements = g_list_append (element->embedded_elements,
+ logical_element);
+ }
+ g_list_foreach (enclosed_logical_partitions, (GFunc) g_object_unref, NULL);
+ g_list_free (enclosed_logical_partitions);
+ }
+ if (ed != NULL)
+ g_object_unref (ed);
+
+ }
+ g_list_foreach (enclosed_partitions, (GFunc) g_object_unref, NULL);
+ g_list_free (enclosed_partitions);
+
+ /* If we have no elements, then make up an element with a NULL presentable - this is to handle
+ * the "No Media Inserted" case.
+ */
+ if (grid->priv->elements == NULL) {
+ element = g_new0 (GridElement, 1);
+ element->size_ratio = 1.0;
+ grid->priv->elements = g_list_append (grid->priv->elements, element);
+ }
+
+ /* reselect focused and selected elements */
+ grid->priv->focused = NULL;
+ if (cur_focused_presentable != NULL) {
+ grid->priv->focused = find_element_for_presentable (grid, cur_focused_presentable);
+ g_object_unref (cur_focused_presentable);
+ }
+ grid->priv->selected = NULL;
+ if (cur_selected_presentable != NULL) {
+ grid->priv->selected = find_element_for_presentable (grid, cur_selected_presentable);
+ g_object_unref (cur_selected_presentable);
+ }
+
+ /* ensure something is always focused/selected */
+ if ( grid->priv->focused == NULL) {
+ grid->priv->focused = grid->priv->elements->data;
+ }
+ if (grid->priv->selected == NULL) {
+ grid->priv->selected = grid->priv->focused;
+ }
+
+ /* queue a redraw */
+ gtk_widget_queue_draw (GTK_WIDGET (grid));
+}
+
+static void
+round_rect (cairo_t *cr,
+ gdouble x, gdouble y,
+ gdouble w, gdouble h,
+ gdouble r,
+ GridEdgeFlags edge_flags)
+{
+ gboolean top_left_round;
+ gboolean top_right_round;
+ gboolean bottom_right_round;
+ gboolean bottom_left_round;
+
+ top_left_round = ((edge_flags & GRID_EDGE_TOP) && (edge_flags & GRID_EDGE_LEFT));
+ top_right_round = ((edge_flags & GRID_EDGE_TOP) && (edge_flags & GRID_EDGE_RIGHT));
+ bottom_right_round = ((edge_flags & GRID_EDGE_BOTTOM) && (edge_flags & GRID_EDGE_RIGHT));
+ bottom_left_round = ((edge_flags & GRID_EDGE_BOTTOM) && (edge_flags & GRID_EDGE_LEFT));
+
+ if (top_left_round) {
+ cairo_move_to (cr,
+ x + r, y);
+ } else {
+ cairo_move_to (cr,
+ x, y);
+ }
+
+ if (top_right_round) {
+ cairo_line_to (cr,
+ x + w - r, y);
+ cairo_curve_to (cr,
+ x + w, y,
+ x + w, y,
+ x + w, y + r);
+ } else {
+ cairo_line_to (cr,
+ x + w, y);
+ }
+
+ if (bottom_right_round) {
+ cairo_line_to (cr,
+ x + w, y + h - r);
+ cairo_curve_to (cr,
+ x + w, y + h,
+ x + w, y + h,
+ x + w - r, y + h);
+ } else {
+ cairo_line_to (cr,
+ x + w, y + h);
+ }
+
+ if (bottom_left_round) {
+ cairo_line_to (cr,
+ x + r, y + h);
+ cairo_curve_to (cr,
+ x, y + h,
+ x, y + h,
+ x, y + h - r);
+ } else {
+ cairo_line_to (cr,
+ x, y + h);
+ }
+
+ if (top_left_round) {
+ cairo_line_to (cr,
+ x, y + r);
+ cairo_curve_to (cr,
+ x, y,
+ x, y,
+ x + r, y);
+ } else {
+ cairo_line_to (cr,
+ x, y);
+ }
+}
+
+static void
+render_element (GduVolumeGrid *grid,
+ cairo_t *cr,
+ GridElement *element,
+ gboolean is_selected,
+ gboolean is_focused,
+ gboolean is_grid_focused)
+{
+ gdouble fill_red;
+ gdouble fill_green;
+ gdouble fill_blue;
+ gdouble fill_selected_red;
+ gdouble fill_selected_green;
+ gdouble fill_selected_blue;
+ gdouble fill_selected_not_focused_red;
+ gdouble fill_selected_not_focused_green;
+ gdouble fill_selected_not_focused_blue;
+ gdouble focus_rect_red;
+ gdouble focus_rect_green;
+ gdouble focus_rect_blue;
+ gdouble focus_rect_selected_red;
+ gdouble focus_rect_selected_green;
+ gdouble focus_rect_selected_blue;
+ gdouble focus_rect_selected_not_focused_red;
+ gdouble focus_rect_selected_not_focused_green;
+ gdouble focus_rect_selected_not_focused_blue;
+ gdouble stroke_red;
+ gdouble stroke_green;
+ gdouble stroke_blue;
+ gdouble stroke_selected_red;
+ gdouble stroke_selected_green;
+ gdouble stroke_selected_blue;
+ gdouble stroke_selected_not_focused_red;
+ gdouble stroke_selected_not_focused_green;
+ gdouble stroke_selected_not_focused_blue;
+ gdouble text_red;
+ gdouble text_green;
+ gdouble text_blue;
+ gdouble text_selected_red;
+ gdouble text_selected_green;
+ gdouble text_selected_blue;
+ gdouble text_selected_not_focused_red;
+ gdouble text_selected_not_focused_green;
+ gdouble text_selected_not_focused_blue;
+
+ fill_red = 1;
+ fill_green = 1;
+ fill_blue = 1;
+ fill_selected_red = 0.40;
+ fill_selected_green = 0.60;
+ fill_selected_blue = 0.80;
+ fill_selected_not_focused_red = 0.60;
+ fill_selected_not_focused_green = 0.60;
+ fill_selected_not_focused_blue = 0.60;
+ focus_rect_red = 0.75;
+ focus_rect_green = 0.75;
+ focus_rect_blue = 0.75;
+ focus_rect_selected_red = 0.70;
+ focus_rect_selected_green = 0.70;
+ focus_rect_selected_blue = 0.80;
+ focus_rect_selected_not_focused_red = 0.70;
+ focus_rect_selected_not_focused_green = 0.70;
+ focus_rect_selected_not_focused_blue = 0.70;
+ stroke_red = 0.75;
+ stroke_green = 0.75;
+ stroke_blue = 0.75;
+ stroke_selected_red = 0.3;
+ stroke_selected_green = 0.45;
+ stroke_selected_blue = 0.6;
+ stroke_selected_not_focused_red = 0.45;
+ stroke_selected_not_focused_green = 0.45;
+ stroke_selected_not_focused_blue = 0.45;
+ text_red = 0;
+ text_green = 0;
+ text_blue = 0;
+ text_selected_red = 1;
+ text_selected_green = 1;
+ text_selected_blue = 1;
+ text_selected_not_focused_red = 1;
+ text_selected_not_focused_green = 1;
+ text_selected_not_focused_blue = 1;
+
+#if 0
+ g_debug ("rendering element: x=%d w=%d",
+ element->x,
+ element->width);
+#endif
+
+ cairo_save (cr);
+ cairo_rectangle (cr,
+ element->x + 0.5,
+ element->y + 0.5,
+ element->width,
+ element->height);
+ cairo_clip (cr);
+
+ round_rect (cr,
+ element->x + 0.5,
+ element->y + 0.5,
+ element->width,
+ element->height,
+ 10,
+ element->edge_flags);
+
+ if (is_selected) {
+ cairo_pattern_t *gradient;
+ gradient = cairo_pattern_create_radial (element->x + element->width / 2,
+ element->y + element->height / 2,
+ 0.0,
+ element->x + element->width / 2,
+ element->y + element->height / 2,
+ element->width/2.0);
+ if (is_grid_focused) {
+ cairo_pattern_add_color_stop_rgb (gradient,
+ 0.0,
+ 1.0 * fill_selected_red,
+ 1.0 * fill_selected_green,
+ 1.0 * fill_selected_blue);
+ cairo_pattern_add_color_stop_rgb (gradient,
+ 1.0,
+ 0.8 * fill_selected_red,
+ 0.8 * fill_selected_green,
+ 0.8 * fill_selected_blue);
+ } else {
+ cairo_pattern_add_color_stop_rgb (gradient,
+ 0.0,
+ 1.0 * fill_selected_not_focused_red,
+ 1.0 * fill_selected_not_focused_green,
+ 1.0 * fill_selected_not_focused_blue);
+ cairo_pattern_add_color_stop_rgb (gradient,
+ 1.0,
+ 0.8 * fill_selected_not_focused_red,
+ 0.8 * fill_selected_not_focused_green,
+ 0.8 * fill_selected_not_focused_blue);
+ }
+ cairo_set_source (cr, gradient);
+ cairo_pattern_destroy (gradient);
+ } else {
+ cairo_set_source_rgb (cr,
+ fill_red,
+ fill_green,
+ fill_blue);
+ }
+ cairo_fill_preserve (cr);
+ if (is_selected) {
+ if (is_grid_focused) {
+ cairo_set_source_rgb (cr,
+ stroke_selected_red,
+ stroke_selected_green,
+ stroke_selected_blue);
+ } else {
+ cairo_set_source_rgb (cr,
+ stroke_selected_not_focused_red,
+ stroke_selected_not_focused_green,
+ stroke_selected_not_focused_blue);
+ }
+ } else {
+ cairo_set_source_rgb (cr,
+ stroke_red,
+ stroke_green,
+ stroke_blue);
+ }
+ cairo_set_dash (cr, NULL, 0, 0.0);
+ cairo_set_line_width (cr, 1.0);
+ cairo_stroke (cr);
+
+ /* focus indicator */
+ if (is_focused && is_grid_focused) {
+ gdouble dashes[] = {2.0};
+ round_rect (cr,
+ element->x + 0.5 + 3,
+ element->y + 0.5 + 3,
+ element->width - 3 * 2,
+ element->height - 3 * 2,
+ 20,
+ element->edge_flags);
+ cairo_set_source_rgb (cr, focus_rect_red, focus_rect_green, focus_rect_blue);
+ cairo_set_dash (cr, dashes, 1, 0.0);
+ cairo_set_line_width (cr, 1.0);
+ cairo_stroke (cr);
+ }
+
+ if (element->presentable == NULL) { /* no media available */
+ cairo_text_extents_t te;
+ const gchar *text;
+
+ text = _("No Media Detected");
+
+ if (is_selected) {
+ if (is_grid_focused) {
+ cairo_set_source_rgb (cr,
+ text_selected_red,
+ text_selected_green,
+ text_selected_blue);
+ } else {
+ cairo_set_source_rgb (cr,
+ text_selected_not_focused_red,
+ text_selected_not_focused_green,
+ text_selected_not_focused_blue);
+ }
+ } else {
+ cairo_set_source_rgb (cr, text_red, text_green, text_blue);
+ }
+ cairo_select_font_face (cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, 8.0);
+
+ cairo_text_extents (cr, text, &te);
+ cairo_move_to (cr,
+ ceil (element->x + element->width / 2 - te.width/2 - te.x_bearing),
+ ceil (element->y + element->height / 2 - 2 - te.height/2 - te.y_bearing));
+ cairo_show_text (cr, text);
+
+ } else { /* render descriptive text for the presentable */
+ gchar *s;
+ gchar *s1;
+ cairo_text_extents_t te;
+ cairo_text_extents_t te1;
+ GduDevice *d;
+ gdouble text_height;
+
+ d = gdu_presentable_get_device (element->presentable);
+
+ s = NULL;
+ s1 = NULL;
+ if (d != NULL && g_strcmp0 (gdu_device_id_get_usage (d), "filesystem") == 0) {
+ gchar *fstype_str;
+ gchar *size_str;
+
+ s = g_strdup (gdu_device_id_get_label (d));
+ fstype_str = gdu_util_get_fstype_for_display (gdu_device_id_get_type (d),
+ gdu_device_id_get_version (d),
+ FALSE);
+ size_str = gdu_util_get_size_for_display (gdu_device_get_size (d),
+ FALSE,
+ FALSE);
+ s1 = g_strdup_printf ("%s %s", size_str, fstype_str);
+ g_free (fstype_str);
+ g_free (size_str);
+ } else if (d != NULL && gdu_device_is_partition (d) &&
+ (g_strcmp0 (gdu_device_partition_get_type (d), "0x05") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (d), "0x0f") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (d), "0x85") == 0)) {
+ s = g_strdup (_("Extended"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->presentable),
+ FALSE,
+ FALSE);
+ } else if (d != NULL && g_strcmp0 (gdu_device_id_get_usage (d), "crypto") == 0) {
+ s = g_strdup (_("Encrypted"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->presentable),
+ FALSE,
+ FALSE);
+ } else if (!gdu_presentable_is_allocated (element->presentable)) {
+ s = g_strdup (_("Free"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->presentable),
+ FALSE,
+ FALSE);
+ } else if (!gdu_presentable_is_recognized (element->presentable)) {
+ s = g_strdup (_("Unknown"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->presentable),
+ FALSE,
+ FALSE);
+ }
+
+ if (s == NULL)
+ s = gdu_presentable_get_name (element->presentable);
+ if (s1 == NULL)
+ s1 = g_strdup ("");
+
+ if (is_selected) {
+ if (is_grid_focused) {
+ cairo_set_source_rgb (cr,
+ text_selected_red,
+ text_selected_green,
+ text_selected_blue);
+ } else {
+ cairo_set_source_rgb (cr,
+ text_selected_not_focused_red,
+ text_selected_not_focused_green,
+ text_selected_not_focused_blue);
+ }
+ } else {
+ cairo_set_source_rgb (cr, text_red, text_green, text_blue);
+ }
+ cairo_select_font_face (cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, 8.0);
+
+ cairo_text_extents (cr, s, &te);
+ cairo_text_extents (cr, s1, &te1);
+
+ text_height = te.height + te1.height;
+
+ cairo_move_to (cr,
+ ceil (element->x + element->width / 2 - te.width/2 - te.x_bearing),
+ ceil (element->y + element->height / 2 - 2 - text_height/2 - te.y_bearing));
+ cairo_show_text (cr, s);
+ cairo_move_to (cr,
+ ceil (element->x + element->width / 2 - te1.width/2 - te1.x_bearing),
+ ceil (element->y + element->height / 2 + 2 - te1.y_bearing));
+ cairo_show_text (cr, s1);
+ g_free (s);
+ g_free (s1);
+
+ if (d != NULL)
+ g_object_unref (d);
+ }
+
+ cairo_restore (cr);
+}
+
+static gboolean
+gdu_volume_grid_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (widget);
+ GList *l;
+ cairo_t *cr;
+ gdouble width;
+ gdouble height;
+
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+
+ recompute_size (grid,
+ width - 1,
+ height -1);
+
+ cr = gdk_cairo_create (widget->window);
+ cairo_rectangle (cr,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_clip (cr);
+
+ for (l = grid->priv->elements; l != NULL; l = l->next) {
+ GridElement *element = l->data;
+ gboolean is_selected;
+ gboolean is_focused;
+ gboolean is_grid_focused;
+ GList *ll;
+
+ is_selected = FALSE;
+ is_focused = FALSE;
+ is_grid_focused = GTK_WIDGET_HAS_FOCUS (grid);
+
+ if (element == grid->priv->selected)
+ is_selected = TRUE;
+
+ if (element == grid->priv->focused) {
+ if (grid->priv->focused != grid->priv->selected && is_grid_focused)
+ is_focused = TRUE;
+ }
+
+ render_element (grid,
+ cr,
+ element,
+ is_selected,
+ is_focused,
+ is_grid_focused);
+
+ for (ll = element->embedded_elements; ll != NULL; ll = ll->next) {
+ GridElement *element = ll->data;
+
+ is_selected = FALSE;
+ is_focused = FALSE;
+ is_grid_focused = GTK_WIDGET_HAS_FOCUS (grid);
+
+ if (element == grid->priv->selected)
+ is_selected = TRUE;
+
+ if (element == grid->priv->focused) {
+ if (grid->priv->focused != grid->priv->selected && is_grid_focused)
+ is_focused = TRUE;
+ }
+
+ render_element (grid,
+ cr,
+ element,
+ is_selected,
+ is_focused,
+ is_grid_focused);
+ }
+ }
+
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+static GridElement *
+do_find_element_for_presentable (GList *elements,
+ GduPresentable *presentable)
+{
+ GList *l;
+ GridElement *ret;
+
+ ret = NULL;
+
+ for (l = elements; l != NULL; l = l->next) {
+ GridElement *e = l->data;
+ if (e->presentable == presentable) {
+ ret = e;
+ goto out;
+ }
+
+ ret = do_find_element_for_presentable (e->embedded_elements, presentable);
+ if (ret != NULL)
+ goto out;
+
+ }
+
+ out:
+ return ret;
+}
+
+static GridElement *
+find_element_for_presentable (GduVolumeGrid *grid,
+ GduPresentable *presentable)
+{
+ return do_find_element_for_presentable (grid->priv->elements, presentable);
+}
+
+static GridElement *
+do_find_element_for_position (GList *elements,
+ gint x,
+ gint y)
+{
+ GList *l;
+ GridElement *ret;
+
+ ret = NULL;
+
+ for (l = elements; l != NULL; l = l->next) {
+ GridElement *e = l->data;
+
+ if ((x >= e->x) &&
+ (x < e->x + e->width) &&
+ (y >= e->y) &&
+ (y < e->y + e->height)) {
+ ret = e;
+ goto out;
+ }
+
+ ret = do_find_element_for_position (e->embedded_elements, x, y);
+ if (ret != NULL)
+ goto out;
+
+ }
+
+ out:
+ return ret;
+}
+
+static GridElement *
+find_element_for_position (GduVolumeGrid *grid,
+ gint x,
+ gint y)
+{
+ return do_find_element_for_position (grid->priv->elements, x, y);
+}
+
+GduPresentable *
+gdu_volume_grid_get_selected (GduVolumeGrid *grid)
+{
+ GduPresentable *ret;
+
+ g_return_val_if_fail (GDU_IS_VOLUME_GRID (grid), NULL);
+
+ ret = NULL;
+ if (grid->priv->selected != NULL) {
+ if (grid->priv->selected->presentable != NULL)
+ ret = g_object_ref (grid->priv->selected->presentable);
+ }
+
+ return ret;
+}
+
+static void
+maybe_recompute (GduVolumeGrid *grid,
+ GduPresentable *p)
+{
+ gboolean recompute;
+
+ recompute = FALSE;
+ if (p == GDU_PRESENTABLE (grid->priv->drive) ||
+ gdu_presentable_encloses (GDU_PRESENTABLE (grid->priv->drive), p) ||
+ find_element_for_presentable (grid, p) != NULL) {
+ recompute = TRUE;
+ }
+
+ if (recompute) {
+ recompute_grid (grid);
+ g_signal_emit (grid,
+ signals[CHANGED_SIGNAL],
+ 0);
+ }
+}
+
+static void
+on_presentable_added (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (user_data);
+ maybe_recompute (grid, p);
+}
+
+static void
+on_presentable_removed (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (user_data);
+ maybe_recompute (grid, p);
+}
+
+static void
+on_presentable_changed (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (user_data);
+ maybe_recompute (grid, p);
+}
+
+static void
+on_presentable_job_changed (GduPool *pool,
+ GduPresentable *p,
+ gpointer user_data)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (user_data);
+ maybe_recompute (grid, p);
+}
diff --git a/src/gdu-gtk/gdu-volume-grid.h b/src/gdu-gtk/gdu-volume-grid.h
new file mode 100644
index 0000000..a3f6777
--- /dev/null
+++ b/src/gdu-gtk/gdu-volume-grid.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-grid-element.h
+ *
+ * Copyright (C) 2009 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#if !defined (__GDU_GTK_INSIDE_GDU_GTK_H) && !defined (GDU_GTK_COMPILATION)
+#error "Only <gdu-gtk/gdu-gtk.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __GDU_VOLUME_GRID_H
+#define __GDU_VOLUME_GRID_H
+
+#include <gdu-gtk/gdu-gtk-types.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_VOLUME_GRID gdu_volume_grid_get_type()
+#define GDU_VOLUME_GRID(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_VOLUME_GRID, GduVolumeGrid))
+#define GDU_VOLUME_GRID_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_VOLUME_GRID, GduVolumeGridClass))
+#define GDU_IS_VOLUME_GRID(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_VOLUME_GRID))
+#define GDU_IS_VOLUME_GRID_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_VOLUME_GRID))
+#define GDU_VOLUME_GRID_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_VOLUME_GRID, GduVolumeGridClass))
+
+typedef struct GduVolumeGridClass GduVolumeGridClass;
+typedef struct GduVolumeGridPrivate GduVolumeGridPrivate;
+
+struct GduVolumeGrid
+{
+ GtkDrawingArea parent;
+
+ /*< private >*/
+ GduVolumeGridPrivate *priv;
+};
+
+struct GduVolumeGridClass
+{
+ GtkDrawingAreaClass parent_class;
+
+ /* signals */
+ void (*changed) (GduVolumeGrid *grid);
+};
+
+GType gdu_volume_grid_get_type (void) G_GNUC_CONST;
+GtkWidget* gdu_volume_grid_new (GduDrive *drive);
+GduPresentable *gdu_volume_grid_get_selected (GduVolumeGrid *grid);
+
+G_END_DECLS
+
+
+
+#endif /* __GDU_VOLUME_GRID_H */
diff --git a/src/gdu/gdu-drive.c b/src/gdu/gdu-drive.c
index 2858776..4d1cced 100644
--- a/src/gdu/gdu-drive.c
+++ b/src/gdu/gdu-drive.c
@@ -559,7 +559,7 @@ gdu_drive_get_name (GduPresentable *presentable)
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);
+ strsize = gdu_util_get_size_for_display (size, FALSE, FALSE);
}
if (is_removable) {
@@ -678,7 +678,7 @@ gdu_drive_get_description (GduPresentable *presentable)
if (is_removable) {
if (has_media && size > 0) {
gchar *strsize;
- strsize = gdu_util_get_size_for_display (size, FALSE);
+ strsize = gdu_util_get_size_for_display (size, FALSE, FALSE);
/* Translators: This string is the description of a drive. The first %s is the
* size of the inserted media, for example '45 GB'.
*/
diff --git a/src/gdu/gdu-linux-md-drive.c b/src/gdu/gdu-linux-md-drive.c
index 981582c..cc73a5c 100644
--- a/src/gdu/gdu-linux-md-drive.c
+++ b/src/gdu/gdu-linux-md-drive.c
@@ -494,7 +494,7 @@ get_names_and_desc (GduPresentable *presentable,
if (drive->priv->device != NULL) {
guint64 size;
size = gdu_device_get_size (drive->priv->device);
- strsize = gdu_util_get_size_for_display (size, FALSE);
+ strsize = gdu_util_get_size_for_display (size, FALSE, FALSE);
}
if (drive->priv->slaves != NULL) {
diff --git a/src/gdu/gdu-presentable.c b/src/gdu/gdu-presentable.c
index 6f38998..d0915f4 100644
--- a/src/gdu/gdu-presentable.c
+++ b/src/gdu/gdu-presentable.c
@@ -25,6 +25,7 @@
#include <dbus/dbus-glib.h>
#include "gdu-presentable.h"
+#include "gdu-pool.h"
/**
* SECTION:gdu-presentable
@@ -596,3 +597,63 @@ gdu_presentable_compare (GduPresentable *a,
return ret;
}
+
+GList *
+gdu_presentable_get_enclosed (GduPresentable *presentable)
+{
+ GList *l;
+ GList *presentables;
+ GList *ret;
+ GduPool *pool;
+
+ pool = gdu_presentable_get_pool (presentable);
+ presentables = gdu_pool_get_presentables (pool);
+
+ ret = NULL;
+ for (l = presentables; l != NULL; l = l->next) {
+ GduPresentable *p = l->data;
+ GduPresentable *e;
+
+ e = gdu_presentable_get_enclosing_presentable (p);
+ if (e != NULL) {
+ if (gdu_presentable_equals (e, presentable)) {
+ GList *enclosed_by_p;
+
+ ret = g_list_prepend (ret, g_object_ref (p));
+
+ enclosed_by_p = gdu_presentable_get_enclosed (p);
+ ret = g_list_concat (ret, enclosed_by_p);
+ }
+ g_object_unref (e);
+ }
+ }
+
+ g_list_foreach (presentables, (GFunc) g_object_unref, NULL);
+ g_list_free (presentables);
+ g_object_unref (pool);
+ return ret;
+}
+
+gboolean
+gdu_presentable_encloses (GduPresentable *a,
+ GduPresentable *b)
+{
+ GList *enclosed_by_a;
+ GList *l;
+ gboolean ret;
+
+ ret = FALSE;
+ enclosed_by_a = gdu_presentable_get_enclosed (a);
+ for (l = enclosed_by_a; l != NULL; l = l->next) {
+ GduPresentable *p = GDU_PRESENTABLE (l->data);
+ if (gdu_presentable_equals (b, p)) {
+ ret = TRUE;
+ break;
+ }
+ }
+ g_list_foreach (enclosed_by_a, (GFunc) g_object_unref, NULL);
+ g_list_free (enclosed_by_a);
+
+ return ret;
+}
+
diff --git a/src/gdu/gdu-presentable.h b/src/gdu/gdu-presentable.h
index 13b5453..b4bc1d4 100644
--- a/src/gdu/gdu-presentable.h
+++ b/src/gdu/gdu-presentable.h
@@ -103,6 +103,11 @@ gboolean gdu_presentable_equals (GduPresentable *a,
gint gdu_presentable_compare (GduPresentable *a,
GduPresentable *b);
+GList *gdu_presentable_get_enclosed (GduPresentable *presentable);
+gboolean gdu_presentable_encloses (GduPresentable *a,
+ GduPresentable *b);
+
+
G_END_DECLS
#endif /* __GDU_PRESENTABLE_H */
diff --git a/src/gdu/gdu-util.c b/src/gdu/gdu-util.c
index 7bf22d5..8172d7c 100644
--- a/src/gdu/gdu-util.c
+++ b/src/gdu/gdu-util.c
@@ -33,10 +33,12 @@
#define KILOBYTE_FACTOR 1000.0
#define MEGABYTE_FACTOR (1000.0 * 1000.0)
#define GIGABYTE_FACTOR (1000.0 * 1000.0 * 1000.0)
+#define TERABYTE_FACTOR (1000.0 * 1000.0 * 1000.0 * 1000.0)
#define KIBIBYTE_FACTOR 1024.0
#define MEBIBYTE_FACTOR (1024.0 * 1024.0)
#define GIBIBYTE_FACTOR (1024.0 * 1024.0 * 1024.0)
+#define TEBIBYTE_FACTOR (1024.0 * 1024.0 * 1024.0 * 10242.0)
static char *
get_pow2_size (guint64 size)
@@ -52,9 +54,12 @@ get_pow2_size (guint64 size)
} else if (size < GIBIBYTE_FACTOR) {
displayed_size = (double) size / MEBIBYTE_FACTOR;
unit = "MiB";
- } else {
+ } else if (size < TEBIBYTE_FACTOR) {
displayed_size = (double) size / GIBIBYTE_FACTOR;
unit = "GiB";
+ } else {
+ displayed_size = (double) size / TEBIBYTE_FACTOR;
+ unit = "TiB";
}
if (displayed_size < 10.0)
@@ -81,9 +86,12 @@ get_pow10_size (guint64 size)
} else if (size < GIGABYTE_FACTOR) {
displayed_size = (double) size / MEGABYTE_FACTOR;
unit = "MB";
- } else {
+ } else if (size < TERABYTE_FACTOR) {
displayed_size = (double) size / GIGABYTE_FACTOR;
unit = "GB";
+ } else {
+ displayed_size = (double) size / TERABYTE_FACTOR;
+ unit = "TB";
}
if (displayed_size < 10.0)
@@ -97,31 +105,45 @@ get_pow10_size (guint64 size)
}
-char *
-gdu_util_get_size_for_display (guint64 size, gboolean long_string)
+gchar *
+gdu_util_get_size_for_display (guint64 size,
+ gboolean use_pow2,
+ gboolean long_string)
{
- char *str;
+ gchar *str;
if (long_string) {
- char *pow2_str;
- char *pow10_str;
- char *size_str;
+ gchar *size_str;
- pow2_str = get_pow2_size (size);
- pow10_str = get_pow10_size (size);
size_str = g_strdup_printf ("%'" G_GINT64_FORMAT, size);
- /* Translators: The first %s is the size in power-of-10 units, e.g. 100 KB
- * the second %s is the size in power-of-2 units, e.g. 20 MiB
- * the third %s is the size as a number
- */
- str = g_strdup_printf (_("%s / %s / %s bytes"), pow10_str, pow2_str, size_str);
+ if (use_pow2) {
+ gchar *pow2_str;
+ pow2_str = get_pow2_size (size);
+
+ /* Translators: The first %s is the size in power-of-2 units, e.g. '64 KiB'
+ * the second %s is the size as a number e.g. '65,536 bytes'
+ */
+ str = g_strdup_printf (_("%s (%s bytes)"), pow2_str, size_str);
+ g_free (pow2_str);
+ } else {
+ gchar *pow10_str;
+ pow10_str = get_pow10_size (size);
+
+ /* Translators: The first %s is the size in power-of-10 units, e.g. '100 KB'
+ * the second %s is the size as a number e.g. '100,000 bytes'
+ */
+ str = g_strdup_printf (_("%s (%s bytes)"), pow10_str, size_str);
+ g_free (pow10_str);
+ }
g_free (size_str);
- g_free (pow10_str);
- g_free (pow2_str);
} else {
- str = get_pow10_size (size);
+ if (use_pow2) {
+ str = get_pow2_size (size);
+ } else {
+ str = get_pow10_size (size);
+ }
}
return str;
diff --git a/src/gdu/gdu-util.h b/src/gdu/gdu-util.h
index 4305a98..049a23d 100644
--- a/src/gdu/gdu-util.h
+++ b/src/gdu/gdu-util.h
@@ -30,7 +30,10 @@
G_BEGIN_DECLS
-char *gdu_util_get_size_for_display (guint64 size, gboolean long_string);
+gchar *gdu_util_get_size_for_display (guint64 size,
+ gboolean use_pow2,
+ gboolean long_string);
+
char *gdu_util_get_fstype_for_display (const char *fstype, const char *fsversion, gboolean long_string);
char *gdu_util_fstype_get_description (char *fstype);
diff --git a/src/gdu/gdu-volume-hole.c b/src/gdu/gdu-volume-hole.c
index 11c8564..64c3821 100644
--- a/src/gdu/gdu-volume-hole.c
+++ b/src/gdu/gdu-volume-hole.c
@@ -143,7 +143,7 @@ gdu_volume_hole_get_name (GduPresentable *presentable)
char *result;
char *strsize;
- strsize = gdu_util_get_size_for_display (volume_hole->priv->size, FALSE);
+ strsize = gdu_util_get_size_for_display (volume_hole->priv->size, FALSE, FALSE);
/* Translators: label for an unallocated space on a disk
* %s is the size, formatted like '45 GB'
*/
diff --git a/src/gdu/gdu-volume.c b/src/gdu/gdu-volume.c
index e4504ab..2db8ac8 100644
--- a/src/gdu/gdu-volume.c
+++ b/src/gdu/gdu-volume.c
@@ -237,7 +237,7 @@ get_names_and_desc (GduPresentable *presentable,
size = gdu_device_partition_get_size (volume->priv->device);
else
size = gdu_device_get_size (volume->priv->device);
- strsize = gdu_util_get_size_for_display (size, FALSE);
+ strsize = gdu_util_get_size_for_display (size, FALSE, FALSE);
presentation_name = gdu_device_get_presentation_name (volume->priv->device);
if (presentation_name != NULL && strlen (presentation_name) > 0) {
diff --git a/src/palimpsest/Makefile.am b/src/palimpsest/Makefile.am
index 42c8bdc..66685a8 100644
--- a/src/palimpsest/Makefile.am
+++ b/src/palimpsest/Makefile.am
@@ -18,6 +18,8 @@ palimpsest_SOURCES = \
gdu-section-encrypted.h gdu-section-encrypted.c \
gdu-section-linux-md-drive.h gdu-section-linux-md-drive.c \
gdu-section-no-media.h gdu-section-no-media.c \
+ gdu-section-drive.h gdu-section-drive.c \
+ gdu-section-volumes.h gdu-section-volumes.c \
$(NULL)
palimpsest_CPPFLAGS = \
diff --git a/src/palimpsest/gdu-section-drive.c b/src/palimpsest/gdu-section-drive.c
new file mode 100644
index 0000000..340b5c9
--- /dev/null
+++ b/src/palimpsest/gdu-section-drive.c
@@ -0,0 +1,605 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-section-drive.c
+ *
+ * Copyright (C) 2009 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <stdlib.h>
+#include <math.h>
+#include <gio/gdesktopappinfo.h>
+
+#include <gdu-gtk/gdu-gtk.h>
+#include "gdu-section-drive.h"
+
+struct _GduSectionDrivePrivate
+{
+ GduDetailsElement *model_element;
+ GduDetailsElement *firmware_element;
+ GduDetailsElement *serial_element;
+ GduDetailsElement *wwn_element;
+ GduDetailsElement *capacity_element;
+ GduDetailsElement *connection_element;
+ GduDetailsElement *partitioning_element;
+ GduDetailsElement *smart_element;
+};
+
+G_DEFINE_TYPE (GduSectionDrive, gdu_section_drive, GDU_TYPE_SECTION)
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_section_drive_finalize (GObject *object)
+{
+ //GduSectionDrive *section = GDU_SECTION_DRIVE (object);
+
+ if (G_OBJECT_CLASS (gdu_section_drive_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_section_drive_parent_class)->finalize (object);
+}
+
+static void
+gdu_section_drive_update (GduSection *_section)
+{
+ GduSectionDrive *section = GDU_SECTION_DRIVE (_section);
+ GduPresentable *p;
+ GduDevice *d;
+ gchar *s;
+ gchar *s2;
+ const gchar *vendor;
+ const gchar *model;
+ const gchar *firmware;
+ const gchar *serial;
+ const gchar *wwn;
+ GIcon *icon;
+
+ d = NULL;
+ p = gdu_section_get_presentable (_section);
+
+ d = gdu_presentable_get_device (p);
+ if (d == NULL)
+ goto out;
+
+ model = gdu_device_drive_get_model (d);
+ vendor = gdu_device_drive_get_vendor (d);
+ if (vendor != NULL && strlen (vendor) == 0)
+ vendor = NULL;
+ if (model != NULL && strlen (model) == 0)
+ model = NULL;
+ s = g_strdup_printf ("%s%s%s",
+ vendor != NULL ? vendor : "",
+ vendor != NULL ? " " : "",
+ model != NULL ? model : "");
+ gdu_details_element_set_text (section->priv->model_element, s);
+ g_free (s);
+
+ firmware = gdu_device_drive_get_revision (d);
+ if (firmware == NULL || strlen (firmware) == 0)
+ firmware = "â??";
+ gdu_details_element_set_text (section->priv->firmware_element, firmware);
+
+ serial = gdu_device_drive_get_serial (d);
+ if (serial == NULL || strlen (serial) == 0)
+ serial = "â??";
+ gdu_details_element_set_text (section->priv->serial_element, serial);
+
+ wwn = NULL; /*TODO: gdu_device_drive_get_wwn (d)*/
+ if (wwn == NULL || strlen (wwn) == 0)
+ wwn = "â??";
+ gdu_details_element_set_text (section->priv->wwn_element, wwn);
+
+ if (gdu_device_is_partition_table (d)) {
+ const gchar *scheme;
+
+ scheme = gdu_device_partition_table_get_scheme (d);
+ if (g_strcmp0 (scheme, "apm") == 0) {
+ s = g_strdup (_("Apple Partition Map"));
+ } else if (g_strcmp0 (scheme, "mbr") == 0) {
+ s = g_strdup (_("Master Boot Record"));
+ } else if (g_strcmp0 (scheme, "gpt") == 0) {
+ s = g_strdup (_("GUID Partition Table"));
+ } else {
+ /* Translators: 'scheme' refers to a partition table format here, like 'mbr' or 'gpt' */
+ s = g_strdup_printf (_("Unknown Scheme: %s"), scheme);
+ }
+ gdu_details_element_set_text (section->priv->partitioning_element, s);
+ g_free (s);
+ } else {
+ gdu_details_element_set_text (section->priv->partitioning_element,
+ _("Not Partitioned"));
+ }
+
+ if (gdu_device_drive_ata_smart_get_is_available (d) &&
+ gdu_device_drive_ata_smart_get_time_collected (d) > 0) {
+ gboolean highlight;
+
+ s = gdu_util_ata_smart_status_to_desc (gdu_device_drive_ata_smart_get_status (d),
+ &highlight,
+ NULL,
+ &icon);
+ if (highlight) {
+ s2 = g_strdup_printf ("<span fgcolor=\"red\"><b>%s</b></span>", s);
+ g_free (s);
+ s = s2;
+ }
+
+ gdu_details_element_set_text (section->priv->smart_element, s);
+ gdu_details_element_set_icon (section->priv->smart_element, icon);
+
+ g_free (s);
+ g_object_unref (icon);
+ } else {
+ gdu_details_element_set_text (section->priv->smart_element,
+ _("Not Supported"));
+ icon = g_themed_icon_new ("gdu-smart-unknown");
+ gdu_details_element_set_icon (section->priv->smart_element, icon);
+ g_object_unref (icon);
+ }
+
+ if (gdu_device_is_media_available (d)) {
+ s = gdu_util_get_size_for_display (gdu_device_get_size (d),
+ FALSE,
+ TRUE);
+ gdu_details_element_set_text (section->priv->capacity_element, s);
+ g_free (s);
+ } else {
+ gdu_details_element_set_text (section->priv->capacity_element,
+ _("No Media Detected"));
+ }
+
+ s = gdu_util_get_connection_for_display (gdu_device_drive_get_connection_interface (d),
+ gdu_device_drive_get_connection_speed (d));
+ gdu_details_element_set_text (section->priv->connection_element, s);
+ g_free (s);
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GtkWidget *
+create_button (const gchar *icon_name,
+ const gchar *button_primary,
+ const gchar *button_secondary)
+{
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *image;
+ GtkWidget *button;
+ gchar *s;
+
+ image = gtk_image_new_from_icon_name (icon_name,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_single_line_mode (GTK_LABEL (label), FALSE);
+ s = g_strdup_printf ("%s\n"
+ "<span fgcolor='#404040'><small>%s</small></span>",
+ button_primary,
+ button_secondary);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
+ g_free (s);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_container_add (GTK_CONTAINER (button), hbox);
+
+ gtk_widget_set_size_request (label, 250, -1);
+
+ return button;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+has_strv0 (gchar **strv, const gchar *str)
+{
+ gboolean ret;
+ guint n;
+
+ ret = FALSE;
+
+ for (n = 0; strv != NULL && strv[n] != NULL; n++) {
+ if (g_strcmp0 (strv[n], str) == 0) {
+ ret = TRUE;
+ goto out;
+ }
+ }
+
+ out:
+ return ret;
+}
+
+static void
+on_cddvd_button_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
+ GAppLaunchContext *launch_context;
+ GAppInfo *app_info;
+ GtkWidget *dialog;
+ GError *error;
+
+ app_info = NULL;
+ launch_context = NULL;
+
+ app_info = G_APP_INFO (g_desktop_app_info_new ("brasero.desktop"));
+ if (app_info == NULL) {
+ /* TODO: Use PackageKit to install Brasero */
+ dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section)))),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "<b><big><big>%s</big></big></b>\n\n%s",
+ _("Error launching Brasero"),
+ _("The application is not installed"));
+ gtk_widget_show_all (dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ goto out;
+ }
+
+ launch_context = G_APP_LAUNCH_CONTEXT (gdk_app_launch_context_new ());
+
+ error = NULL;
+ if (!g_app_info_launch (app_info,
+ NULL, /* no files */
+ launch_context,
+ &error)) {
+ dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section)))),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "<b><big><big>%s</big></big></b>\n\n%s",
+ _("Error launching Brasero"),
+ error->message);
+ g_error_free (error);
+ gtk_widget_show_all (dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+
+ out:
+ if (app_info != NULL)
+ g_object_unref (app_info);
+ if (launch_context != NULL)
+ g_object_unref (launch_context);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_smart_button_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
+ GtkWindow *toplevel;
+ GtkWidget *dialog;
+
+ toplevel = GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))));
+ dialog = gdu_ata_smart_dialog_new (toplevel,
+ GDU_DRIVE (gdu_section_get_presentable (GDU_SECTION (section))));
+ gtk_widget_show_all (dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+eject_op_callback (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GduShell *shell = GDU_SHELL (user_data);
+
+ if (error != NULL) {
+ gdu_shell_raise_error (shell,
+ NULL,
+ error,
+ _("Error ejecting device"));
+ g_error_free (error);
+ }
+ g_object_unref (shell);
+}
+
+static void
+on_eject_button_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
+ GduDevice *d;
+
+ d = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
+ if (d == NULL)
+ goto out;
+
+ gdu_device_op_drive_eject (d,
+ eject_op_callback,
+ g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
+
+ g_object_unref (d);
+ out:
+ ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+detach_op_callback (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GduShell *shell = GDU_SHELL (user_data);
+
+ if (error != NULL) {
+ gdu_shell_raise_error (shell,
+ NULL,
+ error,
+ _("Error detaching device"));
+ g_error_free (error);
+ }
+ g_object_unref (shell);
+}
+
+static void
+on_detach_button_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
+ GduDevice *d;
+
+ d = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
+ if (d == NULL)
+ goto out;
+
+ gdu_device_op_drive_detach (d,
+ detach_op_callback,
+ g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
+
+ g_object_unref (d);
+ out:
+ ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_button (GtkWidget *table,
+ GtkWidget *button,
+ guint *row,
+ guint *column)
+{
+ guint num_columns;
+
+ gtk_table_attach (GTK_TABLE (table),
+ button,
+ *column, *column + 1,
+ *row, *row + 1,
+ GTK_FILL,
+ GTK_FILL,
+ 0, 0);
+
+ g_object_get (table,
+ "n-columns", &num_columns,
+ NULL);
+
+ *column += 1;
+ if (*column >= num_columns) {
+ *column = 0;
+ *row +=1;
+ }
+}
+
+static void
+gdu_section_drive_constructed (GObject *object)
+{
+ GduSectionDrive *section = GDU_SECTION_DRIVE (object);
+ GtkWidget *align;
+ GtkWidget *label;
+ GtkWidget *table;
+ GtkWidget *vbox;
+ GtkWidget *button;
+ gchar *s;
+ GduPresentable *p;
+ GduDevice *d;
+ GPtrArray *elements;
+ GduDetailsElement *element;
+ guint row;
+ guint column;
+
+ d = NULL;
+
+ gtk_box_set_spacing (GTK_BOX (section), 12);
+
+ /*------------------------------------- */
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ s = g_strconcat ("<b>", _("Drive"), "</b>", NULL);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ g_free (s);
+ gtk_box_pack_start (GTK_BOX (section), label, FALSE, FALSE, 0);
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+ gtk_box_pack_start (GTK_BOX (section), align, FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (align), vbox);
+
+ elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+ element = gdu_details_element_new (_("Model:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->model_element = element;
+
+ element = gdu_details_element_new (_("Serial Number:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->serial_element = element;
+
+ element = gdu_details_element_new (_("Firmware Version:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->firmware_element = element;
+
+ element = gdu_details_element_new (_("World Wide Name:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->wwn_element = element;
+
+ element = gdu_details_element_new (_("Capacity:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->capacity_element = element;
+
+ element = gdu_details_element_new (_("Connection:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->connection_element = element;
+
+ element = gdu_details_element_new (_("Partitioning:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->partitioning_element = element;
+
+ element = gdu_details_element_new (_("SMART Status:"), NULL, NULL);
+ g_ptr_array_add (elements, element);
+ section->priv->smart_element = element;
+
+ table = gdu_details_table_new (2,
+ elements);
+ g_ptr_array_unref (elements);
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+
+ /* -------------------------------------------------------------------------------- */
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+ row = 0;
+ column = 0;
+ table = gtk_table_new (1, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 0);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 0);
+ gtk_container_add (GTK_CONTAINER (align), table);
+
+ p = gdu_section_get_presentable (GDU_SECTION (section));
+ d = gdu_presentable_get_device (p);
+ if (d != NULL && has_strv0 (gdu_device_drive_get_media_compatibility (d), "optical_cd")) {
+ button = create_button ("brasero",
+ _("Open CD/_DVD Application"),
+ _("Create and copy CDs and DVDs"));
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (on_cddvd_button_clicked),
+ section);
+ add_button (table, button, &row, &column);
+ } else {
+ button = create_button ("nautilus-gdu",
+ _("Format _Drive"),
+ _("Delete all data and partition the drive"));
+ add_button (table, button, &row, &column);
+ }
+
+ if (d != NULL &&
+ gdu_device_drive_ata_smart_get_is_available (d) &&
+ gdu_device_drive_ata_smart_get_time_collected (d) > 0) {
+ button = create_button ("gdu-check-disk",
+ _("SM_ART Data"),
+ _("View SMART data and run self-tests"));
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (on_smart_button_clicked),
+ section);
+ add_button (table, button, &row, &column);
+ }
+
+ if (d != NULL && gdu_device_drive_get_is_media_ejectable (d)) {
+ button = create_button ("gdu-eject",
+ _("_Eject"),
+ _("Eject media from the drive"));
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (on_eject_button_clicked),
+ section);
+ add_button (table, button, &row, &column);
+ }
+
+ if (d != NULL && gdu_device_drive_get_can_detach (d)) {
+ button = create_button ("gdu-detach",
+ _("Safe Rem_oval"),
+ _("Power down the drive so it can be removed"));
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (on_detach_button_clicked),
+ section);
+ add_button (table, button, &row, &column);
+ }
+
+ /* -------------------------------------------------------------------------------- */
+
+ gtk_widget_show_all (GTK_WIDGET (section));
+
+ if (d != NULL)
+ g_object_unref (d);
+
+ if (G_OBJECT_CLASS (gdu_section_drive_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (gdu_section_drive_parent_class)->constructed (object);
+}
+
+static void
+gdu_section_drive_class_init (GduSectionDriveClass *klass)
+{
+ GObjectClass *gobject_class;
+ GduSectionClass *section_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ section_class = GDU_SECTION_CLASS (klass);
+
+ gobject_class->finalize = gdu_section_drive_finalize;
+ gobject_class->constructed = gdu_section_drive_constructed;
+ section_class->update = gdu_section_drive_update;
+
+ g_type_class_add_private (klass, sizeof (GduSectionDrivePrivate));
+}
+
+static void
+gdu_section_drive_init (GduSectionDrive *section)
+{
+ section->priv = G_TYPE_INSTANCE_GET_PRIVATE (section, GDU_TYPE_SECTION_DRIVE, GduSectionDrivePrivate);
+}
+
+GtkWidget *
+gdu_section_drive_new (GduShell *shell,
+ GduPresentable *presentable)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_SECTION_DRIVE,
+ "shell", shell,
+ "presentable", presentable,
+ NULL));
+}
diff --git a/src/palimpsest/gdu-section-drive.h b/src/palimpsest/gdu-section-drive.h
new file mode 100644
index 0000000..901df80
--- /dev/null
+++ b/src/palimpsest/gdu-section-drive.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-section-drive.h
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include "gdu-section.h"
+
+#ifndef GDU_SECTION_DRIVE_H
+#define GDU_SECTION_DRIVE_H
+
+#define GDU_TYPE_SECTION_DRIVE (gdu_section_drive_get_type ())
+#define GDU_SECTION_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_SECTION_DRIVE, GduSectionDrive))
+#define GDU_SECTION_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_SECTION_DRIVE, GduSectionDriveClass))
+#define GDU_IS_SECTION_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_SECTION_DRIVE))
+#define GDU_IS_SECTION_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_SECTION_DRIVE))
+#define GDU_SECTION_DRIVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_SECTION_DRIVE, GduSectionDriveClass))
+
+typedef struct _GduSectionDriveClass GduSectionDriveClass;
+typedef struct _GduSectionDrive GduSectionDrive;
+
+struct _GduSectionDrivePrivate;
+typedef struct _GduSectionDrivePrivate GduSectionDrivePrivate;
+
+struct _GduSectionDrive
+{
+ GduSection parent;
+
+ /* private */
+ GduSectionDrivePrivate *priv;
+};
+
+struct _GduSectionDriveClass
+{
+ GduSectionClass parent_class;
+};
+
+GType gdu_section_drive_get_type (void);
+GtkWidget *gdu_section_drive_new (GduShell *shell,
+ GduPresentable *presentable);
+
+#endif /* GDU_SECTION_DRIVE_H */
diff --git a/src/palimpsest/gdu-section-linux-md-drive.c b/src/palimpsest/gdu-section-linux-md-drive.c
index c3f6941..fcb9b0d 100644
--- a/src/palimpsest/gdu-section-linux-md-drive.c
+++ b/src/palimpsest/gdu-section-linux-md-drive.c
@@ -171,6 +171,7 @@ on_add_clicked (GtkButton *button,
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_SHADOW_IN);
model = gdu_pool_tree_model_new (pool,
+ NULL,
GDU_POOL_TREE_MODEL_FLAGS_NONE);
tree_view = gdu_pool_tree_view_new (model, GDU_POOL_TREE_VIEW_FLAGS_NONE);
g_object_unref (model);
@@ -707,7 +708,9 @@ update (GduSectionLinuxMdDrive *section)
level_str = g_strdup (level);
}
- s = gdu_util_get_size_for_display (component_size, FALSE);
+ s = gdu_util_get_size_for_display (component_size,
+ FALSE,
+ FALSE);
if (strcmp (level, "linear") == 0) {
/* Translators: %d is the number of components in the RAID */
components_str = g_strdup_printf (ngettext ("%d Component", "%d Components", num_raid_devices), num_raid_devices);
@@ -722,7 +725,9 @@ update (GduSectionLinuxMdDrive *section)
if (raid_size == 0) {
raid_size_str = g_strdup_printf ("-");
} else {
- raid_size_str = gdu_util_get_size_for_display (raid_size, TRUE);
+ raid_size_str = gdu_util_get_size_for_display (raid_size,
+ FALSE,
+ TRUE);
}
if (!gdu_drive_is_active (GDU_DRIVE (linux_md_drive))) {
diff --git a/src/palimpsest/gdu-section-volumes.c b/src/palimpsest/gdu-section-volumes.c
new file mode 100644
index 0000000..9952e8f
--- /dev/null
+++ b/src/palimpsest/gdu-section-volumes.c
@@ -0,0 +1,601 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-section-volumes.c
+ *
+ * Copyright (C) 2009 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <gdu-gtk/gdu-gtk.h>
+#include "gdu-section-volumes.h"
+
+struct _GduSectionVolumesPrivate
+{
+ GduPresentable *cur_volume;
+
+ GtkWidget *grid;
+ GtkWidget *details_table;
+ GtkWidget *buttons_align;
+
+ /* shared between all volume types */
+ GduDetailsElement *usage_element;
+ GduDetailsElement *capacity_element;
+ GduDetailsElement *partition_element;
+ GduDetailsElement *device_element;
+
+ /* elements for the 'filesystem' usage */
+ GduDetailsElement *fs_type_element;
+ GduDetailsElement *fs_available_element;
+ GduDetailsElement *fs_label_element;
+ GduDetailsElement *fs_mount_point_element;
+
+ GtkWidget *fs_mount_button;
+ GtkWidget *fs_unmount_button;
+};
+
+G_DEFINE_TYPE (GduSectionVolumes, gdu_section_volumes, GDU_TYPE_SECTION)
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_section_volumes_finalize (GObject *object)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (object);
+
+ if (section->priv->cur_volume != NULL)
+ g_object_unref (section->priv->cur_volume);
+
+ if (G_OBJECT_CLASS (gdu_section_volumes_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_section_volumes_parent_class)->finalize (object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GtkWidget *
+create_button (const gchar *icon_name,
+ const gchar *button_primary,
+ const gchar *button_secondary)
+{
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *image;
+ GtkWidget *button;
+ gchar *s;
+
+ image = gtk_image_new_from_icon_name (icon_name,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_single_line_mode (GTK_LABEL (label), FALSE);
+ s = g_strdup_printf ("%s\n"
+ "<span fgcolor='#404040'><small>%s</small></span>",
+ button_primary,
+ button_secondary);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
+ g_free (s);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ gtk_container_add (GTK_CONTAINER (button), hbox);
+
+ gtk_widget_set_size_request (label, 250, -1);
+
+ return button;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+add_button (GtkWidget *table,
+ GtkWidget *button,
+ guint *row,
+ guint *column)
+{
+ guint num_columns;
+
+ gtk_table_attach (GTK_TABLE (table),
+ button,
+ *column, *column + 1,
+ *row, *row + 1,
+ GTK_FILL,
+ GTK_FILL,
+ 0, 0);
+
+ g_object_get (table,
+ "n-columns", &num_columns,
+ NULL);
+
+ *column += 1;
+ if (*column >= num_columns) {
+ *column = 0;
+ *row +=1;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+unmount_op_callback (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GduShell *shell = GDU_SHELL (user_data);
+
+ /* TODO: handle busy mounts using GtkMountOperation */
+
+ if (error != NULL) {
+ gdu_shell_raise_error (shell,
+ NULL,
+ error,
+ _("Error unmounting device"));
+ g_error_free (error);
+ }
+ g_object_unref (shell);
+}
+
+static void
+on_unmount_button_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+
+ GduPresentable *v;
+ GduDevice *d;
+
+ v = NULL;
+ d = NULL;
+
+ v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+ if (v == NULL)
+ goto out;
+
+ d = gdu_presentable_get_device (v);
+ if (d == NULL)
+ goto out;
+
+ gdu_device_op_filesystem_unmount (d,
+ unmount_op_callback,
+ g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+ if (v != NULL)
+ g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+mount_op_callback (GduDevice *device,
+ gchar *mount_point,
+ GError *error,
+ gpointer user_data)
+{
+ GduShell *shell = GDU_SHELL (user_data);
+
+ if (error != NULL) {
+ gdu_shell_raise_error (shell,
+ NULL,
+ error,
+ _("Error mounting device"));
+ g_error_free (error);
+ } else {
+ g_free (mount_point);
+ }
+ g_object_unref (shell);
+}
+
+static void
+on_mount_button_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+ GduPresentable *v;
+ GduDevice *d;
+
+ v = NULL;
+ d = NULL;
+
+ v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+ if (v == NULL)
+ goto out;
+
+ d = gdu_presentable_get_device (v);
+ if (d == NULL)
+ goto out;
+
+ gdu_device_op_filesystem_mount (d,
+ NULL,
+ mount_op_callback,
+ g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+ if (v != NULL)
+ g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_section_volumes_update (GduSection *_section)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (_section);
+ GduPresentable *v;
+ GduDevice *d;
+ gchar *s;
+ gchar *s2;
+ const gchar *usage;
+
+ v = NULL;
+ d = NULL;
+ usage = "";
+
+ v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+
+ if (v != NULL) {
+ d = gdu_presentable_get_device (v);
+ if (d != NULL) {
+ usage = gdu_device_id_get_usage (d);
+ }
+ }
+
+ /* ---------------------------------------------------------------------------------------------------- */
+ /* rebuild table if the selected volume has changed */
+
+ if (section->priv->cur_volume != v) {
+ GPtrArray *elements;
+ GtkWidget *child;
+ GtkWidget *table;
+ GtkWidget *button;
+ guint row;
+ guint column;
+
+ child = gtk_bin_get_child (GTK_BIN (section->priv->buttons_align));
+ if (child != NULL)
+ gtk_container_remove (GTK_CONTAINER (section->priv->buttons_align), child);
+ row = 0;
+ column = 0;
+ table = gtk_table_new (1, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 0);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 0);
+ gtk_container_add (GTK_CONTAINER (section->priv->buttons_align), table);
+
+ if (section->priv->cur_volume != NULL)
+ g_object_unref (section->priv->cur_volume);
+ section->priv->cur_volume = v != NULL ? g_object_ref (v) : NULL;
+
+ section->priv->usage_element = NULL;
+ section->priv->capacity_element = NULL;
+ section->priv->partition_element = NULL;
+ section->priv->device_element = NULL;
+ section->priv->fs_type_element = NULL;
+ section->priv->fs_label_element = NULL;
+ section->priv->fs_available_element = NULL;
+ section->priv->fs_mount_point_element = NULL;
+
+ elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+ section->priv->usage_element = gdu_details_element_new (_("Usage:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->usage_element);
+
+ section->priv->device_element = gdu_details_element_new (_("Device:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->device_element);
+
+ section->priv->partition_element = gdu_details_element_new (_("Partition:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->partition_element);
+
+ section->priv->capacity_element = gdu_details_element_new (_("Capacity:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->capacity_element);
+
+ if (g_strcmp0 (usage, "filesystem") == 0) {
+ section->priv->fs_type_element = gdu_details_element_new (_("Type:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->fs_type_element);
+
+ section->priv->fs_available_element = gdu_details_element_new (_("Available:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->fs_available_element);
+
+ section->priv->fs_label_element = gdu_details_element_new (_("Label:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->fs_label_element);
+
+ section->priv->fs_mount_point_element = gdu_details_element_new (_("Mount Point:"), NULL, NULL);
+ g_ptr_array_add (elements, section->priv->fs_mount_point_element);
+
+ button = create_button ("gdu-mount",
+ _("_Mount Volume"),
+ _("Mount the volume"));
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (on_mount_button_clicked),
+ section);
+ section->priv->fs_mount_button = button;
+ add_button (table, button, &row, &column);
+
+ button = create_button ("gdu-unmount",
+ _("_Unmount Volume"),
+ _("Unmount the volume"));
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (on_unmount_button_clicked),
+ section);
+ section->priv->fs_unmount_button = button;
+ add_button (table, button, &row, &column);
+
+ button = create_button ("gdu-check-disk",
+ _("_Check Filesystem"),
+ _("Check the filesystem for errors"));
+ add_button (table, button, &row, &column);
+
+ button = create_button ("nautilus-gdu",
+ _("Fo_rmat Volume"),
+ _("Format the volume"));
+ add_button (table, button, &row, &column);
+
+ if (d != NULL && gdu_device_is_partition (d)) {
+ button = create_button (GTK_STOCK_EDIT,
+ _("Ed_it Partition"),
+ _("Change partition type and flags"));
+ add_button (table, button, &row, &column);
+
+ button = create_button (GTK_STOCK_DELETE,
+ _("D_elete Partition"),
+ _("Delete the partition"));
+ add_button (table, button, &row, &column);
+ }
+ }
+
+ gdu_details_table_set_elements (GDU_DETAILS_TABLE (section->priv->details_table), elements);
+ g_ptr_array_unref (elements);
+
+ gtk_widget_show_all (table);
+ }
+
+ /* ---------------------------------------------------------------------------------------------------- */
+ /* reset all elements */
+
+ if (section->priv->usage_element != NULL)
+ gdu_details_element_set_text (section->priv->usage_element, "â??");
+ if (section->priv->capacity_element != NULL) {
+ if (v != NULL) {
+ s = gdu_util_get_size_for_display (gdu_presentable_get_size (v), FALSE, TRUE);
+ gdu_details_element_set_text (section->priv->capacity_element, s);
+ g_free (s);
+ } else {
+ gdu_details_element_set_text (section->priv->capacity_element, "â??");
+ }
+ }
+ if (section->priv->partition_element != NULL) {
+ if (d != NULL && gdu_device_is_partition (d)) {
+ s = gdu_util_get_desc_for_part_type (gdu_device_partition_get_scheme (d),
+ gdu_device_partition_get_type (d));
+ gdu_details_element_set_text (section->priv->partition_element, s);
+ /* TODO: include partition flags... */
+ g_free (s);
+ } else {
+ gdu_details_element_set_text (section->priv->partition_element, "â??");
+ }
+ }
+ if (section->priv->device_element != NULL) {
+ if (d != NULL) {
+ gdu_details_element_set_text (section->priv->device_element,
+ gdu_device_get_device_file (d));
+ } else {
+ gdu_details_element_set_text (section->priv->device_element, "â??");
+ }
+ }
+ if (section->priv->fs_type_element != NULL)
+ gdu_details_element_set_text (section->priv->fs_type_element, "â??");
+ if (section->priv->fs_available_element != NULL)
+ gdu_details_element_set_text (section->priv->fs_available_element, "â??");
+ if (section->priv->fs_label_element != NULL)
+ gdu_details_element_set_text (section->priv->fs_label_element, "â??");
+ if (section->priv->fs_mount_point_element != NULL)
+ gdu_details_element_set_text (section->priv->fs_mount_point_element, "â??");
+
+ if (v == NULL)
+ goto out;
+
+ /* ---------------------------------------------------------------------------------------------------- */
+ /* populate according to usage */
+
+ if (g_strcmp0 (usage, "filesystem") == 0) {
+ gdu_details_element_set_text (section->priv->usage_element, _("Filesystem"));
+ s = gdu_util_get_fstype_for_display (gdu_device_id_get_type (d),
+ gdu_device_id_get_version (d),
+ TRUE);
+ gdu_details_element_set_text (section->priv->fs_type_element, s);
+ g_free (s);
+ gdu_details_element_set_text (section->priv->fs_label_element,
+ gdu_device_id_get_label (d));
+
+ /* TODO: figure out amount of free space */
+ gdu_details_element_set_text (section->priv->fs_available_element, "â??");
+
+
+ if (gdu_device_is_mounted (d)) {
+ const gchar* const *mount_paths;
+
+ /* For now we ignore if the device is mounted in multiple places */
+ mount_paths = (const gchar* const *) gdu_device_get_mount_paths (d);
+ s = g_strdup_printf ("<a title=\"%s\" href=\"file://%s\">%s</a>",
+ /* Translators: this the mount point hyperlink tooltip */
+ _("View files on the volume"),
+ mount_paths[0],
+ mount_paths[0]);
+ /* Translators: this the the text for the mount point
+ * item - %s is the mount point, e.g. '/media/disk'
+ */
+ s2 = g_strdup_printf (_("Mounted at %s"), s);
+ gdu_details_element_set_text (section->priv->fs_mount_point_element, s2);
+ g_free (s);
+ g_free (s2);
+
+ gtk_widget_set_sensitive (section->priv->fs_mount_button, FALSE);
+ gtk_widget_set_sensitive (section->priv->fs_unmount_button, TRUE);
+ } else {
+ gdu_details_element_set_text (section->priv->fs_mount_point_element, _("Not Mounted"));
+
+ gtk_widget_set_sensitive (section->priv->fs_mount_button, TRUE);
+ gtk_widget_set_sensitive (section->priv->fs_unmount_button, FALSE);
+ }
+
+ } else if (g_strcmp0 (usage, "") == 0 &&
+ d != NULL && gdu_device_is_partition (d) &&
+ g_strcmp0 (gdu_device_partition_get_scheme (d), "mbr") == 0 &&
+ (g_strcmp0 (gdu_device_partition_get_type (d), "0x05") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (d), "0x0f") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (d), "0x85") == 0)) {
+ gdu_details_element_set_text (section->priv->usage_element, _("Container for Logical Partitions"));
+
+ } else if (GDU_IS_VOLUME_HOLE (v)) {
+ GduDevice *drive_device;
+ gdu_details_element_set_text (section->priv->usage_element, _("Unallocated Space"));
+ drive_device = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
+ gdu_details_element_set_text (section->priv->device_element,
+ gdu_device_get_device_file (drive_device));
+ g_object_unref (drive_device);
+ }
+
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+ if (v != NULL)
+ g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_grid_changed (GduVolumeGrid *grid,
+ gpointer user_data)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+
+ gdu_section_volumes_update (GDU_SECTION (section));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_section_volumes_constructed (GObject *object)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (object);
+ GtkWidget *grid;
+ GtkWidget *align;
+ GtkWidget *label;
+ GtkWidget *vbox2;
+ GtkWidget *table;
+ gchar *s;
+
+ gtk_box_set_spacing (GTK_BOX (section), 12);
+
+ /*------------------------------------- */
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ s = g_strconcat ("<b>", _("_Volumes"), "</b>", NULL);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
+ g_free (s);
+ gtk_box_pack_start (GTK_BOX (section), label, FALSE, FALSE, 0);
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+ gtk_box_pack_start (GTK_BOX (section), align, FALSE, FALSE, 0);
+
+ vbox2 = gtk_vbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (align), vbox2);
+
+ grid = gdu_volume_grid_new (GDU_DRIVE (gdu_section_get_presentable (GDU_SECTION (section))));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), grid);
+ section->priv->grid = grid;
+ gtk_box_pack_start (GTK_BOX (vbox2),
+ grid,
+ FALSE,
+ FALSE,
+ 0);
+ g_signal_connect (grid,
+ "changed",
+ G_CALLBACK (on_grid_changed),
+ section);
+
+ table = gdu_details_table_new (2, NULL);
+ section->priv->details_table = table;
+ gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+ section->priv->buttons_align = align;
+ gtk_box_pack_start (GTK_BOX (vbox2), align, FALSE, FALSE, 0);
+
+ /* -------------------------------------------------------------------------------- */
+
+ gtk_widget_show_all (GTK_WIDGET (section));
+
+ if (G_OBJECT_CLASS (gdu_section_volumes_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (gdu_section_volumes_parent_class)->constructed (object);
+}
+
+static void
+gdu_section_volumes_class_init (GduSectionVolumesClass *klass)
+{
+ GObjectClass *gobject_class;
+ GduSectionClass *section_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ section_class = GDU_SECTION_CLASS (klass);
+
+ gobject_class->finalize = gdu_section_volumes_finalize;
+ gobject_class->constructed = gdu_section_volumes_constructed;
+ section_class->update = gdu_section_volumes_update;
+
+ g_type_class_add_private (klass, sizeof (GduSectionVolumesPrivate));
+}
+
+static void
+gdu_section_volumes_init (GduSectionVolumes *section)
+{
+ section->priv = G_TYPE_INSTANCE_GET_PRIVATE (section, GDU_TYPE_SECTION_VOLUMES, GduSectionVolumesPrivate);
+}
+
+GtkWidget *
+gdu_section_volumes_new (GduShell *shell,
+ GduPresentable *presentable)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_SECTION_VOLUMES,
+ "shell", shell,
+ "presentable", presentable,
+ NULL));
+}
diff --git a/src/palimpsest/gdu-section-volumes.h b/src/palimpsest/gdu-section-volumes.h
new file mode 100644
index 0000000..d2aa63e
--- /dev/null
+++ b/src/palimpsest/gdu-section-volumes.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-section-volumes.h
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include "gdu-section.h"
+
+#ifndef GDU_SECTION_VOLUMES_H
+#define GDU_SECTION_VOLUMES_H
+
+#define GDU_TYPE_SECTION_VOLUMES (gdu_section_volumes_get_type ())
+#define GDU_SECTION_VOLUMES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_SECTION_VOLUMES, GduSectionVolumes))
+#define GDU_SECTION_VOLUMES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_SECTION_VOLUMES, GduSectionVolumesClass))
+#define GDU_IS_SECTION_VOLUMES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_SECTION_VOLUMES))
+#define GDU_IS_SECTION_VOLUMES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_SECTION_VOLUMES))
+#define GDU_SECTION_VOLUMES_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_SECTION_VOLUMES, GduSectionVolumesClass))
+
+typedef struct _GduSectionVolumesClass GduSectionVolumesClass;
+typedef struct _GduSectionVolumes GduSectionVolumes;
+
+struct _GduSectionVolumesPrivate;
+typedef struct _GduSectionVolumesPrivate GduSectionVolumesPrivate;
+
+struct _GduSectionVolumes
+{
+ GduSection parent;
+
+ /* private */
+ GduSectionVolumesPrivate *priv;
+};
+
+struct _GduSectionVolumesClass
+{
+ GduSectionClass parent_class;
+};
+
+GType gdu_section_volumes_get_type (void);
+GtkWidget *gdu_section_volumes_new (GduShell *shell,
+ GduPresentable *presentable);
+
+#endif /* GDU_SECTION_VOLUMES_H */
diff --git a/src/palimpsest/gdu-section.c b/src/palimpsest/gdu-section.c
index 80c161b..a3d0e92 100644
--- a/src/palimpsest/gdu-section.c
+++ b/src/palimpsest/gdu-section.c
@@ -135,7 +135,8 @@ gdu_section_class_init (GduSectionClass *klass)
NULL,
GDU_TYPE_SHELL,
G_PARAM_WRITABLE |
- G_PARAM_READABLE));
+ G_PARAM_READABLE |
+ G_PARAM_CONSTRUCT));
/**
* GduSection:presentable:
@@ -149,7 +150,8 @@ gdu_section_class_init (GduSectionClass *klass)
NULL,
GDU_TYPE_PRESENTABLE,
G_PARAM_WRITABLE |
- G_PARAM_READABLE));
+ G_PARAM_READABLE |
+ G_PARAM_CONSTRUCT));
}
static void
diff --git a/src/palimpsest/gdu-section.h b/src/palimpsest/gdu-section.h
index b590275..d265a20 100644
--- a/src/palimpsest/gdu-section.h
+++ b/src/palimpsest/gdu-section.h
@@ -26,12 +26,12 @@
#ifndef GDU_SECTION_H
#define GDU_SECTION_H
-#define GDU_TYPE_SECTION (gdu_section_get_type ())
-#define GDU_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDU_TYPE_SECTION, GduSection))
-#define GDU_SECTION_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GDU_SECTION, GduSectionClass))
-#define GDU_IS_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDU_TYPE_SECTION))
-#define GDU_IS_SECTION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GDU_TYPE_SECTION))
-#define GDU_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDU_TYPE_SECTION, GduSectionClass))
+#define GDU_TYPE_SECTION (gdu_section_get_type ())
+#define GDU_SECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_SECTION, GduSection))
+#define GDU_SECTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_SECTION, GduSectionClass))
+#define GDU_IS_SECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_SECTION))
+#define GDU_IS_SECTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_SECTION))
+#define GDU_SECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_SECTION, GduSectionClass))
typedef struct _GduSectionClass GduSectionClass;
typedef struct _GduSection GduSection;
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index ef121a0..8b5f2f9 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -43,6 +43,8 @@
#include "gdu-section-encrypted.h"
#include "gdu-section-linux-md-drive.h"
#include "gdu-section-no-media.h"
+#include "gdu-section-drive.h"
+#include "gdu-section-volumes.h"
#include "bling-spinner.h"
struct _GduShellPrivate
@@ -198,7 +200,9 @@ details_update (GduShell *shell)
presentable_size = gdu_presentable_get_size (presentable);
if (presentable_size > 0) {
- strsize_long = gdu_util_get_size_for_display (presentable_size, TRUE);
+ strsize_long = gdu_util_get_size_for_display (presentable_size,
+ FALSE,
+ TRUE);
} else {
strsize_long = g_strdup (_("Unknown Size"));
}
@@ -504,15 +508,21 @@ compute_sections_to_show (GduShell *shell)
if (GDU_IS_LINUX_MD_DRIVE (shell->priv->presentable_now_showing)) {
+ sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_DRIVE);
+ sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_VOLUMES);
+
sections_to_show = g_list_append (sections_to_show,
(gpointer) GDU_TYPE_SECTION_LINUX_MD_DRIVE);
} else if (GDU_IS_DRIVE (shell->priv->presentable_now_showing) && device != NULL) {
+ sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_DRIVE);
+ sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_VOLUMES);
+
if (gdu_device_is_removable (device) && !gdu_device_is_media_available (device)) {
- sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_NO_MEDIA);
+ //sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_NO_MEDIA);
}
@@ -720,6 +730,21 @@ gdu_shell_update (GduShell *shell)
last_presentable = shell->priv->presentable_now_showing;
sections_to_show = compute_sections_to_show (shell);
+ if (GDU_IS_DRIVE (shell->priv->presentable_now_showing)) {
+ gtk_widget_hide (shell->priv->icon_image);
+ gtk_widget_hide (shell->priv->name_label);
+ gtk_widget_hide (shell->priv->details0_label);
+ gtk_widget_hide (shell->priv->details1_label);
+ gtk_widget_hide (shell->priv->details2_label);
+ gtk_widget_hide (shell->priv->details3_label);
+ } else {
+ gtk_widget_show (shell->priv->icon_image);
+ gtk_widget_show (shell->priv->name_label);
+ gtk_widget_show (shell->priv->details0_label);
+ gtk_widget_show (shell->priv->details1_label);
+ gtk_widget_show (shell->priv->details2_label);
+ gtk_widget_show (shell->priv->details3_label);
+ }
if (job_in_progress) {
gchar *desc;
@@ -797,7 +822,7 @@ gdu_shell_update (GduShell *shell)
gtk_box_pack_start (GTK_BOX (shell->priv->sections_vbox),
section,
- TRUE, TRUE, 0);
+ FALSE, FALSE, 0);
}
}
@@ -1867,7 +1892,7 @@ about_action_callback (GtkAction *action, gpointer user_data)
NULL);
gtk_show_about_dialog (GTK_WINDOW (shell->priv->app_window),
- "program-name", _("Palimpsest Disk Utility"),
+ "program-name", _("Disk Utility"),
"version", VERSION,
"copyright", "\xc2\xa9 2008 Red Hat, Inc.",
"authors", authors,
@@ -1888,6 +1913,7 @@ static const gchar *ui =
" </menu>"
" <menuitem action='quit'/>"
" </menu>"
+#if 0
" <menu action='edit'>"
" <menuitem action='mount'/>"
" <menuitem action='unmount'/>"
@@ -1904,6 +1930,7 @@ static const gchar *ui =
" <separator/>"
" <menuitem action='erase'/>"
" </menu>"
+#endif
" <menu action='help'>"
" <menuitem action='contents'/>"
" <menuitem action='about'/>"
@@ -1945,9 +1972,8 @@ static GtkActionEntry entries[] = {
{"stop", "gdu-raid-array-stop", N_("_Stop"), NULL, N_("Stop the array"), G_CALLBACK (stop_action_callback)},
{"erase", "nautilus-gdu", N_("_Erase"), NULL, N_("Erase the contents of the device"), G_CALLBACK (erase_action_callback)},
-
{"quit", GTK_STOCK_QUIT, N_("_Quit"), "<Ctrl>Q", N_("Quit"), G_CALLBACK (quit_action_callback)},
- {"contents", GTK_STOCK_HELP, N_("_Help"), "F1", N_("Get Help on Palimpsest Disk Utility"), G_CALLBACK (help_contents_action_callback)},
+ {"contents", GTK_STOCK_HELP, N_("_Help"), "F1", N_("Get Help on Disk Utility"), G_CALLBACK (help_contents_action_callback)},
{"about", GTK_STOCK_ABOUT, N_("_About"), NULL, NULL, G_CALLBACK (about_action_callback)}
};
@@ -2176,7 +2202,6 @@ create_window (GduShell *shell)
GtkWidget *vbox1;
GtkWidget *vbox2;
GtkWidget *menubar;
- GtkWidget *toolbar;
GtkAccelGroup *accel_group;
GtkWidget *hpane;
GtkWidget *tree_view_scrolled_window;
@@ -2189,13 +2214,14 @@ create_window (GduShell *shell)
GtkWidget *hbox;
GtkWidget *image;
GduPoolTreeModel *model;
+ GtkTreeViewColumn *column;
shell->priv->pool = gdu_pool_new ();
shell->priv->app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable (GTK_WINDOW (shell->priv->app_window), TRUE);
gtk_window_set_default_size (GTK_WINDOW (shell->priv->app_window), 800, 600);
- gtk_window_set_title (GTK_WINDOW (shell->priv->app_window), _("Palimpsest Disk Utility"));
+ gtk_window_set_title (GTK_WINDOW (shell->priv->app_window), _("Disk Utility"));
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (shell->priv->app_window), vbox);
@@ -2206,8 +2232,6 @@ create_window (GduShell *shell)
menubar = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/menubar");
gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
- toolbar = gtk_ui_manager_get_widget (shell->priv->ui_manager, "/toolbar");
- gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
/* tree view */
tree_view_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
@@ -2217,12 +2241,14 @@ create_window (GduShell *shell)
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,
- GDU_POOL_TREE_MODEL_FLAGS_NONE);
+ NULL,
+ GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES);
shell->priv->tree_view = gdu_pool_tree_view_new (model,
GDU_POOL_TREE_VIEW_FLAGS_NONE);
g_object_unref (model);
gtk_container_add (GTK_CONTAINER (tree_view_scrolled_window), shell->priv->tree_view);
+
/* --- */
vbox1 = gtk_vbox_new (FALSE, 0);
@@ -2261,7 +2287,7 @@ create_window (GduShell *shell)
/* --- */
vbox2 = gtk_vbox_new (FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (vbox2), 12);
+ //gtk_container_set_border_width (GTK_CONTAINER (vbox2), 12);
gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0);
/* --- */
@@ -2321,12 +2347,24 @@ create_window (GduShell *shell)
/* --- */
- shell->priv->sections_vbox = gtk_vbox_new (FALSE, 18);
- gtk_container_set_border_width (GTK_CONTAINER (shell->priv->sections_vbox), 8);
+ shell->priv->sections_vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (shell->priv->sections_vbox), 6);
gtk_box_pack_start (GTK_BOX (vbox2), shell->priv->sections_vbox, TRUE, TRUE, 0);
/* setup and add horizontal pane */
hpane = gtk_hpaned_new ();
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (label),
+ _("_Storage Devices"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), shell->priv->tree_view);
+
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (shell->priv->tree_view), 0);
+ gtk_tree_view_column_set_widget (column, label);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (shell->priv->tree_view), TRUE);
+ gtk_widget_show (label);
+
gtk_paned_add1 (GTK_PANED (hpane), tree_view_scrolled_window);
gtk_paned_add2 (GTK_PANED (hpane), vbox1);
//gtk_paned_set_position (GTK_PANED (hpane), 260);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]