1
/***************************************************************************
4
* Copyright 2009 Benjamin Ducke, OA Digital
5
* <benjamin.ducke@oxfordarch.co.uk>>
6
****************************************************************************/
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU Library General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
26
Purpose: Provide error message handling.
37
#include "error_handler.h"
38
#include "dlg_generic.h"
41
static gboolean GUI_ERRORS = FALSE;
42
static gboolean GUI_WARNINGS = FALSE;
44
/* global buffer which all funcs in this file use to pass messages between each other */
45
static char MSGBUF [ MAXSTR ];
66
Read current program options and format them into one big string with
67
multiple lines for output as part of an error message.
68
Memory for the "system info" string will be allocated and must be freed by caller.
70
char *make_sys_info_str ( prg_options *opts )
78
str = malloc ( sizeof ( char ) * 10 * MAXSTR ); /* should be big enough */
79
sprintf ( str, "\n" );
81
if ( opts->sys.configured ) {
82
strcat ( str, "--- System Details ---\n" );
83
snprintf ( buf, MAXSTR, "System: %s ", opts->sys.name );
84
strcat ( str, &buf[0] );
85
snprintf ( buf, MAXSTR, "version %i.%i\n", opts->sys.version, opts->sys.subversion );
86
strcat ( str, &buf[0] );
87
snprintf ( buf, MAXSTR, "Executable: %s\n", opts->sys.argv[0] );
88
strcat ( str, &buf[0] );
89
if ( opts->sys.argc > 1 ) {
90
snprintf ( buf, MAXSTR, "CLI options:\n ");
91
strcat ( str, &buf[0] );
92
for ( i = 1; i < opts->sys.argc; i ++ ) {
93
snprintf ( buf, MAXSTR, "\t%s", opts->sys.argv[i] );
94
cp = opts->sys.argv[i];
98
strcat ( str, &buf[0] );
100
strcat ( str, "\n" );
104
if ( opts->db.configured ) {
105
strcat ( str, "\n--- Database Connection ---\n" );
106
if ( !opts->db.connected ) {
107
strcat ( str, "Not connected.\n" );
109
snprintf ( buf, MAXSTR, "File: %s\n", opts->db.filename );
111
strcat ( str, "\n" );
114
if ( opts->gui.configured ) {
115
strcat ( str, "\n--- Interface Settings ---\n" );
116
if ( opts->gui.compact_mode ) {
117
strcat ( str, "Running in compact mode.\n" );
119
if ( opts->gui.managed ) {
120
strcat ( str, "Using managed dialogs.\n" );
122
snprintf ( buf, MAXSTR, "X resolution: %i\n", opts->gui.xres );
123
strcat ( str, &buf[0] );
124
snprintf ( buf, MAXSTR, "Y resolution: %i\n", opts->gui.yres );
125
strcat ( str, &buf[0] );
132
Displays an error message in a dialog.
134
There are a number of things to set here:
136
title = the window title
137
symbol_style = warning, error etc.
138
primary = heading (bold)
139
secondary = detail text
141
This should never be called directly, but only through first-level error message handlers like "error_fatal()"!
142
If there is no parent widget for the message dialog, set win=NULL and it will create it's own toplevel window.
144
void gui_message ( prg_options *opts, GtkWidget *win,
145
char *title, int symbol_style,
146
const char *primary, const char *secondary )
148
GtkWidget *dialog = NULL;
149
GtkWidget *vbox = NULL;
150
GtkWidget *vbox2 = NULL;
151
GtkWidget *scrWin = NULL;
152
GtkWidget *separator = NULL;
153
GtkWidget *separator2 = NULL;
154
GtkWidget *label = NULL;
155
GtkWidget *textview = NULL;
156
GtkTextBuffer *buffer = NULL;
161
if ( title == NULL ) {
162
title = strdup ("Important Message");
166
/* create a (hidden) toplevel window to attach this message dialog to */
167
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
170
/* do we have a heading (primary string)? */
171
if ( primary != NULL ) {
172
dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL, symbol_style,
173
GTK_BUTTONS_CLOSE, primary );
174
gtk_message_dialog_format_secondary_text ( GTK_MESSAGE_DIALOG (dialog), secondary );
176
dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL, symbol_style,
177
GTK_BUTTONS_CLOSE, secondary );
180
/* the first vbox is the main layout container of the dialog window */
181
vbox = GTK_DIALOG(dialog)->vbox;
182
separator = gtk_hseparator_new ();
183
gtk_container_add ( GTK_CONTAINER ( vbox ), separator );
185
/* put another vbox into the main dialog container */
186
vbox2 = gtk_vbox_new ( FALSE, PAD_SMALL );
187
gtk_container_add ( GTK_CONTAINER ( vbox ), vbox2 );
189
/* add a standard comment label */
190
label = gtk_label_new ( NULL );
191
gtk_label_set_markup ( GTK_LABEL (label),
192
"<small>(below is the full message text with additional system details. Send it to your IT admin if needed)</small>" );
193
gtk_label_set_line_wrap ( GTK_LABEL ( label ), TRUE );
194
gtk_label_set_line_wrap_mode ( GTK_LABEL ( label ), PANGO_WRAP_WORD_CHAR );
195
gtk_container_add ( GTK_CONTAINER ( vbox2 ), label );
197
/* add a scrolling view window for the detailed message text buffer */
198
scrWin = gtk_scrolled_window_new ( NULL, NULL );
199
/* the text view widget should get most of the dialog size allocated to it, but only if the
200
screen is big enough! */
201
if ( opts->gui.compact_mode ) {
202
ysize = (int) opts->gui.yres * 0.20;
203
if ( opts->gui.yres >= 250 ) {
204
ysize = (int) opts->gui.yres * 0.33;
206
if ( opts->gui.yres >= 350 ) {
207
ysize = (int) opts->gui.yres * 0.50;
209
if ( opts->gui.yres >= 450 ) {
210
ysize = (int) opts->gui.yres * 0.60;
215
gtk_widget_set_size_request ( scrWin, -1, ysize );
216
gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW (scrWin),
217
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
218
gtk_container_add ( GTK_CONTAINER ( vbox2 ), scrWin );
219
textview = gtk_text_view_new ();
221
/* now create a text buffer and fill it with text */
222
buffer = gtk_text_view_get_buffer ( GTK_TEXT_VIEW ( textview) );
223
gtk_text_buffer_set_text ( buffer, title, -1 );
225
gtk_text_buffer_insert_at_cursor ( buffer, ": ", -1 );
226
gtk_text_buffer_insert_at_cursor ( buffer, primary, -1 );
227
gtk_text_buffer_insert_at_cursor ( buffer, "\n", -1 );
229
gtk_text_buffer_insert_at_cursor ( buffer, "\n", -1 );
230
gtk_text_buffer_insert_at_cursor ( buffer, secondary, -1 );
231
gtk_text_buffer_insert_at_cursor ( buffer, "\n", -1 );
233
details = make_sys_info_str ( opts );
234
gtk_text_buffer_insert_at_cursor ( buffer, details, -1 );
237
gtk_text_view_set_wrap_mode ( GTK_TEXT_VIEW (textview), GTK_WRAP_WORD );
238
gtk_text_view_set_editable ( GTK_TEXT_VIEW (textview), 0 );
239
gtk_container_add ( GTK_CONTAINER ( scrWin ), textview );
241
/* add another separator line and instantiate the dialog */
242
separator2 = gtk_hseparator_new ();
243
gtk_container_add ( GTK_CONTAINER ( vbox2 ), separator2 );
245
gtk_widget_show_all ( dialog );
247
gtk_window_set_title (GTK_WINDOW (dialog), title );
248
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
250
if ( opts->gui.configured ) {
251
dlg_set_size ( opts, dialog );
253
gtk_dialog_run (GTK_DIALOG (dialog));
254
gtk_widget_destroy (dialog);
259
Handle an error message.
261
The option "fatal" is a boolean that signals whether this error should lead to program abortion or not.
263
This is for a fatal error that leads to program abortion.
265
Optionally, "heading" can contain a simple string that gives some clue about the type of the error (origin).
266
Set to "NULL" if no heading wanted.
267
It will be printed bold in the GUI dialog. The "msg" printf() style text should contain the detailed error message.
270
void error_handle ( prg_options *opts, GtkWidget *win, gboolean fatal,
271
const char *heading, const char *msg )
273
char buffer [ MAXSTR + 1 ];
274
char str [ MAXSTR + 1 ];
275
char hstr [ MAXSTR + 1 ];
280
strncpy ( buffer, msg, MAXSTR );
283
strncpy ( hstr, heading, MAXSTR );
284
/* Unify header messages: make sure first char is upper case and
285
handle punctuation marks; cut off trailing '\n' if present */
287
hstr[0] = toupper ( *cp );
288
cp = &hstr [ strlen(hstr) - 1];
299
sprintf ( str, "Unspecified error.\n" );
301
strncpy ( str, buffer, MAXSTR );
302
/* Unify message text: make sure first char is upper case and
303
handle punctuation marks; cut off trailing '\n' if present */
305
str[0] = toupper ( *cp );
306
cp = &str [ strlen(str) - 1];
311
if ( ( *cp != '.') && ( *cp != '!') && ( *cp != '?') ) {
322
fprintf ( stderr, "FATAL ERROR: %s\n%s\n", hstr, str );
324
fprintf ( stderr, "ERROR: %s\n%s\n", hstr, str );
328
fprintf ( stderr, "FATAL ERROR\n%s\n", str );
330
fprintf ( stderr, "ERROR%s\n\n", str );
333
details = make_sys_info_str ( opts );
334
fprintf ( stderr, details );
336
fprintf ( stderr, "\n" );
340
gui_message ( opts, win, "FATAL ERROR", GTK_MESSAGE_ERROR, hstr, str );
342
gui_message ( opts, win, "FATAL ERROR", GTK_MESSAGE_ERROR, NULL, str );
346
gui_message ( opts, win, "ERROR", GTK_MESSAGE_ERROR, hstr, str );
348
gui_message ( opts, win, "ERROR", GTK_MESSAGE_ERROR, NULL, str );
360
/* ************************************************************************************ */
361
/* P U B L I C I N T E R F A C E */
362
/* ************************************************************************************ */
365
The following functions are the public interface functions for throwing error and warning messages.
367
Optionally, "heading" can contain a simple string that gives some clue about the type of the error (origin).
368
Set to "NULL" if no heading wanted. It will be printed bold in the GUI dialog. The "msg" printf() style text
369
should contain the detailed error message.
374
This is for a fatal error that leads to program abortion.
376
void err_throw_fatal ( prg_options *opts, GtkWidget *win,
377
const char *heading, const char *msg,... )
383
sprintf ( MSGBUF, "Unspecified error." );
385
va_start ( ap, msg );
386
vsprintf ( MSGBUF, msg, ap );
390
error_handle ( opts, win, TRUE, heading, MSGBUF );
395
This is for a non-fatal error that does not lead to program abortion.
397
void err_throw_non_fatal ( prg_options *opts, GtkWidget *win,
398
const char *heading, const char *msg,... )
404
sprintf ( MSGBUF, "Unspecified error." );
406
va_start ( ap, msg );
407
vsprintf ( MSGBUF, msg, ap );
411
error_handle ( opts, win, FALSE, heading, MSGBUF );