[gnome-disk-utility/new-ui: 80/80] Add new GduButtonElement and GduButtonTable to unify UI and code



commit c1a15773b816cb860f2e38923320b4685d7c8376
Author: David Zeuthen <davidz redhat com>
Date:   Tue Sep 29 18:27:07 2009 -0400

    Add new GduButtonElement and GduButtonTable to unify UI and code

 src/gdu-gtk/Makefile.am              |    4 +
 src/gdu-gtk/gdu-button-element.c     |  306 +++++++++++++++++++++
 src/gdu-gtk/gdu-button-element.h     |   79 ++++++
 src/gdu-gtk/gdu-button-table.c       |  488 ++++++++++++++++++++++++++++++++++
 src/gdu-gtk/gdu-button-table.h       |   66 +++++
 src/gdu-gtk/gdu-details-element.h    |    2 +-
 src/gdu-gtk/gdu-gtk-types.h          |    2 +
 src/gdu-gtk/gdu-gtk.h                |    2 +
 src/palimpsest/gdu-section-drive.c   |  278 +++++++++-----------
 src/palimpsest/gdu-section-volumes.c |  260 ++++++++----------
 10 files changed, 1185 insertions(+), 302 deletions(-)
---
diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index 32eda03..8e804f7 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -41,6 +41,8 @@ libgdu_gtkinclude_HEADERS =              				\
 	gdu-details-table.h						\
 	gdu-details-element.h						\
 	gdu-error-dialog.h						\
+	gdu-button-element.h						\
+	gdu-button-table.h						\
 	$(NULL)
 
 libgdu_gtk_la_SOURCES =                 	               				\
@@ -59,6 +61,8 @@ libgdu_gtk_la_SOURCES =                 	               				\
 	gdu-details-table.h			gdu-details-table.c			\
 	gdu-details-element.h			gdu-details-element.c			\
 	gdu-error-dialog.h			gdu-error-dialog.c			\
+	gdu-button-element.h			gdu-button-element.c			\
+	gdu-button-table.h			gdu-button-table.c			\
 	$(NULL)
 
 libgdu_gtk_la_CPPFLAGS = 				\
