[evolution] EAlertBar: Add a close button to all alerts.



commit 451179909849e4e4058180f095e6ae889d97b797
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon Nov 21 18:51:00 2011 -0500

    EAlertBar: Add a close button to all alerts.
    
    Replaces the 'Dismiss' button.  All alerts appearing in an alert bar
    should be dismissable (i.e. non-modal).  For modal alerts use a dialog.

 e-util/e-alert.c                                   |   12 -
 .../evolution-offline-alert.error.xml              |    2 -
 widgets/misc/e-alert-bar.c                         |  218 +++++++++++++-------
 widgets/misc/e-alert-bar.h                         |    1 +
 4 files changed, 147 insertions(+), 86 deletions(-)
---
diff --git a/e-util/e-alert.c b/e-util/e-alert.c
index 88dbb71..d4a7a9e 100644
--- a/e-util/e-alert.c
+++ b/e-util/e-alert.c
@@ -909,18 +909,6 @@ e_alert_peek_actions (EAlert *alert)
 {
 	g_return_val_if_fail (E_IS_ALERT (alert), NULL);
 
-	/* Make sure we have at least one action.  Do this on-demand
-	 * in case the XML definition did not specify any actions but
-	 * other actions were added via e_alert_add_action(). */
-	if (g_queue_is_empty (&alert->priv->actions)) {
-		GtkAction *action;
-
-		action = gtk_action_new (
-			"alert-response-0", _("_Dismiss"), NULL, NULL);
-		e_alert_add_action (alert, action, GTK_RESPONSE_CLOSE);
-		g_object_unref (action);
-	}
-
 	return g_queue_peek_head_link (&alert->priv->actions);
 }
 
diff --git a/modules/offline-alert/evolution-offline-alert.error.xml b/modules/offline-alert/evolution-offline-alert.error.xml
index a6362da..782ee8d 100644
--- a/modules/offline-alert/evolution-offline-alert.error.xml
+++ b/modules/offline-alert/evolution-offline-alert.error.xml
@@ -3,11 +3,9 @@
   <error id="offline" type="info">
     <_primary>Evolution is currently offline.</_primary>
     <_secondary>Click 'Work Online' to return to online mode.</_secondary>
-    <button _label="_Dismiss" response="GTK_RESPONSE_OK"/>
   </error>
   <error id="no-network" type="info">
     <_primary>Evolution is currently offline due to a network outage.</_primary>
     <_secondary>Evolution will return to online mode once a network connection is established.</_secondary>
-    <button _label="_Dismiss" response="GTK_RESPONSE_OK"/>
   </error>
 </error-list>
diff --git a/widgets/misc/e-alert-bar.c b/widgets/misc/e-alert-bar.c
index 7ec731e..75bf55f 100644
--- a/widgets/misc/e-alert-bar.c
+++ b/widgets/misc/e-alert-bar.c
@@ -16,14 +16,15 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
 #include "e-alert-bar.h"
 
+#include <config.h>
 #include <glib/gi18n-lib.h>
 
+#define E_ALERT_BAR_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_ALERT_BAR, EAlertBarPrivate))
+
 /* GTK_ICON_SIZE_DIALOG is a tad too big. */
 #define ICON_SIZE GTK_ICON_SIZE_DND
 
@@ -43,19 +44,30 @@ G_DEFINE_TYPE (
 	GTK_TYPE_INFO_BAR)
 
 static void
