/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-alert-dialog.c: An HIG compliant alert dialog. The Mate Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Mate Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Mate Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <config.h> #include "eel-alert-dialog.h" #include "eel-gtk-macros.h" #include <glib/gi18n-lib.h> #include <gtk/gtk.h> #include <string.h> enum { PROP_0, PROP_ALERT_TYPE, PROP_BUTTONS }; struct _EelAlertDialogDetails { GtkWidget *image; GtkWidget *primary_label; GtkWidget *secondary_label; GtkWidget *details_expander; GtkWidget *details_label; GtkMessageType type; }; static gpointer parent_class; static void eel_alert_dialog_finalize (GObject *object); static void eel_alert_dialog_class_init (EelAlertDialogClass *klass); static void eel_alert_dialog_init (EelAlertDialog *dialog); static void eel_alert_dialog_style_set (GtkWidget *widget, GtkStyle *prev_style); static void eel_alert_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void eel_alert_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void eel_alert_dialog_add_buttons (EelAlertDialog *alert_dialog, GtkButtonsType buttons); GType eel_alert_dialog_get_type (void) { static GType dialog_type = 0; if (!dialog_type) { const GTypeInfo dialog_info = { sizeof (EelAlertDialogClass), NULL, NULL, (GClassInitFunc) eel_alert_dialog_class_init, NULL, NULL, sizeof (EelAlertDialog), 0, (GInstanceInitFunc) eel_alert_dialog_init, }; dialog_type = g_type_register_static (GTK_TYPE_DIALOG, "EelAlertDialog", &dialog_info, 0); } return dialog_type; } static void eel_alert_dialog_class_init (EelAlertDialogClass *class) { GtkWidgetClass *widget_class; GObjectClass *gobject_class; widget_class = GTK_WIDGET_CLASS (class); gobject_class = G_OBJECT_CLASS (class); parent_class = g_type_class_peek_parent (class); G_OBJECT_CLASS (class)->finalize = eel_alert_dialog_finalize; widget_class->style_set = eel_alert_dialog_style_set; gobject_class->set_property = eel_alert_dialog_set_property; gobject_class->get_property = eel_alert_dialog_get_property; gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("alert_border", _("Image/label border"), _("Width of border around the label and image in the alert dialog"), 0, G_MAXINT, 5, G_PARAM_READABLE)); g_object_class_install_property (gobject_class, PROP_ALERT_TYPE, g_param_spec_enum ("alert_type", _("Alert Type"), _("The type of alert"), GTK_TYPE_MESSAGE_TYPE, GTK_MESSAGE_INFO, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_BUTTONS, g_param_spec_enum ("buttons", _("Alert Buttons"), _("The buttons shown in the alert dialog"), GTK_TYPE_BUTTONS_TYPE, GTK_BUTTONS_NONE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); } static void eel_alert_dialog_finalize (GObject *object) { EelAlertDialog *dialog; dialog = EEL_ALERT_DIALOG (object); g_free (dialog->details); EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); } static void eel_alert_dialog_init (EelAlertDialog *dialog) { GtkWidget *hbox; GtkWidget *vbox; GtkWidget *expander; dialog->details = g_new0 (EelAlertDialogDetails, 1); dialog->details->primary_label = gtk_label_new (NULL); dialog->details->secondary_label = gtk_label_new (NULL); dialog->details->details_label = gtk_label_new (NULL); dialog->details->image = gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG); gtk_misc_set_alignment (GTK_MISC (dialog->details->image), 0.5, 0.0); gtk_label_set_line_wrap (GTK_LABEL (dialog->details->primary_label), TRUE); gtk_label_set_selectable (GTK_LABEL (dialog->details->primary_label), TRUE); gtk_label_set_use_markup (GTK_LABEL (dialog->details->primary_label), TRUE); gtk_misc_set_alignment (GTK_MISC (dialog->details->primary_label), 0.0, 0.5); gtk_label_set_line_wrap (GTK_LABEL (dialog->details->secondary_label), TRUE); gtk_label_set_selectable (GTK_LABEL (dialog->details->secondary_label), TRUE); gtk_misc_set_alignment (GTK_MISC (dialog->details->secondary_label), 0.0, 0.5); gtk_label_set_line_wrap (GTK_LABEL (dialog->details->details_label), TRUE); gtk_label_set_selectable (GTK_LABEL (dialog->details->details_label), TRUE); gtk_misc_set_alignment (GTK_MISC (dialog->details->details_label), 0.0, 0.5); hbox = gtk_hbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_box_pack_start (GTK_BOX (hbox), dialog->details->image, FALSE, FALSE, 0); vbox = gtk_vbox_new (FALSE, 12); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), dialog->details->primary_label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), dialog->details->secondary_label, FALSE, FALSE, 0); expander = gtk_expander_new_with_mnemonic (_("Show more _details")); dialog->details->details_expander = expander; gtk_expander_set_spacing (GTK_EXPANDER (expander), 6); gtk_container_add (GTK_CONTAINER (expander), dialog->details->details_label); gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, FALSE, FALSE, 0); gtk_widget_show_all (hbox); gtk_widget_hide (expander); } static void setup_type (EelAlertDialog *dialog, GtkMessageType type) { const gchar *stock_id = NULL; GtkStockItem item; switch (type) { case GTK_MESSAGE_INFO: stock_id = GTK_STOCK_DIALOG_INFO; break; case GTK_MESSAGE_QUESTION: stock_id = GTK_STOCK_DIALOG_QUESTION; break; case GTK_MESSAGE_WARNING: stock_id = GTK_STOCK_DIALOG_WARNING; break; case GTK_MESSAGE_ERROR: stock_id = GTK_STOCK_DIALOG_ERROR; break; default: g_warning ("Unknown GtkMessageType %d", type); break; } if (stock_id == NULL) { stock_id = GTK_STOCK_DIALOG_INFO; } if (gtk_stock_lookup (stock_id, &item)) { gtk_image_set_from_stock (GTK_IMAGE (dialog->details->image), stock_id, GTK_ICON_SIZE_DIALOG); } else { g_warning ("Stock dialog ID doesn't exist?"); } } static void eel_alert_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EelAlertDialog *dialog; dialog = EEL_ALERT_DIALOG (object); switch (prop_id) { case PROP_ALERT_TYPE: dialog->details->type = g_value_get_enum (value); setup_type (dialog, dialog->details->type); break; case PROP_BUTTONS: eel_alert_dialog_add_buttons (dialog, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void eel_alert_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EelAlertDialog *dialog; dialog = EEL_ALERT_DIALOG (object); switch (prop_id) { case PROP_ALERT_TYPE: g_value_set_enum (value, dialog->details->type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } void eel_alert_dialog_set_primary_label (EelAlertDialog *dialog, const gchar *message) { gchar *markup_str; char *escaped_message; if (message != NULL) { escaped_message = g_markup_escape_text (message, -1); markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", escaped_message, "</span>", NULL); gtk_label_set_markup (GTK_LABEL (EEL_ALERT_DIALOG (dialog)->details->primary_label), markup_str); g_free (markup_str); g_free (escaped_message); } } void eel_alert_dialog_set_secondary_label (EelAlertDialog *dialog, const gchar *message) { if (message != NULL) { gtk_label_set_text (GTK_LABEL (EEL_ALERT_DIALOG (dialog)->details->secondary_label), message); } else { gtk_widget_hide (EEL_ALERT_DIALOG (dialog)->details->secondary_label); } } void eel_alert_dialog_set_details_label (EelAlertDialog *dialog, const gchar *message) { if (message != NULL) { gtk_widget_show (dialog->details->details_expander); gtk_label_set_text (GTK_LABEL (dialog->details->details_label), message); } else { gtk_widget_hide (dialog->details->details_expander); } } GtkWidget* eel_alert_dialog_new (GtkWindow *parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const gchar *primary_message, const gchar *secondary_message) { GtkWidget *widget; GtkDialog *dialog; g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); widget = g_object_new (EEL_TYPE_ALERT_DIALOG, "alert_type", type, "buttons", buttons, NULL); atk_object_set_role (gtk_widget_get_accessible (widget), ATK_ROLE_ALERT); dialog = GTK_DIALOG (widget); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_dialog_set_has_separator (dialog, FALSE); /* Make sure we don't get a window title. * HIG says that alert dialogs should not have window title */ gtk_window_set_title (GTK_WINDOW (dialog), ""); gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); eel_alert_dialog_set_primary_label (EEL_ALERT_DIALOG (dialog), primary_message); eel_alert_dialog_set_secondary_label (EEL_ALERT_DIALOG (dialog), secondary_message); if (parent != NULL) { gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (parent)); } if (flags & GTK_DIALOG_MODAL) { gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); } if (flags & GTK_DIALOG_DESTROY_WITH_PARENT) { gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); } return widget; } static void eel_alert_dialog_add_buttons (EelAlertDialog* alert_dialog, GtkButtonsType buttons) { GtkDialog* dialog; dialog = GTK_DIALOG (alert_dialog); switch (buttons) { case GTK_BUTTONS_NONE: break; case GTK_BUTTONS_OK: gtk_dialog_add_button (dialog, GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK); break; case GTK_BUTTONS_CLOSE: gtk_dialog_add_button (dialog, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_CLOSE); break; case GTK_BUTTONS_CANCEL: gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_CANCEL); break; case GTK_BUTTONS_YES_NO: gtk_dialog_add_button (dialog, GTK_STOCK_NO, GTK_RESPONSE_NO); gtk_dialog_add_button (dialog, GTK_STOCK_YES, GTK_RESPONSE_YES); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_YES); break; case GTK_BUTTONS_OK_CANCEL: gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button (dialog, GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK); break; default: g_warning ("Unknown GtkButtonsType"); break; } g_object_notify (G_OBJECT (alert_dialog), "buttons"); } static void eel_alert_dialog_style_set (GtkWidget *widget, GtkStyle *prev_style) { GtkWidget *parent; gint border_width; border_width = 0; parent = GTK_WIDGET (gtk_widget_get_parent (EEL_ALERT_DIALOG (widget)->details->image)); if (parent != NULL) { gtk_widget_style_get (widget, "alert_border", &border_width, NULL); gtk_container_set_border_width (GTK_CONTAINER (parent), border_width); } if (GTK_WIDGET_CLASS (parent_class)->style_set) { (GTK_WIDGET_CLASS (parent_class)->style_set) (widget, prev_style); } }