~digisite-dev/digisite/head

« back to all changes in this revision

Viewing changes to mobile-gui/src/error_handler.c

  • Committer: Yann Hamon
  • Date: 2009-02-23 11:33:20 UTC
  • Revision ID: yann.hamon@thehumanjourney.net-20090223113320-k9qbb7bnumgjqkp5
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *            error_handler.c
 
3
 *
 
4
 *  Copyright  2009  Benjamin Ducke, OA Digital
 
5
 *  <benjamin.ducke@oxfordarch.co.uk>>
 
6
 ****************************************************************************/
 
7
 
 
8
/*
 
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.
 
13
 *
 
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.
 
18
 *
 
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
 
22
 */
 
23
 
 
24
 /*
 
25
 
 
26
 Purpose: Provide error message handling.
 
27
 
 
28
 */
 
29
 
 
30
#include <stdlib.h>
 
31
#include <stdarg.h>
 
32
#include <string.h>
 
33
#include <ctype.h>
 
34
#include <gtk/gtk.h>
 
35
 
 
36
#include "global.h"
 
37
#include "error_handler.h"
 
38
#include "dlg_generic.h"
 
39
 
 
40
 
 
41
static gboolean GUI_ERRORS = FALSE;
 
42
static gboolean GUI_WARNINGS = FALSE;
 
43
 
 
44
/* global buffer which all funcs in this file use to pass messages between each other */
 
45
static char MSGBUF [ MAXSTR ];
 
46
 
 
47
 
 
48
void err_set_gui() {
 
49
    GUI_ERRORS = TRUE;
 
50
};
 
51
 
 
52
void err_set_con() {
 
53
    GUI_ERRORS = FALSE;
 
54
};
 
55
 
 
56
void warn_set_gui() {
 
57
    GUI_WARNINGS = TRUE;
 
58
};
 
59
 
 
60
void warn_set_con() {
 
61
    GUI_WARNINGS = FALSE;
 
62
};
 
63
 
 
64
 
 
65
/*
 
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.
 
69
*/
 
70
char *make_sys_info_str ( prg_options *opts )
 
71
{
 
72
    char *str;
 
73
    char buf [ MAXSTR ];
 
74
    int i;
 
75
    char *cp;
 
76
 
 
77
 
 
78
    str = malloc ( sizeof ( char ) * 10 * MAXSTR ); /* should be big enough */
 
79
    sprintf ( str, "\n" );
 
80
 
 
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];
 
95
                if ( *cp == '-' ) {
 
96
                    strcat ( str, "\n" );
 
97
                }
 
98
                strcat ( str, &buf[0] );
 
99
            }
 
100
            strcat ( str, "\n" );
 
101
        }
 
102
    }
 
103
 
 
104
    if ( opts->db.configured ) {
 
105
        strcat ( str, "\n--- Database Connection ---\n" );
 
106
        if ( !opts->db.connected ) {
 
107
            strcat ( str, "Not connected.\n" );
 
108
        } else {
 
109
            snprintf ( buf, MAXSTR, "File: %s\n", opts->db.filename );
 
110
        }
 
111
        strcat ( str, "\n" );
 
112
    }
 
113
 
 
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" );
 
118
        }
 
119
        if ( opts->gui.managed ) {
 
120
        strcat ( str, "Using managed dialogs.\n" );
 
121
        }
 
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] );
 
126
    }
 
127
 
 
128
    return ( str );
 
129
}
 
130
 
 
131
/*
 
132
    Displays an error message in a dialog.
 
133
 
 
134
    There are a number of things to set here:
 
135
 
 
136
    title = the window title
 
137
    symbol_style = warning, error etc.
 
138
    primary = heading (bold)
 
139
    secondary = detail text
 
140
 
 
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.
 
143
*/
 
144
void gui_message ( prg_options *opts, GtkWidget *win,
 
145
                   char *title, int symbol_style,
 
146
                   const char *primary, const char *secondary )
 
147
{
 
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;
 
157
    int ysize;
 
158
    char *details;
 
159
 
 
160
 
 
161
    if ( title == NULL ) {
 
162
        title = strdup ("Important Message");
 
163
    }
 
164
 
 
165
    if ( win == NULL ) {
 
166
        /* create a (hidden) toplevel window to attach this message dialog to */
 
167
        win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
168
    }
 
169
 
 
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 );
 
175
    } else {
 
176
        dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL, symbol_style,
 
177
        GTK_BUTTONS_CLOSE, secondary );
 
178
    }
 
179
 
 
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 );
 
184
 
 
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 );
 
188
 
 
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 );
 
196
 
 
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;
 
205
        }
 
206
        if ( opts->gui.yres >= 350 ) {
 
207
            ysize = (int) opts->gui.yres * 0.50;
 
208
        }
 
209
        if ( opts->gui.yres >= 450 ) {
 
210
            ysize = (int) opts->gui.yres * 0.60;
 
211
        }
 
212
    } else {
 
213
        ysize = 300;
 
214
    }
 
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 ();
 
220
 
 
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 );
 
224
    if ( primary ) {
 
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 );
 
228
    }
 
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 );
 
232
 
 
233
    details = make_sys_info_str ( opts );
 
234
    gtk_text_buffer_insert_at_cursor ( buffer, details, -1 );
 
235
    free ( details );
 
236
 
 
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 );
 
240
 
 
241
    /* add another separator line and instantiate the dialog */
 
242
    separator2 = gtk_hseparator_new ();
 
243
    gtk_container_add ( GTK_CONTAINER ( vbox2 ), separator2 );
 
244
 
 
245
    gtk_widget_show_all ( dialog );
 
246
 
 
247
    gtk_window_set_title (GTK_WINDOW (dialog), title );
 
248
    gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
 