+alert_bar_response_close (EAlert *alert)
+{
+	e_alert_response (alert, GTK_RESPONSE_CLOSE);
+}
+
+static void
 alert_bar_show_alert (EAlertBar *alert_bar)
 {
 	GtkImage *image;
-	GtkLabel *label;
 	GtkInfoBar *info_bar;
 	GtkWidget *action_area;
+	GtkWidget *widget;
 	EAlert *alert;
 	GList *actions;
 	GList *children;
 	GtkMessageType message_type;
+	const gchar *primary_text;
+	const gchar *secondary_text;
 	const gchar *stock_id;
-	const gchar *text;
+	gboolean have_primary_text;
+	gboolean have_secondary_text;
+	gboolean visible;
 	gint response_id;
+	gchar *markup;
 
 	info_bar = GTK_INFO_BAR (alert_bar);
 	action_area = gtk_info_bar_get_action_area (info_bar);
@@ -71,48 +83,94 @@ alert_bar_show_alert (EAlertBar *alert_bar)
 		children = g_list_delete_link (children, children);
 	}
 
-	/* Add new buttons. */
+	/* Add alert-specific buttons. */
 	actions = e_alert_peek_actions (alert);
 	while (actions != NULL) {
-		GtkWidget *button;
-
 		/* These actions are already wired to trigger an
 		 * EAlert::response signal when activated, which
 		 * will in turn call gtk_info_bar_response(), so
 		 * we can add buttons directly to the action
 		 * area without knowning their response IDs. */
 
-		button = gtk_button_new ();
+		widget = gtk_button_new ();
 
 		gtk_activatable_set_related_action (
-			GTK_ACTIVATABLE (button),
+			GTK_ACTIVATABLE (widget),
 			GTK_ACTION (actions->data));
 
 		gtk_box_pack_end (
-			GTK_BOX (action_area),
-			button, FALSE, FALSE, 0);
+			GTK_BOX (action_area), widget, FALSE, FALSE, 0);
 
 		actions = g_list_next (actions);
 	}
 
+	/* Add a dismiss button. */
+	widget = gtk_button_new ();
+	gtk_button_set_image (
+		GTK_BUTTON (widget),
+		gtk_image_new_from_stock (
+		GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));
+	gtk_button_set_relief (
+		GTK_BUTTON (widget), GTK_RELIEF_NONE);
+	gtk_widget_set_tooltip_text (
+		widget, _("Close this message"));
+	gtk_box_pack_end (
+		GTK_BOX (action_area), widget, FALSE, FALSE, 0);
+	gtk_button_box_set_child_non_homogeneous (
+		GTK_BUTTON_BOX (action_area), widget, TRUE);
+	gtk_widget_show (widget);
+
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (alert_bar_response_close), alert);
+
+	primary_text = e_alert_get_primary_text (alert);
+	secondary_text = e_alert_get_secondary_text (alert);
+
+	if (primary_text == NULL)
+		primary_text = "";
+
+	if (secondary_text == NULL)
+		secondary_text = "";
+
+	have_primary_text = (*primary_text != '\0');
+	have_secondary_text = (*secondary_text != '\0');
+
 	response_id = e_alert_get_default_response (alert);
 	gtk_info_bar_set_default_response (info_bar, response_id);
 
 	message_type = e_alert_get_message_type (alert);
 	gtk_info_bar_set_message_type (info_bar, message_type);
 
-	text = e_alert_get_primary_text (alert);
-	label = GTK_LABEL (alert_bar->priv->primary_label);
-	gtk_label_set_text (label, text);
-
-	text = e_alert_get_secondary_text (alert);
-	label = GTK_LABEL (alert_bar->priv->secondary_label);
-	gtk_label_set_text (label, text);
+	widget = alert_bar->priv->primary_label;
+	if (have_primary_text && have_secondary_text)
+		markup = g_markup_printf_escaped (
+			"<b>%s</b>", primary_text);
+	else
+		markup = g_markup_escape_text (primary_text, -1);
+	gtk_label_set_markup (GTK_LABEL (widget), markup);
+	gtk_widget_set_visible (widget, have_primary_text);
+	g_free (markup);
+
+	widget = alert_bar->priv->secondary_label;
+	if (have_primary_text && have_secondary_text)
+		markup = g_markup_printf_escaped (
+			"<small>%s</small>", secondary_text);
+	else
+		markup = g_markup_escape_text (secondary_text, -1);
+	gtk_label_set_markup (GTK_LABEL (widget), markup);
+	gtk_widget_set_visible (widget, have_secondary_text);
+	g_free (markup);
 
 	stock_id = e_alert_get_stock_id (alert);
 	image = GTK_IMAGE (alert_bar->priv->image);
 	gtk_image_set_from_stock (image, stock_id, ICON_SIZE);
 
