From e598cda225c4f98025ec43b72eb1a9dd691b77cd Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 10 Feb 2008 07:08:45 +0000 Subject: [PATCH] Consolidate multiple messages into single message dialog. Patch #6405. Thanks to John Darrington for review. * automake.mk (dist_src_ui_gui_psppire_DATA): Add message-dialog.glade. * helper.c (give_help): Use GtkMessageDialog directly instead of trying to reuse message-dialog code. * message-dialog.c: Rewritten. * message-dialog.glade: New file. --- src/ui/gui/automake.mk | 1 + src/ui/gui/helper.c | 21 ++- src/ui/gui/message-dialog.c | 265 +++++++++++++++++++++----------- src/ui/gui/message-dialog.glade | 108 +++++++++++++ 4 files changed, 294 insertions(+), 101 deletions(-) create mode 100644 src/ui/gui/message-dialog.glade diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index 3a1dd3a6..12be6283 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -53,6 +53,7 @@ dist_src_ui_gui_psppire_DATA = \ $(top_srcdir)/src/ui/gui/descriptives-dialog.glade \ $(top_srcdir)/src/ui/gui/crosstabs.glade \ $(top_srcdir)/src/ui/gui/frequencies.glade \ + $(top_srcdir)/src/ui/gui/message-dialog.glade \ $(top_srcdir)/src/ui/gui/oneway.glade \ $(top_srcdir)/src/ui/gui/output-viewer.glade \ $(top_srcdir)/src/ui/gui/psppire.glade \ diff --git a/src/ui/gui/helper.c b/src/ui/gui/helper.c index da74882a..bc197e63 100644 --- a/src/ui/gui/helper.c +++ b/src/ui/gui/helper.c @@ -129,17 +129,16 @@ pspp_locale_to_utf8 (const gchar *text, gssize len, GError **err) static void give_help (void) { - static struct msg m = { - MSG_GENERAL, - MSG_NOTE, - {0, -1}, - 0, - }; - - if (! m.text) - m.text=g_strdup (_("Sorry. The help system hasn't yet been implemented.")); - - popup_message (&m); + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, + GTK_DIALOG_MODAL, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + _("Sorry. The help system hasn't yet " + "been implemented.")); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); } void diff --git a/src/ui/gui/message-dialog.c b/src/ui/gui/message-dialog.c index 708d397e..525fca40 100644 --- a/src/ui/gui/message-dialog.c +++ b/src/ui/gui/message-dialog.c @@ -36,154 +36,239 @@ #include "helper.h" static void enqueue_msg (const struct msg *m); +static gboolean popup_messages (gpointer); +#define MAX_EARLY_MESSAGES 100 +static GQueue *early_queue; -static GQueue *message_queue; +static unsigned long dropped_messages; +#define MAX_LATE_MESSAGES 10 +static GQueue *late_queue; + +static int error_cnt, warning_cnt, note_cnt; + +static GladeXML *message_xml; +static GtkDialog *message_dialog; void message_dialog_init (struct source_stream *ss) { - message_queue = g_queue_new (); + early_queue = g_queue_new (); + dropped_messages = 0; + late_queue = g_queue_new (); + error_cnt = warning_cnt = note_cnt = 0; msg_init (ss, enqueue_msg); + message_xml = XML_NEW ("message-dialog.glade"); + message_dialog = GTK_DIALOG (get_widget_assert (message_xml, + "message-dialog")); } void message_dialog_done (void) { msg_done (); - g_queue_free (message_queue); -} - -static gboolean -dequeue_message (gpointer data) -{ - struct msg * m ; - - /* If a pointer grab is in effect, then the combination of that, and - a modal dialog box, will cause an impossible situation. - So don't pop it up just yet. - */ - if ( gdk_pointer_is_grabbed ()) - return TRUE; - - m = g_queue_pop_tail (message_queue); - - if ( m ) - { - popup_message (m); - msg_destroy (m); - return TRUE; - } - - return FALSE; + g_queue_free (early_queue); + dropped_messages = 0; + g_queue_free (late_queue); + gtk_widget_destroy (GTK_WIDGET (message_dialog)); + g_object_unref (message_xml); } static void -enqueue_msg (const struct msg *msg) +format_message (struct msg *m, struct string *msg) { - struct msg *m = msg_dup (msg); - - g_queue_push_head (message_queue, m); - - g_idle_add (dequeue_message, 0); -} - + const char *label; -void -popup_message (const struct msg *m) -{ - GtkWidget *dialog; - gchar *location = NULL; - - gint message_type; - const char *msg; + if (m->where.file_name) + ds_put_format (msg, "%s:", m->where.file_name); + if (m->where.line_number != -1) + ds_put_format (msg, "%d:", m->where.line_number); + if (m->where.file_name || m->where.line_number != -1) + ds_put_char (msg, ' '); switch (m->severity) { case MSG_ERROR: - message_type = GTK_MESSAGE_ERROR; switch (m->category) { case MSG_SYNTAX: - msg = _("Syntax Error"); + label = _("syntax error"); break; case MSG_DATA: - msg = _("Data File Error"); + label = _("data file error"); break; case MSG_GENERAL: default: - msg = _("PSPP Error"); + label = _("PSPP error"); break; - }; + } break; case MSG_WARNING: - message_type = GTK_MESSAGE_WARNING; switch (m->category) { case MSG_SYNTAX: - msg = _("Syntax Warning"); - break; + label = _("syntax warning"); + break; case MSG_DATA: - msg = _("Data File Warning"); + label = _("data file warning"); break; case MSG_GENERAL: - default: - msg = _("PSPP Warning"); - break; - }; + default: + label = _("PSPP warning"); + break; + } break; case MSG_NOTE: default: - message_type = GTK_MESSAGE_INFO; - switch (m->category) - { - case MSG_SYNTAX: - msg = _("Syntax Information"); + switch (m->category) + { + case MSG_SYNTAX: + label = _("syntax information"); + break; + + case MSG_DATA: + label = _("data file information"); + break; + + case MSG_GENERAL: + default: + label = _("PSPP information"); + break; + } break; + } + ds_put_format (msg, "%s: %s\n", label, m->text); + msg_destroy (m); +} - case MSG_DATA: - msg = _("Data File Information"); - break; +static void +enqueue_msg (const struct msg *msg) +{ + struct msg *m = msg_dup (msg); - case MSG_GENERAL: - default: - msg = _("PSPP Information"); - break; - }; + switch (m->severity) + { + case MSG_ERROR: + error_cnt++; break; - }; - - dialog = gtk_message_dialog_new ( NULL, - GTK_DIALOG_MODAL, - message_type, - GTK_BUTTONS_CLOSE, - msg); - if ( m->where.line_number != -1) + case MSG_WARNING: + warning_cnt++; + break; + case MSG_NOTE: + note_cnt++; + break; + } + + if (g_queue_get_length (early_queue) < MAX_EARLY_MESSAGES) { - location = g_strdup_printf (_("%s (line %d)"), - m->where.file_name ? m->where.file_name : "", - m->where.line_number); + if (g_queue_is_empty (early_queue)) + g_idle_add (popup_messages, NULL); + g_queue_push_tail (early_queue, m); } else { - location = g_strdup_printf (_("%s"), - m->where.file_name ? m->where.file_name : ""); } + if (g_queue_get_length (late_queue) >= MAX_LATE_MESSAGES) + { + struct msg *m = g_queue_pop_head (late_queue); + msg_destroy (m); + dropped_messages++; + } + g_queue_push_tail (late_queue, m); + } +} - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - _("%s %s"), - location, - m->text); - g_free (location); +gboolean +popup_messages (gpointer unused UNUSED) +{ + GtkTextBuffer *text_buffer; + GtkTextIter end; + GtkTextView *text_view; + GtkLabel *label; + struct string lead, msg; + int message_cnt; - gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE); + /* If a pointer grab is in effect, then the combination of that, and + a modal dialog box, will cause an impossible situation. + So don't pop it up just yet. + */ + if ( gdk_pointer_is_grabbed ()) + return TRUE; + + /* Compose the lead-in. */ + message_cnt = error_cnt + warning_cnt + note_cnt; + ds_init_empty (&lead); + if (dropped_messages == 0) + ds_put_format ( + &lead, + ngettext ("The PSPP processing engine reported the following message:", + "The PSPP processing engine reported the following messages:", + message_cnt)); + else + { + ds_put_format ( + &lead, + ngettext ("The PSPP processing engine reported %d message.", + "The PSPP processing engine reported %d messages.", + message_cnt), + message_cnt); + ds_put_cstr (&lead, " "); + ds_put_format ( + &lead, + ngettext ("%d of these messages are displayed below.", + "%d of these messages are displayed below.", + MAX_EARLY_MESSAGES + MAX_LATE_MESSAGES), + MAX_EARLY_MESSAGES + MAX_LATE_MESSAGES); + } + + + /* Compose the messages. */ + ds_init_empty (&msg); + while (!g_queue_is_empty (early_queue)) + format_message (g_queue_pop_head (early_queue), &msg); + if (dropped_messages) + { + ds_put_format (&msg, "...\nOmitting %lu messages\n...\n", + dropped_messages); + dropped_messages = 0; + } + while (!g_queue_is_empty (late_queue)) + format_message (g_queue_pop_head (late_queue), &msg); + + /* Set up the dialog. */ + if (message_xml == NULL || message_dialog == NULL) + goto use_fallback; + + text_buffer = gtk_text_buffer_new (NULL); + gtk_text_buffer_get_end_iter (text_buffer, &end); + gtk_text_buffer_insert (text_buffer, &end, ds_data (&msg), ds_length (&msg)); + ds_destroy (&msg); + + label = GTK_LABEL (get_widget_assert (message_xml, "lead-in")); + if (label == NULL) + goto use_fallback; + gtk_label_set_text (label, ds_cstr (&lead)); - gtk_dialog_run (GTK_DIALOG (dialog)); + text_view = GTK_TEXT_VIEW (get_widget_assert (message_xml, "message")); + if (text_view == NULL) + goto use_fallback; + gtk_text_view_set_buffer (text_view, text_buffer); - gtk_widget_destroy (dialog); + gtk_dialog_run (message_dialog); + gtk_widget_hide (GTK_WIDGET (message_dialog)); + + return FALSE; + +use_fallback: + g_warning ("Could not create message dialog. " + "Is PSPPIRE properly installed?"); + fputs (ds_cstr (&msg), stderr); + ds_destroy (&lead); + ds_destroy (&msg); + return FALSE; } diff --git a/src/ui/gui/message-dialog.glade b/src/ui/gui/message-dialog.glade new file mode 100644 index 00000000..719c1aad --- /dev/null +++ b/src/ui/gui/message-dialog.glade @@ -0,0 +1,108 @@ + + + + + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Messages Reported + True + GTK_WIN_POS_CENTER_ON_PARENT + GDK_WINDOW_TYPE_HINT_DIALOG + False + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-dialog-info + 6 + + + False + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + The PSPP processor reported # errors. The first # and last # are shown below: + True + + + False + False + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + GTK_WRAP_WORD + False + + + + + 1 + + + + + 1 + + + + + 1 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_BUTTONBOX_END + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-close + True + 0 + + + + + False + GTK_PACK_END + + + + + + -- 2.30.2