249
 
 
250
    if ( opts->gui.configured ) {
 
251
        dlg_set_size ( opts, dialog );
 
252
    }
 
253
    gtk_dialog_run (GTK_DIALOG (dialog));
 
254
    gtk_widget_destroy (dialog);
 
255
}
 
256
 
 
257
 
 
258
/*
 
259
  Handle an error message.
 
260
 
 
261
  The option "fatal" is a boolean that signals whether this error should lead to program abortion or not.
 
262
 
 
263
  This is for a fatal error that leads to program abortion.
 
264
 
 
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.
 
268
 
 
269
*/
 
270
void error_handle ( prg_options *opts, GtkWidget *win, gboolean fatal,
 
271
                    const char *heading, const char *msg )
 
272
{
 
273
    char buffer [ MAXSTR + 1 ];
 
274
    char str [ MAXSTR + 1 ];
 
275
    char hstr [ MAXSTR + 1 ];
 
276
    char *cp;
 
277
    char *details;
 
278
 
 
279
 
 
280
    strncpy ( buffer, msg, MAXSTR );
 
281
 
 
282
    if ( heading ) {
 
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 */
 
286
        cp = hstr;
 
287
        hstr[0] = toupper ( *cp );
 
288
        cp = &hstr [ strlen(hstr) - 1];
 
289
        if ( *cp == '\n') {
 
290
            *cp = '\0';
 
291
            cp --;
 
292
        }
 
293
        if ( *cp == '.') {
 
294
            *cp = '\0';
 
295
        }
 
296
    }
 
297
 
 
298
    if ( msg == NULL ) {
 
299
        sprintf ( str, "Unspecified error.\n" );
 
300
    } else {
 
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 */
 
304
        cp = str;
 
305
        str[0] = toupper ( *cp );
 
306
        cp = &str [ strlen(str) - 1];
 
307
        if ( *cp == '\n') {
 
308
            *cp = '\0';
 
309
            cp --;
 
310
        }
 
311
        if ( ( *cp != '.') && ( *cp != '!') && ( *cp != '?') ) {
 
312
            cp ++;
 
313
            *cp = '.';
 
314
            cp ++;
 
315
            *cp = '\0';
 
316
        }
 
317
    }
 
318
 
 
319
    if ( !GUI_ERRORS ) {
 
320
        if ( heading ) {
 
321
            if ( fatal ) {
 
322
                fprintf ( stderr, "FATAL ERROR: %s\n%s\n", hstr, str );
 
323
            } else  {
 
324
                fprintf ( stderr, "ERROR: %s\n%s\n", hstr, str );
 
325
            }
 
326
        } else {
 
327
            if ( fatal ) {
 
328
                fprintf ( stderr, "FATAL ERROR\n%s\n", str );
 
329
            } else {
 
330
                fprintf ( stderr, "ERROR%s\n\n", str );
 
331
            }
 
332
        }
 
333
        details = make_sys_info_str ( opts );
 
334
        fprintf ( stderr, details );
 
335
        free ( details );
 
336
        fprintf ( stderr, "\n" );
 
337
    } else {
 
338
        if ( fatal ) {
 
339
            if ( heading ) {
 
340
                gui_message ( opts, win, "FATAL ERROR", GTK_MESSAGE_ERROR, hstr, str );
 
341
            } else {
 
342
                gui_message ( opts, win, "FATAL ERROR", GTK_MESSAGE_ERROR, NULL, str );
 
343
            }
 
344
        } else {
 
345
            if ( heading ) {
 
346
                gui_message ( opts, win, "ERROR", GTK_MESSAGE_ERROR, hstr, str );
 
347
            } else {
 
348
                gui_message ( opts, win, "ERROR", GTK_MESSAGE_ERROR, NULL, str );
 
349
            }
 
350
        }
 
351
    }
 
352
 
 
353
    /* abort? */
 
354
    if ( fatal ) {
 
355
        exit ( -1 );
 
356
    }
 
357
};
 
358
 
 
359
 
 
360
/* ************************************************************************************ */
 
361
/*                                                      P U B L I C  I N T E R F A C E                              */
 
362
/* ************************************************************************************ */
 
363
 
 
364
/*
 
365
  The following functions are the public interface functions for throwing error and warning messages.
 
366
 
 
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.
 
370
 
 
371
*/
 
372
 
 
373
/*
 
374
  This is for a fatal error that leads to program abortion.
 
375
*/
 
376
void err_throw_fatal (  prg_options *opts, GtkWidget *win,
 
377
                        const char *heading, const char *msg,... )
 
378
{
 
379
  va_list ap;
 
380
 
 
381
 
 
382
  if ( msg == NULL ) {
 
383
        sprintf ( MSGBUF, "Unspecified error." );
 
384
  } else {
 
385
    va_start ( ap, msg );
 
386
    vsprintf ( MSGBUF, msg, ap );
 
387
    va_end ( ap );
 
388
  }
 
389
 
 
390
  error_handle ( opts, win, TRUE, heading, MSGBUF );
 
391
};
 
392
 
 
393
 
 
394
/*
 
395
  This is for a non-fatal error that does not lead to program abortion.
 
396
*/
 
397
void err_throw_non_fatal (  prg_options *opts, GtkWidget *win,
 
398
                            const char *heading, const char *msg,... )
 
399
{
 
400
  va_list ap;
 
401
 
 
402
 
 
403
  if ( msg == NULL ) {
 
404
        sprintf ( MSGBUF, "Unspecified error." );
 
405
  } else {
 
406
    va_start ( ap, msg );
 
407
    vsprintf ( MSGBUF, msg, ap );
 
408
    va_end ( ap );
 
409
  }
 
410
 
 
411
  error_handle ( opts, win, FALSE, heading, MSGBUF );
 
412
};
 
413