+	/* Avoid showing an image for one-line alerts,
+	 * which are usually questions or informational. */
+	visible = have_primary_text && have_secondary_text;
+	gtk_widget_set_visible (alert_bar->priv->image, visible);
+
 	gtk_widget_show (GTK_WIDGET (alert_bar));
 
 	/* Warnings are generally meant for transient errors.
@@ -130,7 +188,6 @@ alert_bar_response_cb (EAlert *alert,
 {
 	GQueue *queue;
 	EAlert *head;
-	GList *link;
 	gboolean was_head;
 
 	queue = &alert_bar->priv->alerts;
@@ -140,12 +197,8 @@ alert_bar_response_cb (EAlert *alert,
 	g_signal_handlers_disconnect_by_func (
 		alert, alert_bar_response_cb, alert_bar);
 
-	/* XXX Would be easier if g_queue_remove() returned a boolean. */
-	link = g_queue_find (queue, alert);
-	if (link != NULL) {
-		g_queue_delete_link (queue, link);
+	if (g_queue_remove (queue, alert))
 		g_object_unref (alert);
-	}
 
 	if (g_queue_is_empty (queue))
 		gtk_widget_hide (GTK_WIDGET (alert_bar));
@@ -161,7 +214,7 @@ alert_bar_dispose (GObject *object)
 {
 	EAlertBarPrivate *priv;
 
-	priv = E_ALERT_BAR (object)->priv;
+	priv = E_ALERT_BAR_GET_PRIVATE (object);
 
 	while (!g_queue_is_empty (&priv->alerts)) {
 		EAlert *alert = g_queue_pop_head (&priv->alerts);
@@ -174,48 +227,37 @@ alert_bar_dispose (GObject *object)
 	G_OBJECT_CLASS (e_alert_bar_parent_class)->dispose (object);
 }
 
-static GtkSizeRequestMode
-alert_bar_get_request_mode (GtkWidget *widget)
-{
-	/* GtkHBox does width-for-height by default.  But we
-	 * want the alert bar to be as short as possible. */
-	return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
-}
-
 static void
-e_alert_bar_class_init (EAlertBarClass *class)
+alert_bar_constructed (GObject *object)
 {
-	GObjectClass *object_class;
-	GtkWidgetClass *widget_class;
+	EAlertBarPrivate *priv;
+	GtkInfoBar *info_bar;
+	GtkWidget *action_area;
+	GtkWidget *content_area;
+	GtkWidget *container;
+	GtkWidget *widget;
 
-	g_type_class_add_private (class, sizeof (EAlertBarPrivate));
+	priv = E_ALERT_BAR_GET_PRIVATE (object);
 
-	object_class = G_OBJECT_CLASS (class);
-	object_class->dispose = alert_bar_dispose;
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (e_alert_bar_parent_class)->constructed (object);
 
-	widget_class = GTK_WIDGET_CLASS (class);
-	widget_class->get_request_mode = alert_bar_get_request_mode;
-}
+	g_queue_init (&priv->alerts);
 
-static void
-e_alert_bar_init (EAlertBar *alert_bar)
-{
-	GtkWidget *container;
-	GtkWidget *widget;
-	PangoAttribute *attr;
-	PangoAttrList *attr_list;
-
-	alert_bar->priv = G_TYPE_INSTANCE_GET_PRIVATE (
-		alert_bar, E_TYPE_ALERT_BAR, EAlertBarPrivate);
+	info_bar = GTK_INFO_BAR (object);
+	action_area = gtk_info_bar_get_action_area (info_bar);
+	content_area = gtk_info_bar_get_content_area (info_bar);
 
-	g_queue_init (&alert_bar->priv->alerts);
+	gtk_orientable_set_orientation (
+		GTK_ORIENTABLE (action_area), GTK_ORIENTATION_HORIZONTAL);
+	gtk_widget_set_valign (action_area, GTK_ALIGN_START);
 
-	container = gtk_info_bar_get_content_area (GTK_INFO_BAR (alert_bar));
+	container = content_area;
 
 	widget = gtk_image_new ();
 	gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.0);
 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
-	alert_bar->priv->image = widget;
+	priv->image = widget;
 	gtk_widget_show (widget);
 
 	widget = gtk_vbox_new (FALSE, 12);
@@ -224,35 +266,53 @@ e_alert_bar_init (EAlertBar *alert_bar)
 
 	container = widget;
 
-	attr_list = pango_attr_list_new ();
-	attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
-	pango_attr_list_insert (attr_list, attr);
-
 	widget = gtk_label_new (NULL);
-	gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
 	gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
 	gtk_label_set_selectable (GTK_LABEL (widget), TRUE);
 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
-	alert_bar->priv->primary_label = widget;
+	priv->primary_label = widget;
 	gtk_widget_show (widget);
 
-	pango_attr_list_unref (attr_list);
-
-	attr_list = pango_attr_list_new ();
-	attr = pango_attr_scale_new  (PANGO_SCALE_SMALL);
-	pango_attr_list_insert (attr_list, attr);
-
 	widget = gtk_label_new (NULL);
-	gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
 	gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
 	gtk_label_set_selectable (GTK_LABEL (widget), TRUE);
 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
-	alert_bar->priv->secondary_label = widget;
+	priv->secondary_label = widget;
 	gtk_widget_show (widget);
 
-	pango_attr_list_unref (attr_list);
+	container = action_area;
+}
+
+static GtkSizeRequestMode
+alert_bar_get_request_mode (GtkWidget *widget)
+{
+	/* GtkHBox does width-for-height by default.  But we
+	 * want the alert bar to be as short as possible. */
+	return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+}
+
+static void
+e_alert_bar_class_init (EAlertBarClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+
+	g_type_class_add_private (class, sizeof (EAlertBarPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->dispose = alert_bar_dispose;
+	object_class->constructed = alert_bar_constructed;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->get_request_mode = alert_bar_get_request_mode;
+}
+
+static void
+e_alert_bar_init (EAlertBar *alert_bar)
+{
+	alert_bar->priv = E_ALERT_BAR_GET_PRIVATE (alert_bar);
 }
 
 GtkWidget *
@@ -261,6 +321,20 @@ e_alert_bar_new (void)
 	return g_object_new (E_TYPE_ALERT_BAR, NULL);
 }
 
+void
+e_alert_bar_clear (EAlertBar *alert_bar)
+{
+	GQueue *queue;
+	EAlert *alert;
+
+	g_return_if_fail (E_IS_ALERT_BAR (alert_bar));
+
+	queue = &alert_bar->priv->alerts;
+
+	while ((alert = g_queue_pop_head (queue)) != NULL)
+		alert_bar_response_close (alert);
+}
+
 typedef struct {
 	gboolean found;
 	EAlert *looking_for;
diff --git a/widgets/misc/e-alert-bar.h b/widgets/misc/e-alert-bar.h
index fc23dec..f1e84b5 100644
--- a/widgets/misc/e-alert-bar.h
+++ b/widgets/misc/e-alert-bar.h
@@ -58,6 +58,7 @@ struct _EAlertBarClass {
 
 GType		e_alert_bar_get_type		(void);
 GtkWidget *	e_alert_bar_new			(void);
+void		e_alert_bar_clear		(EAlertBar *alert_bar);
 void		e_alert_bar_add_alert		(EAlertBar *alert_bar,
 						 EAlert *alert);
 



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