diff --git a/src/gdu-gtk/gdu-button-element.c b/src/gdu-gtk/gdu-button-element.c
new file mode 100644
index 0000000..63f17c4
--- /dev/null
+++ b/src/gdu-gtk/gdu-button-element.c
@@ -0,0 +1,306 @@
+/* -*- 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 GduButtonElementPrivate
+{
+        gchar *primary_text;
+        gchar *secondary_text;
+        gchar *icon_name;
+        gboolean visible;
+};
+
+enum
+{
+        PROP_0,
+        PROP_ICON_NAME,
+        PROP_PRIMARY_TEXT,
+        PROP_SECONDARY_TEXT,
+        PROP_VISIBLE,
+};
+
+enum
+{
+        CHANGED_SIGNAL,
+        CLICKED_SIGNAL,
+        LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0,};
+
+G_DEFINE_TYPE (GduButtonElement, gdu_button_element, G_TYPE_OBJECT)
+
+static void
+gdu_button_element_finalize (GObject *object)
+{
+        GduButtonElement *element = GDU_BUTTON_ELEMENT (object);
+
+        g_free (element->priv->icon_name);
+        g_free (element->priv->primary_text);
+        g_free (element->priv->secondary_text);
+
+        if (G_OBJECT_CLASS (gdu_button_element_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_button_element_parent_class)->finalize (object);
+}
+
+static void
+gdu_button_element_get_property (GObject    *object,
+                                  guint       property_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+        GduButtonElement *element = GDU_BUTTON_ELEMENT (object);
+
+        switch (property_id) {
+        case PROP_ICON_NAME:
+                g_value_set_string (value, gdu_button_element_get_icon_name (element));
+                break;
+
+        case PROP_PRIMARY_TEXT:
+                g_value_set_string (value, gdu_button_element_get_primary_text (element));
+                break;
+
+        case PROP_SECONDARY_TEXT:
+                g_value_set_string (value, gdu_button_element_get_primary_text (element));
+                break;
+
+        case PROP_VISIBLE:
+                g_value_set_boolean (value, gdu_button_element_get_visible (element));
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_button_element_set_property (GObject      *object,
+                                  guint         property_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+        GduButtonElement *element = GDU_BUTTON_ELEMENT (object);
+
+        switch (property_id) {
+        case PROP_ICON_NAME:
+                gdu_button_element_set_icon_name (element, g_value_get_string (value));
+                break;
+
+        case PROP_PRIMARY_TEXT:
+                gdu_button_element_set_primary_text (element, g_value_get_string (value));
+                break;
+
+        case PROP_SECONDARY_TEXT:
+                gdu_button_element_set_secondary_text (element, g_value_get_string (value));
+                break;
+
+        case PROP_VISIBLE:
+                gdu_button_element_set_visible (element, g_value_get_boolean (value));
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_button_element_init (GduButtonElement *element)
+{
+        element->priv = G_TYPE_INSTANCE_GET_PRIVATE (element,
+                                                     GDU_TYPE_BUTTON_ELEMENT,
+                                                     GduButtonElementPrivate);
+
+}
+
+static void
+gdu_button_element_class_init (GduButtonElementClass *klass)
+{
+        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+        g_type_class_add_private (klass, sizeof (GduButtonElementPrivate));
+
+        gobject_class->get_property        = gdu_button_element_get_property;
+        gobject_class->set_property        = gdu_button_element_set_property;
+        gobject_class->finalize            = gdu_button_element_finalize;
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_ICON_NAME,
+                                         g_param_spec_string ("icon-name",
+                                                             NULL,
+                                                             NULL,
+                                                             NULL,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT));
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_PRIMARY_TEXT,
+                                         g_param_spec_string ("primary-text",
+                                                             NULL,
+                                                             NULL,
+                                                             NULL,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT));
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_SECONDARY_TEXT,
+                                         g_param_spec_string ("secondary-text",
+                                                             NULL,
+                                                             NULL,
+                                                             NULL,
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_CONSTRUCT));
+
+        g_object_class_install_property (gobject_class,
+                                         PROP_VISIBLE,
+                                         g_param_spec_boolean ("visible",
+                                                               NULL,
+                                                               NULL,
+                                                               TRUE,
+                                                               G_PARAM_READABLE |
+                                                               G_PARAM_WRITABLE |
+                                                               G_PARAM_CONSTRUCT));
+
+        signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+                                                GDU_TYPE_BUTTON_ELEMENT,
+                                                G_SIGNAL_RUN_LAST,
+                                                G_STRUCT_OFFSET (GduButtonElementClass, changed),
+                                                NULL,
+                                                NULL,
+                                                g_cclosure_marshal_VOID__VOID,
+                                                G_TYPE_NONE,
+                                                0);
+
+        signals[CLICKED_SIGNAL] = g_signal_new ("clicked",
+                                                GDU_TYPE_BUTTON_ELEMENT,
+                                                G_SIGNAL_RUN_LAST,
+                                                G_STRUCT_OFFSET (GduButtonElementClass, clicked),
+                                                NULL,
+                                                NULL,
+                                                g_cclosure_marshal_VOID__VOID,
+                                                G_TYPE_NONE,
+                                                0);
+}
+
+GduButtonElement *
+gdu_button_element_new (const gchar       *icon_name,
+                        const gchar       *primary_text,
+                        const gchar       *secondary_text)
+{
+        return GDU_BUTTON_ELEMENT (g_object_new (GDU_TYPE_BUTTON_ELEMENT,
+                                                 "icon-name", icon_name,
+                                                 "primary-text", primary_text,
+                                                 "secondary-text", secondary_text,
+                                                 NULL));
+}
+
+const gchar *
+gdu_button_element_get_icon_name (GduButtonElement *element)
+{
+        g_return_val_if_fail (GDU_IS_BUTTON_ELEMENT (element), NULL);
+        return element->priv->icon_name;
+}
+
+const gchar *
+gdu_button_element_get_primary_text (GduButtonElement *element)
+{
+        g_return_val_if_fail (GDU_IS_BUTTON_ELEMENT (element), NULL);
+        return element->priv->primary_text;
+}
+
+const gchar *
+gdu_button_element_get_secondary_text (GduButtonElement *element)
+{
+        g_return_val_if_fail (GDU_IS_BUTTON_ELEMENT (element), NULL);
+        return element->priv->secondary_text;
+}
+
+gboolean
+gdu_button_element_get_visible (GduButtonElement *element)
+{
+        g_return_val_if_fail (GDU_IS_BUTTON_ELEMENT (element), FALSE);
+        return element->priv->visible;
+}
+
+
+void
+gdu_button_element_set_icon_name (GduButtonElement *element,
+                                  const gchar      *icon_name)
+{
+        g_return_if_fail (GDU_IS_BUTTON_ELEMENT (element));
+        if (g_strcmp0 (element->priv->icon_name, icon_name) != 0) {
+                g_free (element->priv->icon_name);
+                element->priv->icon_name = g_strdup (icon_name);
+                g_object_notify (G_OBJECT (element), "icon-name");
+                g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+        }
+}
+
+void
+gdu_button_element_set_primary_text (GduButtonElement *element,
+                                     const gchar      *primary_text)
+{
+        g_return_if_fail (GDU_IS_BUTTON_ELEMENT (element));
+        if (g_strcmp0 (element->priv->primary_text, primary_text) != 0) {
+                g_free (element->priv->primary_text);
+                element->priv->primary_text = g_strdup (primary_text);
+                g_object_notify (G_OBJECT (element), "primary-text");
+                g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+        }
+}
+
+void
+gdu_button_element_set_secondary_text (GduButtonElement *element,
+                                       const gchar      *secondary_text)
+{
+        g_return_if_fail (GDU_IS_BUTTON_ELEMENT (element));
+        if (g_strcmp0 (element->priv->secondary_text, secondary_text) != 0) {
+                g_free (element->priv->secondary_text);
+                element->priv->secondary_text = g_strdup (secondary_text);
+                g_object_notify (G_OBJECT (element), "secondary-text");
+                g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+        }
+}
+
+void
+gdu_button_element_set_visible (GduButtonElement *element,
+                                gboolean          visible)
+{
+        g_return_if_fail (GDU_IS_BUTTON_ELEMENT (element));
+        if (element->priv->visible != visible) {
+                element->priv->visible = visible;
+                g_object_notify (G_OBJECT (element), "visible");
+                g_signal_emit (element, signals[CHANGED_SIGNAL], 0);
+        }
+}
diff --git a/src/gdu-gtk/gdu-button-element.h b/src/gdu-gtk/gdu-button-element.h
new file mode 100644
index 0000000..da94bfd
--- /dev/null
+++ b/src/gdu-gtk/gdu-button-element.h
@@ -0,0 +1,79 @@
+/* -*- 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_BUTTON_ELEMENT_H
+#define __GDU_BUTTON_ELEMENT_H
+
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_BUTTON_ELEMENT         (gdu_button_element_get_type())
+#define GDU_BUTTON_ELEMENT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_BUTTON_ELEMENT, GduButtonElement))
+#define GDU_BUTTON_ELEMENT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_BUTTON_ELEMENT, GduButtonElementClass))
+#define GDU_IS_BUTTON_ELEMENT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_BUTTON_ELEMENT))
+#define GDU_IS_BUTTON_ELEMENT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_BUTTON_ELEMENT))
+#define GDU_BUTTON_ELEMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_BUTTON_ELEMENT, GduButtonElementClass))
+
+typedef struct GduButtonElementClass   GduButtonElementClass;
+typedef struct GduButtonElementPrivate GduButtonElementPrivate;
+
+struct GduButtonElement
+{
+        GObject parent;
+
+        /*< private >*/
+        GduButtonElementPrivate *priv;
+};
+
+struct GduButtonElementClass
+{
+        GObjectClass parent_class;
+
+        /* signals */
+        void (*changed) (GduButtonElement *element);
+
+        /* signals */
+        void (*clicked) (GduButtonElement *element);
+};
+
+GType              gdu_button_element_get_type             (void) G_GNUC_CONST;
+GduButtonElement*  gdu_button_element_new                  (const gchar       *icon_name,
+                                                            const gchar       *primary_text,
+                                                            const gchar       *secondary_text);
+const gchar       *gdu_button_element_get_icon_name        (GduButtonElement *element);
+const gchar       *gdu_button_element_get_primary_text     (GduButtonElement *element);
+const gchar       *gdu_button_element_get_secondary_text   (GduButtonElement *element);
+gboolean           gdu_button_element_get_visible          (GduButtonElement *element);
+void               gdu_button_element_set_icon_name        (GduButtonElement *element,
+                                                            const gchar      *icon_name);
+void               gdu_button_element_set_primary_text     (GduButtonElement  *element,
+                                                            const gchar       *primary_text);
+void               gdu_button_element_set_secondary_text   (GduButtonElement  *element,
+                                                            const gchar       *primary_text);
+void               gdu_button_element_set_visible          (GduButtonElement  *element,
+                                                            gboolean           visible);
+
+G_END_DECLS
+
+#endif  /* __GDU_BUTTON_ELEMENT_H */
+
diff --git a/src/gdu-gtk/gdu-button-table.c b/src/gdu-gtk/gdu-button-table.c
new file mode 100644
index 0000000..dc63d0e
--- /dev/null
+++ b/src/gdu-gtk/gdu-button-table.c
@@ -0,0 +1,488 @@
+/* -*- 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 GduButtonTablePrivate
+{
+        guint      num_columns;
+        GPtrArray *elements;
+
+        GPtrArray *column_tables;
+
+        GPtrArray *element_data_array;
+};
+
+enum
+{
+        PROP_0,
+        PROP_NUM_COLUMNS,
+        PROP_ELEMENTS,
+};
+
+static void do_relayout (GduButtonTable *table);
+
+G_DEFINE_TYPE (GduButtonTable, gdu_button_table, GTK_TYPE_HBOX)
+
+static void
+gdu_button_table_finalize (GObject *object)
+{
+        GduButtonTable *table = GDU_BUTTON_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_button_table_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_button_table_parent_class)->finalize (object);
+}
+
+static void
+gdu_button_table_get_property (GObject    *object,
+                               guint       property_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+        GduButtonTable *table = GDU_BUTTON_TABLE (object);
+
+        switch (property_id) {
+        case PROP_NUM_COLUMNS:
+                g_value_set_uint (value, gdu_button_table_get_num_columns (table));
+                break;
+
+        case PROP_ELEMENTS:
+                g_value_take_boxed (value, gdu_button_table_get_elements (table));
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_button_table_set_property (GObject      *object,
+                               guint         property_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+        GduButtonTable *table = GDU_BUTTON_TABLE (object);
+
+        switch (property_id) {
+        case PROP_NUM_COLUMNS:
+                gdu_button_table_set_num_columns (table, g_value_get_uint (value));
+                break;
+
+        case PROP_ELEMENTS:
+                gdu_button_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_button_table_init (GduButtonTable *table)
+{
+        table->priv = G_TYPE_INSTANCE_GET_PRIVATE (table,
+                                                   GDU_TYPE_BUTTON_TABLE,
+                                                   GduButtonTablePrivate);
+
+}
+
+static void
+gdu_button_table_constructed (GObject *object)
+{
+        GduButtonTable *table = GDU_BUTTON_TABLE (object);
+
+        gtk_box_set_homogeneous (GTK_BOX (table), TRUE);
+        gtk_box_set_spacing (GTK_BOX (table), 12);
+
+        if (G_OBJECT_CLASS (gdu_button_table_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_button_table_parent_class)->constructed (object);
+}
+
+static void
+gdu_button_table_class_init (GduButtonTableClass *klass)
+{
+        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+        g_type_class_add_private (klass, sizeof (GduButtonTablePrivate));
+
+        gobject_class->get_property        = gdu_button_table_get_property;
+        gobject_class->set_property        = gdu_button_table_set_property;
+        gobject_class->constructed         = gdu_button_table_constructed;
+        gobject_class->finalize            = gdu_button_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_button_table_new (guint      num_columns,
+                      GPtrArray *elements)
+{
+        return GTK_WIDGET (g_object_new (GDU_TYPE_BUTTON_TABLE,
+                                         "num-columns", num_columns,
+                                         "elements", elements,
+                                         NULL));
+}
+
+guint
+gdu_button_table_get_num_columns (GduButtonTable *table)
+{
+        g_return_val_if_fail (GDU_IS_BUTTON_TABLE (table), 0);
+        return table->priv->num_columns;
+}
+
+GPtrArray *
+gdu_button_table_get_elements (GduButtonTable *table)
+{
+        g_return_val_if_fail (GDU_IS_BUTTON_TABLE (table), NULL);
+        return table->priv->elements != NULL ? g_ptr_array_ref (table->priv->elements) : NULL;
+}
+
+void
+gdu_button_table_set_num_columns (GduButtonTable *table,
+                                   guint            num_columns)
+{
+        g_return_if_fail (GDU_IS_BUTTON_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_button_table_set_elements (GduButtonTable *table,
+                                GPtrArray       *elements)
+{
+        g_return_if_fail (GDU_IS_BUTTON_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 {
+        GduButtonTable *table;
+        GduButtonElement *element;
+
+        GtkWidget *button;
+} ElementData;
+
+static void on_button_element_changed (GduButtonElement *element,
+                                       ElementData       *data);
+
+static void on_button_clicked (GtkButton *button,
+                               gpointer   user_data);
+
+static void
+element_data_free (ElementData *data)
+{
+        g_signal_handlers_disconnect_by_func (data->element,
+                                              G_CALLBACK (on_button_element_changed),
+                                              data);
+        g_object_unref (data->element);
+#if 0
+        g_signal_handlers_disconnect_by_func (data->action_label,
+                                              G_CALLBACK (on_activate_link),
+                                              data);
+        g_object_unref (data->action_label);
+#endif
+        g_free (data);
+}
+
+static void
+on_button_element_changed (GduButtonElement *element,
+                           ElementData       *data)
+{
+        do_relayout (data->table);
+#if 0
+        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_button_element_get_heading (element));
+        gtk_label_set_markup (GTK_LABEL (data->heading_label), s);
+        g_free (s);
+
+        text = gdu_button_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_button_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_button_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_button_element_get_action_text (element);
+        action_uri = gdu_button_element_get_action_uri (element);
+        action_tooltip = gdu_button_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_button_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_button_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);
+        }
+#endif
+}
+
+static void
+on_button_clicked (GtkButton  *button,
+                   gpointer    user_data)
+{
+        ElementData *data = user_data;
+        g_signal_emit_by_name (data->element, "clicked");
+}
+
+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
+do_relayout (GduButtonTable *table)
+{
+        GList *children;
+        GList *l;
+        guint n;
+        guint m;
+        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, m = 0; n < table->priv->elements->len; n++) {
+                GduButtonElement *element = GDU_BUTTON_ELEMENT (table->priv->elements->pdata[n]);
+                guint column_table_number;
+                GtkWidget *column_table;
+                ElementData *data;
+
+                /* Always connect to ::changed since visibility may change */
+                data = g_new0 (ElementData, 1);
+                data->table = table;
+                data->element = g_object_ref (element);
+                g_ptr_array_add (table->priv->element_data_array, data);
+                g_signal_connect (element,
+                                  "changed",
+                                  G_CALLBACK (on_button_element_changed),
+                                  data);
+
+                if (!gdu_button_element_get_visible (element)) {
+                        continue;
+                }
+
+                column_table_number = m % table->priv->num_columns;
+                if (column_table_number == 0)
+                        row++;
+                column_table = table->priv->column_tables->pdata[column_table_number];
+                m++;
+
+                data->button = create_button (gdu_button_element_get_icon_name (element),
+                                              gdu_button_element_get_primary_text (element),
+                                              gdu_button_element_get_secondary_text (element));
+                gtk_widget_show (data->button);
+
+                gtk_table_attach (GTK_TABLE (column_table),
+                                  data->button,
+                                  0, 1, row, row + 1,
+                                  GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+
+                g_signal_connect (data->button,
+                                  "clicked",
+                                  G_CALLBACK (on_button_clicked),
+                                  data);
+        }
+        gtk_widget_show_all (GTK_WIDGET (table));
+
+ out:
+        ;
+}
diff --git a/src/gdu-gtk/gdu-button-table.h b/src/gdu-gtk/gdu-button-table.h
new file mode 100644
index 0000000..a1ae15b
--- /dev/null
+++ b/src/gdu-gtk/gdu-button-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_BUTTON_TABLE_H
+#define __GDU_BUTTON_TABLE_H
+
+#include <gdu-gtk/gdu-gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_BUTTON_TABLE         (gdu_button_table_get_type())
+#define GDU_BUTTON_TABLE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_BUTTON_TABLE, GduButtonTable))
+#define GDU_BUTTON_TABLE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_BUTTON_TABLE, GduButtonTableClass))
+#define GDU_IS_BUTTON_TABLE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_BUTTON_TABLE))
+#define GDU_IS_BUTTON_TABLE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_BUTTON_TABLE))
+#define GDU_BUTTON_TABLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_BUTTON_TABLE, GduButtonTableClass))
+
+typedef struct GduButtonTableClass   GduButtonTableClass;
+typedef struct GduButtonTablePrivate GduButtonTablePrivate;
+
+struct GduButtonTable
+{
+        GtkHBox parent;
+
+        /*< private >*/
+        GduButtonTablePrivate *priv;
+};
+
+struct GduButtonTableClass
+{
+        GtkHBoxClass parent_class;
+};
+
+GType       gdu_button_table_get_type        (void) G_GNUC_CONST;
+GtkWidget*  gdu_button_table_new             (guint            num_columns,
+                                              GPtrArray       *elements);
+guint       gdu_button_table_get_num_columns (GduButtonTable *table);
+GPtrArray  *gdu_button_table_get_elements    (GduButtonTable *table);
+void        gdu_button_table_set_num_columns (GduButtonTable *table,
+                                              guint            num_columns);
+void        gdu_button_table_set_elements    (GduButtonTable *table,
+                                              GPtrArray       *elements);
+
+G_END_DECLS
+
+#endif  /* __GDU_BUTTON_TABLE_H */
+
diff --git a/src/gdu-gtk/gdu-details-element.h b/src/gdu-gtk/gdu-details-element.h
index d7ebc43..ebc0854 100644
--- a/src/gdu-gtk/gdu-details-element.h
+++ b/src/gdu-gtk/gdu-details-element.h
@@ -95,5 +95,5 @@ void                gdu_details_element_set_is_spinning    (GduDetailsElement *e
 
 G_END_DECLS
 
-#endif  /* __GDU_SIZE_WIDGET_H */
+#endif  /* __GDU_DETAILS_ELEMENT_H */
 
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index 4103ee8..843f0ce 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -48,6 +48,8 @@ typedef struct GduVolumeGrid               GduVolumeGrid;
 typedef struct GduDetailsTable             GduDetailsTable;
 typedef struct GduDetailsElement           GduDetailsElement;
 typedef struct GduErrorDialog              GduErrorDialog;
+typedef struct GduButtonElement            GduButtonElement;
+typedef struct GduButtonTable              GduButtonTable;
 
 G_END_DECLS
 
diff --git a/src/gdu-gtk/gdu-gtk.h b/src/gdu-gtk/gdu-gtk.h
index 360ddbc..c5be964 100644
--- a/src/gdu-gtk/gdu-gtk.h
+++ b/src/gdu-gtk/gdu-gtk.h
@@ -40,6 +40,8 @@
 #include <gdu-gtk/gdu-details-table.h>
 #include <gdu-gtk/gdu-details-element.h>
 #include <gdu-gtk/gdu-error-dialog.h>
+#include <gdu-gtk/gdu-button-element.h>
+#include <gdu-gtk/gdu-button-table.h>
 #undef __GDU_GTK_INSIDE_GDU_GTK_H
 
 G_BEGIN_DECLS
diff --git a/src/palimpsest/gdu-section-drive.c b/src/palimpsest/gdu-section-drive.c
index 8707168..b55cf90 100644
--- a/src/palimpsest/gdu-section-drive.c
+++ b/src/palimpsest/gdu-section-drive.c
@@ -40,12 +40,39 @@ struct _GduSectionDrivePrivate
         GduDetailsElement *connection_element;
         GduDetailsElement *partitioning_element;
         GduDetailsElement *smart_element;
+
+        GduButtonElement *cddvd_button;
+        GduButtonElement *format_button;
+        GduButtonElement *eject_button;
+        GduButtonElement *detach_button;
+        GduButtonElement *smart_button;
 };
 
 G_DEFINE_TYPE (GduSectionDrive, gdu_section_drive, GDU_TYPE_SECTION)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+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
 gdu_section_drive_finalize (GObject *object)
 {
@@ -169,78 +196,45 @@ gdu_section_drive_update (GduSection *_section)
         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;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
+        /* buttons */
+        if (d != NULL &&
+            gdu_device_drive_ata_smart_get_is_available (d) &&
+            gdu_device_drive_ata_smart_get_time_collected (d) > 0) {
+                gdu_button_element_set_visible (section->priv->smart_button, TRUE);
+        } else {
+                gdu_button_element_set_visible (section->priv->smart_button, FALSE);
+        }
 
-static gboolean
-has_strv0 (gchar **strv, const gchar *str)
-{
-        gboolean ret;
-        guint n;
+        if (d != NULL && gdu_device_drive_get_is_media_ejectable (d)) {
+                gdu_button_element_set_visible (section->priv->eject_button, TRUE);
+        } else {
+                gdu_button_element_set_visible (section->priv->eject_button, FALSE);
+        }
 
-        ret = FALSE;
+        if (d != NULL && gdu_device_drive_get_can_detach (d)) {
+                gdu_button_element_set_visible (section->priv->detach_button, TRUE);
+        } else {
+                gdu_button_element_set_visible (section->priv->detach_button, FALSE);
+        }
 
-        for (n = 0; strv != NULL && strv[n] != NULL; n++) {
-                if (g_strcmp0 (strv[n], str) == 0) {
-                        ret = TRUE;
-                        goto out;
-                }
+        if (d != NULL && has_strv0 (gdu_device_drive_get_media_compatibility (d), "optical_cd")) {
+                gdu_button_element_set_visible (section->priv->cddvd_button, TRUE);
+                gdu_button_element_set_visible (section->priv->format_button, FALSE);
+        } else {
+                gdu_button_element_set_visible (section->priv->cddvd_button, FALSE);
+                gdu_button_element_set_visible (section->priv->format_button, TRUE);
         }
 
  out:
-        return ret;
+        if (d != NULL)
+                g_object_unref (d);
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
-on_cddvd_button_clicked (GtkButton *button,
-                         gpointer   user_data)
+on_cddvd_button_clicked (GduButtonElement *button_element,
+                         gpointer          user_data)
 {
         GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
         GAppLaunchContext *launch_context;
@@ -297,8 +291,8 @@ on_cddvd_button_clicked (GtkButton *button,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-on_smart_button_clicked (GtkButton *button,
-                         gpointer   user_data)
+on_smart_button_clicked (GduButtonElement *button_element,
+                         gpointer          user_data)
 {
         GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
         GtkWindow *toplevel;
@@ -337,8 +331,8 @@ eject_op_callback (GduDevice *device,
 }
 
 static void
-on_eject_button_clicked (GtkButton *button,
-                         gpointer   user_data)
+on_eject_button_clicked (GduButtonElement *button_element,
+                         gpointer          user_data)
 {
         GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
         GduDevice *d;
@@ -381,8 +375,8 @@ detach_op_callback (GduDevice *device,
 }
 
 static void
-on_detach_button_clicked (GtkButton *button,
-                          gpointer   user_data)
+on_detach_button_clicked (GduButtonElement *button_element,
+                          gpointer          user_data)
 {
         GduSectionDrive *section = GDU_SECTION_DRIVE (user_data);
         GduDevice *d;
@@ -403,33 +397,6 @@ on_detach_button_clicked (GtkButton *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
 gdu_section_drive_constructed (GObject *object)
 {
         GduSectionDrive *section = GDU_SECTION_DRIVE (object);
@@ -437,14 +404,12 @@ gdu_section_drive_constructed (GObject *object)
         GtkWidget *label;
         GtkWidget *table;
         GtkWidget *vbox;
-        GtkWidget *button;
         gchar *s;
         GduPresentable *p;
         GduDevice *d;
         GPtrArray *elements;
         GduDetailsElement *element;
-        guint row;
-        guint column;
+        GduButtonElement *button_element;
 
         d = NULL;
 
@@ -500,8 +465,7 @@ gdu_section_drive_constructed (GObject *object)
         g_ptr_array_add (elements, element);
         section->priv->smart_element = element;
 
-        table = gdu_details_table_new (2,
-                                       elements);
+        table = gdu_details_table_new (2, elements);
         g_ptr_array_unref (elements);
         gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
 
@@ -511,65 +475,65 @@ gdu_section_drive_constructed (GObject *object)
         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
         gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
 
-        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);
-        }
+        elements = g_ptr_array_new_with_free_func (g_object_unref);
 
-        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);
-        }
+        button_element = gdu_button_element_new ("brasero",
+                                                 _("Open CD/_DVD Application"),
+                                                 _("Create and copy CDs and DVDs"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_cddvd_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->cddvd_button = button_element;
+
+        button_element = gdu_button_element_new ("nautilus-gdu",
+                                                 _("Format _Drive"),
+                                                 _("Delete all data and partition the drive"));
+#if 0
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_format_button_clicked),
+                          section);
+#endif
+        g_ptr_array_add (elements, button_element);
+        section->priv->format_button = button_element;
+
+        button_element = gdu_button_element_new ("gdu-check-disk",
+                                                 _("SM_ART Data"),
+                                                 _("View SMART data and run self-tests"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_smart_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->smart_button = button_element;
+
+        button_element = gdu_button_element_new ("gdu-eject",
+                                                 _("_Eject"),
+                                                 _("Eject media from the drive"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_eject_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->eject_button = button_element;
+
+        button_element = gdu_button_element_new ("gdu-detach",
+                                                 _("Safe Rem_oval"),
+                                                 _("Power down the drive so it can be removed"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_detach_button_clicked),
+                          section);
+        g_ptr_array_add (elements, button_element);
+        section->priv->detach_button = button_element;
+
+        table = gdu_button_table_new (2, elements);
+        g_ptr_array_unref (elements);
+        gtk_container_add (GTK_CONTAINER (align), table);
 
         /* -------------------------------------------------------------------------------- */
 
diff --git a/src/palimpsest/gdu-section-volumes.c b/src/palimpsest/gdu-section-volumes.c
index 576d5bc..12741ab 100644
--- a/src/palimpsest/gdu-section-volumes.c
+++ b/src/palimpsest/gdu-section-volumes.c
@@ -35,7 +35,7 @@ struct _GduSectionVolumesPrivate
 
         GtkWidget *grid;
         GtkWidget *details_table;
-        GtkWidget *buttons_align;
+        GtkWidget *button_table;
 
         /* shared between all volume types */
         GduDetailsElement *usage_element;
@@ -49,8 +49,12 @@ struct _GduSectionVolumesPrivate
         GduDetailsElement *fs_label_element;
         GduDetailsElement *fs_mount_point_element;
 
-        GtkWidget *fs_mount_button;
-        GtkWidget *fs_unmount_button;
+        GduButtonElement *fs_mount_button;
+        GduButtonElement *fs_unmount_button;
+        GduButtonElement *fs_check_button;
+        GduButtonElement *format_button;
+        GduButtonElement *partition_edit_button;
+        GduButtonElement *partition_delete_button;
 };
 
 G_DEFINE_TYPE (GduSectionVolumes, gdu_section_volumes, GDU_TYPE_SECTION)
@@ -71,78 +75,6 @@ gdu_section_volumes_finalize (GObject *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,
@@ -168,8 +100,8 @@ unmount_op_callback (GduDevice *device,
 }
 
 static void
-on_unmount_button_clicked (GtkButton *button,
-                           gpointer   user_data)
+on_unmount_button_clicked (GduButtonElement *button_element,
+                           gpointer          user_data)
 {
         GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
 
@@ -221,8 +153,8 @@ mount_op_callback (GduDevice *device,
 }
 
 static void
-on_mount_button_clicked (GtkButton *button,
-                         gpointer   user_data)
+on_mount_button_clicked (GduButtonElement *button_element,
+                         gpointer          user_data)
 {
         GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
         GduPresentable *v;
@@ -262,10 +194,22 @@ gdu_section_volumes_update (GduSection *_section)
         gchar *s;
         gchar *s2;
         const gchar *usage;
+        gboolean show_fs_mount_button;
+        gboolean show_fs_unmount_button;
+        gboolean show_fs_check_button;
+        gboolean show_format_button;
+        gboolean show_partition_edit_button;
+        gboolean show_partition_delete_button;
 
         v = NULL;
         d = NULL;
         usage = "";
+        show_fs_mount_button = FALSE;
+        show_fs_unmount_button = FALSE;
+        show_fs_check_button = FALSE;
+        show_format_button = FALSE;
+        show_partition_edit_button = FALSE;
+        show_partition_delete_button = FALSE;
 
         v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
 
@@ -281,21 +225,6 @@ gdu_section_volumes_update (GduSection *_section)
 
         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);
@@ -336,54 +265,10 @@ gdu_section_volumes_update (GduSection *_section)
 
                         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);
         }
 
         /* ---------------------------------------------------------------------------------------------------- */
@@ -407,6 +292,9 @@ gdu_section_volumes_update (GduSection *_section)
                         gdu_details_element_set_text (section->priv->partition_element, s);
                         /* TODO: include partition flags... */
                         g_free (s);
+
+                        show_partition_edit_button = TRUE;
+                        show_partition_delete_button = TRUE;
                 } else {
                         gdu_details_element_set_text (section->priv->partition_element, "â??");
                 }
@@ -466,15 +354,14 @@ gdu_section_volumes_update (GduSection *_section)
                         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);
+                        show_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);
+                        show_fs_mount_button = TRUE;
                 }
 
+                show_fs_check_button = TRUE;
+
         } else if (g_strcmp0 (usage, "") == 0 &&
                    d != NULL && gdu_device_is_partition (d) &&
                    g_strcmp0 (gdu_device_partition_get_scheme (d), "mbr") == 0 &&
@@ -492,6 +379,14 @@ gdu_section_volumes_update (GduSection *_section)
                 g_object_unref (drive_device);
         }
 
+        show_format_button = TRUE;
+
+        gdu_button_element_set_visible (section->priv->fs_mount_button, show_fs_mount_button);
+        gdu_button_element_set_visible (section->priv->fs_unmount_button, show_fs_unmount_button);
+        gdu_button_element_set_visible (section->priv->fs_check_button, show_fs_check_button);
+        gdu_button_element_set_visible (section->priv->format_button, show_format_button);
+        gdu_button_element_set_visible (section->priv->partition_edit_button, show_partition_edit_button);
+        gdu_button_element_set_visible (section->priv->partition_delete_button, show_partition_delete_button);
 
  out:
         if (d != NULL)
@@ -517,6 +412,8 @@ static void
 gdu_section_volumes_constructed (GObject *object)
 {
         GduSectionVolumes *section = GDU_SECTION_VOLUMES (object);
+        GPtrArray *button_elements;
+        GduButtonElement *button_element;
         GtkWidget *grid;
         GtkWidget *align;
         GtkWidget *label;
@@ -562,9 +459,84 @@ gdu_section_volumes_constructed (GObject *object)
 
         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);
 
+        table = gdu_button_table_new (2, NULL);
+        section->priv->button_table = table;
+        gtk_container_add (GTK_CONTAINER (align), table);
+        button_elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+        button_element = gdu_button_element_new ("gdu-mount",
+                                                 _("_Mount Volume"),
+                                                 _("Mount the volume"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_mount_button_clicked),
+                          section);
+        g_ptr_array_add (button_elements, button_element);
+        section->priv->fs_mount_button = button_element;
+
+        button_element = gdu_button_element_new ("gdu-unmount",
+                                                 _("_Unmount Volume"),
+                                                 _("Unmount the volume"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_unmount_button_clicked),
+                          section);
+        g_ptr_array_add (button_elements, button_element);
+        section->priv->fs_unmount_button = button_element;
+
+        button_element = gdu_button_element_new ("gdu-check-disk",
+                                                 _("_Check Filesystem"),
+                                                 _("Check the filesystem for errors"));
+#if 0
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_fsck_button_clicked),
+                          section);
+#endif
+        g_ptr_array_add (button_elements, button_element);
+        section->priv->fs_check_button = button_element;
+
+        button_element = gdu_button_element_new ("nautilus-gdu",
+                                                 _("Fo_rmat Volume"),
+                                                 _("Format the volume"));
+#if 0
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_format_button_clicked),
+                          section);
+#endif
+        g_ptr_array_add (button_elements, button_element);
+        section->priv->format_button = button_element;
+
+        button_element = gdu_button_element_new (GTK_STOCK_EDIT,
+                                                 _("Ed_it Partition"),
+                                                 _("Change partition type and flags"));
+#if 0
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_partition_edit_button_clicked),
+                          section);
+#endif
+        g_ptr_array_add (button_elements, button_element);
+        section->priv->partition_edit_button = button_element;
+
+        button_element = gdu_button_element_new (GTK_STOCK_DELETE,
+                                                 _("D_elete Partition"),
+                                                 _("Delete the partition"));
+#if 0
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_partition_delete_button_clicked),
+                          section);
+#endif
+        g_ptr_array_add (button_elements, button_element);
+        section->priv->partition_delete_button = button_element;
+
+        gdu_button_table_set_elements (GDU_BUTTON_TABLE (section->priv->button_table), button_elements);
+        g_ptr_array_unref (button_elements);
+
         /* -------------------------------------------------------------------------------- */
 
         gtk_widget_show_all (GTK_WIDGET (section));



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