aboutsummaryrefslogtreecommitdiffstats
path: root/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'widgets')
-rw-r--r--widgets/misc/e-alert-bar.c218
-rw-r--r--widgets/misc/e-alert-bar.h1
-rw-r--r--widgets/misc/e-preview-pane.c70
-rw-r--r--widgets/misc/e-preview-pane.h1
4 files changed, 216 insertions, 74 deletions
diff --git a/widgets/misc/e-alert-bar.c b/widgets/misc/e-alert-bar.c
index 7ec731e90d..75bf55ff25 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 fc23dec8bf..f1e84b5016 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);
diff --git a/widgets/misc/e-preview-pane.c b/widgets/misc/e-preview-pane.c
index 1a7a319ea4..42f338c75b 100644
--- a/widgets/misc/e-preview-pane.c
+++ b/widgets/misc/e-preview-pane.c
@@ -27,7 +27,13 @@
#include <gdk/gdkkeysyms.h>
+#include <e-util/e-alert-sink.h>
+#include <e-util/e-alert-dialog.h>
+
+#include "e-alert-bar.h"
+
struct _EPreviewPanePrivate {
+ GtkWidget *alert_bar;
GtkWidget *web_view;
GtkWidget *search_bar;
};
@@ -45,10 +51,17 @@ enum {
static guint signals[LAST_SIGNAL];
-G_DEFINE_TYPE (
+/* Forward Declarations */
+static void e_preview_pane_alert_sink_init
+ (EAlertSinkInterface *interface);
+
+G_DEFINE_TYPE_WITH_CODE (
EPreviewPane,
e_preview_pane,
- GTK_TYPE_VBOX)
+ GTK_TYPE_VBOX,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_ALERT_SINK,
+ e_preview_pane_alert_sink_init))
static void
preview_pane_set_web_view (EPreviewPane *preview_pane,
@@ -107,6 +120,11 @@ preview_pane_dispose (GObject *object)
priv = E_PREVIEW_PANE (object)->priv;
+ if (priv->alert_bar != NULL) {
+ g_object_unref (priv->alert_bar);
+ priv->alert_bar = NULL;
+ }
+
if (priv->search_bar != NULL) {
g_object_unref (priv->search_bar);
priv->search_bar = NULL;
@@ -129,6 +147,11 @@ preview_pane_constructed (GObject *object)
priv = E_PREVIEW_PANE (object)->priv;
+ widget = e_alert_bar_new ();
+ gtk_box_pack_start (GTK_BOX (object), widget, FALSE, FALSE, 0);
+ priv->alert_bar = g_object_ref (widget);
+ /* EAlertBar controls its own visibility. */
+
widget = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (
GTK_SCROLLED_WINDOW (widget),
@@ -160,6 +183,35 @@ preview_pane_show_search_bar (EPreviewPane *preview_pane)
}
static void
+preview_pane_submit_alert (EAlertSink *alert_sink,
+ EAlert *alert)
+{
+ EPreviewPane *preview_pane;
+ EAlertBar *alert_bar;
+ GtkWidget *dialog;
+ GtkWindow *parent;
+
+ preview_pane = E_PREVIEW_PANE (alert_sink);
+ alert_bar = E_ALERT_BAR (preview_pane->priv->alert_bar);
+
+ switch (e_alert_get_message_type (alert)) {
+ case GTK_MESSAGE_INFO:
+ case GTK_MESSAGE_WARNING:
+ case GTK_MESSAGE_QUESTION:
+ case GTK_MESSAGE_ERROR:
+ e_alert_bar_add_alert (alert_bar, alert);
+ break;
+
+ default:
+ parent = GTK_WINDOW (alert_sink);
+ dialog = e_alert_dialog_new (parent, alert);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ break;
+ }
+}
+
+static void
e_preview_pane_class_init (EPreviewPaneClass *class)
{
GObjectClass *object_class;
@@ -213,6 +265,12 @@ e_preview_pane_class_init (EPreviewPaneClass *class)
}
static void
+e_preview_pane_alert_sink_init (EAlertSinkInterface *interface)
+{
+ interface->submit_alert = preview_pane_submit_alert;
+}
+
+static void
e_preview_pane_init (EPreviewPane *preview_pane)
{
preview_pane->priv = G_TYPE_INSTANCE_GET_PRIVATE (
@@ -248,6 +306,14 @@ e_preview_pane_get_search_bar (EPreviewPane *preview_pane)
}
void
+e_preview_pane_clear_alerts (EPreviewPane *preview_pane)
+{
+ g_return_if_fail (E_IS_PREVIEW_PANE (preview_pane));
+
+ e_alert_bar_clear (E_ALERT_BAR (preview_pane->priv->alert_bar));
+}
+
+void
e_preview_pane_show_search_bar (EPreviewPane *preview_pane)
{
g_return_if_fail (E_IS_PREVIEW_PANE (preview_pane));
diff --git a/widgets/misc/e-preview-pane.h b/widgets/misc/e-preview-pane.h
index bd965ed307..1313193d97 100644
--- a/widgets/misc/e-preview-pane.h
+++ b/widgets/misc/e-preview-pane.h
@@ -67,6 +67,7 @@ GType e_preview_pane_get_type (void);
GtkWidget * e_preview_pane_new (EWebView *web_view);
EWebView * e_preview_pane_get_web_view (EPreviewPane *preview_pane);
ESearchBar * e_preview_pane_get_search_bar (EPreviewPane *preview_pane);
+void e_preview_pane_clear_alerts (EPreviewPane *preview_pane);
void e_preview_pane_show_search_bar (EPreviewPane *preview_pane);
G_END_DECLS