And finally (I hope) the last part from the patch
[obnox/wireshark/wip.git] / gtk / help_dlg.c
1 /* help_dlg.c
2  *
3  * $Id$
4  *
5  * Laurent Deniel <laurent.deniel@free.fr>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 2000 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <errno.h>
34
35 #include "epan/filesystem.h"
36 #include "help_dlg.h"
37 #include "text_page.h"
38 #include <epan/prefs.h>
39 #include "gtkglobals.h"
40 #include "ui_util.h"
41 #include "compat_macros.h"
42 #include "dlg_utils.h"
43 #include "simple_dialog.h"
44 #include "webbrowser.h"
45
46 #define HELP_DIR        "help"
47
48
49 #define NOTEBOOK_KEY    "notebook_key"
50
51 static void help_destroy_cb(GtkWidget *w, gpointer data);
52
53 /*
54  * Keep a static pointer to the current "Help" window, if any, so that
55  * if somebody tries to do "Help->Help" while there's already a
56  * "Help" window up, we just pop up the existing one, rather than
57  * creating a new one.
58 */
59 static GtkWidget *help_w = NULL;
60
61 /*
62  * Keep a list of text widgets and corresponding file names as well
63  * (for text format changes).
64  */
65 typedef struct {
66   char *topic;
67   char *pathname;
68   GtkWidget *page;
69 } help_page_t;
70
71 static GSList *help_text_pages = NULL;
72
73
74 /*
75  * Helper function to show a simple help text page.
76  */
77 static GtkWidget * help_page(const char *topic, const char *filename)
78 {
79   GtkWidget *text_page;
80   char *relative_path, *absolute_path;
81   help_page_t *page;
82
83   relative_path = g_strconcat(HELP_DIR, G_DIR_SEPARATOR_S, filename, NULL);
84   absolute_path = get_datafile_path(relative_path);
85   text_page = text_page_new(absolute_path);
86   g_free(relative_path);
87   gtk_widget_show(text_page);
88
89   page = g_malloc(sizeof (help_page_t));
90   page->topic = g_strdup(topic);
91   page->pathname = absolute_path;
92   page->page = text_page;
93   help_text_pages = g_slist_append(help_text_pages, page);
94
95   return text_page;
96 }
97
98
99 /*
100  * Create and show help dialog.
101  */
102 static
103 void help_dialog(void)
104 {
105   GtkWidget *main_vb, *bbox, *help_nb, *close_bt, *label, *topic_vb;
106   char line[4096+1];    /* XXX - size? */
107   char *p;
108   char *filename;
109   char *help_toc_file_path;
110   FILE *help_toc_file;
111
112   if (help_w != NULL) {
113     /* There's already a "Help" dialog box; reactivate it. */
114     reactivate_window(help_w);
115     return;
116   }
117
118   help_toc_file_path = get_datafile_path(HELP_DIR G_DIR_SEPARATOR_S "toc");
119   help_toc_file = fopen(help_toc_file_path, "r");
120   if (help_toc_file == NULL) {
121     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not open file \"%s\": %s",
122                   help_toc_file_path, strerror(errno));
123     g_free(help_toc_file_path);
124     return;
125   }
126
127   help_w = window_new_with_geom(GTK_WINDOW_TOPLEVEL, "Ethereal: Help", "help");
128   gtk_window_set_default_size(GTK_WINDOW(help_w), DEF_WIDTH, DEF_HEIGHT);
129   gtk_container_border_width(GTK_CONTAINER(help_w), 2);
130
131   /* Container for each row of widgets */
132   main_vb = gtk_vbox_new(FALSE, 1);
133   gtk_container_border_width(GTK_CONTAINER(main_vb), 1);
134   gtk_container_add(GTK_CONTAINER(help_w), main_vb);
135
136   /* help topics container */
137   help_nb = gtk_notebook_new();
138   gtk_container_add(GTK_CONTAINER(main_vb), help_nb);
139   OBJECT_SET_DATA(help_w, NOTEBOOK_KEY, help_nb);
140
141   /* help topics */
142   while (fgets(line, sizeof line, help_toc_file) != NULL) {
143     /* Strip off line ending. */
144     p = strpbrk(line, "\r\n");
145     if (p == NULL)
146       break;            /* last line has no line ending */
147     *p = '\0';
148     /* {Topic title}:{filename of help file} */
149     p = strchr(line, ':');
150     if (p != NULL) {
151       *p++ = '\0';
152       filename = p;
153
154       /*
155        * "line" refers to the topic now, and "filename" refers to the
156        * file name.
157        */
158       topic_vb = help_page(line, filename);
159       label = gtk_label_new(line);
160       gtk_notebook_append_page(GTK_NOTEBOOK(help_nb), topic_vb, label);
161     }
162   }
163   if(ferror(help_toc_file)) {
164     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Error reading file \"%s\": %s",
165                   help_toc_file_path, strerror(errno));
166   }
167   fclose(help_toc_file);
168
169
170   /* Button row */
171   bbox = dlg_button_row_new(GTK_STOCK_OK, NULL);
172   gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
173
174   close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
175   window_set_cancel_button(help_w, close_bt, window_cancel_button_cb);
176
177   SIGNAL_CONNECT(help_w, "delete_event", window_delete_event_cb, NULL);
178   SIGNAL_CONNECT(help_w, "destroy", help_destroy_cb, NULL);
179
180   gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(help_w));
181
182   gtk_widget_show_all(help_w);
183   window_present(help_w);
184 } /* help_dialog */
185
186
187 gboolean topic_available(topic_action_e action) {
188
189 #ifdef ETHEREAL_EUG_DIR
190     /* online: we have all pages available */
191     return TRUE;
192 #else
193     /* offline: we have only some pages available */
194     switch(action) {
195     case(HELP_CONTENT):
196         return TRUE;
197         break;
198     case(HELP_GETTING_STARTED):
199         return TRUE;
200         break;
201     case(HELP_CAPTURE_OPTIONS_DIALOG):
202         return TRUE;
203         break;
204     case(HELP_CAPTURE_FILTERS_DIALOG):
205         return TRUE;
206         break;
207     case(HELP_DISPLAY_FILTERS_DIALOG):
208         return TRUE;
209         break;
210     default:
211         return FALSE;
212     }
213 #endif
214 }
215
216 /*
217  * Open the help dialog and show a specific help page.
218  */
219 void help_topic(gchar *topic) {
220     gchar       *page_topic;
221     GtkWidget   *help_nb;
222     GSList      *help_page_ent;
223     gint        page_num = 0;
224     help_page_t *page;
225
226
227     /* show help dialog, if not already opened */
228     help_dialog();
229
230     help_nb = OBJECT_GET_DATA(help_w, NOTEBOOK_KEY);
231
232     /* find page to display */
233     for (help_page_ent = help_text_pages; help_page_ent != NULL;
234          help_page_ent = g_slist_next(help_page_ent))
235     {
236         page = (help_page_t *)help_page_ent->data;
237         page_topic = page->topic;
238         if (strcmp (page_topic, topic) == 0) {
239             /* topic page found, switch to notebook page */
240             gtk_notebook_set_page(GTK_NOTEBOOK(help_nb), page_num);
241             return;
242         }
243         page_num++;
244     }
245
246     /* topic page not found, default (first page) will be shown */
247 }
248
249
250 /*
251  * Help dialog is closed now.
252  */
253 static void help_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
254 {
255   GSList *help_page_ent;
256   help_page_t *page;
257
258   /* Free up the list of help pages. */
259   for (help_page_ent = help_text_pages; help_page_ent != NULL;
260        help_page_ent = g_slist_next(help_page_ent)) {
261     page = (help_page_t *)help_page_ent->data;
262     g_free(page->topic);
263     g_free(page->pathname);
264     g_free(page);
265   }
266   g_slist_free(help_text_pages);
267   help_text_pages = NULL;
268
269   /* Note that we no longer have a Help window. */
270   help_w = NULL;
271 }
272
273
274 /**
275  * Redraw all help pages, to use a new font.
276  */
277 void help_redraw(void)
278 {
279   GSList *help_page_ent;
280   help_page_t *help_page;
281
282   if (help_w != NULL) {
283     for (help_page_ent = help_text_pages; help_page_ent != NULL;
284         help_page_ent = g_slist_next(help_page_ent))
285     {
286       help_page = (help_page_t *)help_page_ent->data;
287       text_page_redraw(help_page->page, help_page->pathname);
288     }
289   }
290 }
291
292
293 static void
294 topic_action(topic_action_e action)
295 {
296     /* pages online at www.ethereal.com */
297     switch(action) {
298     case(ONLINEPAGE_HOME):
299         browser_open_url ("http://www.ethereal.com");
300         break;
301     case(ONLINEPAGE_WIKI):
302         browser_open_url ("http://wiki.ethereal.com");
303         break;
304     case(ONLINEPAGE_DOWNLOAD):
305         browser_open_url ("http://www.ethereal.com/download.html");
306         break;
307     case(ONLINEPAGE_USERGUIDE):
308         browser_open_url ("http://www.ethereal.com/docs/user-guide");
309         break;
310     case(ONLINEPAGE_FAQ):
311         browser_open_url ("http://www.ethereal.com/faq.html");
312         break;
313     case(ONLINEPAGE_SAMPLE_FILES):
314         browser_open_url ("http://wiki.ethereal.com/SampleCaptures");
315         break;
316
317     /* local manual pages */
318     case(LOCALPAGE_MAN_ETHEREAL):
319         browser_open_data_file("ethereal.html");
320         break;
321     case(LOCALPAGE_MAN_ETHEREAL_FILTER):
322         browser_open_data_file("ethereal-filter.html");
323         break;
324     case(LOCALPAGE_MAN_TETHEREAL):
325         browser_open_data_file("tethereal.html");
326         break;
327     case(LOCALPAGE_MAN_MERGECAP):
328         browser_open_data_file("mergecap.html");
329         break;
330     case(LOCALPAGE_MAN_EDITCAP):
331         browser_open_data_file("editcap.html");
332         break;
333     case(LOCALPAGE_MAN_TEXT2PCAP):
334         browser_open_data_file("text2pcap.html");
335         break;
336
337 #ifdef ETHEREAL_EUG_DIR
338     /* local help pages (User's Guide) */
339     case(HELP_CONTENT):
340         browser_open_data_file("eug_html_chunked/index.html");
341         break;
342     case(HELP_CAPTURE_OPTIONS_DIALOG):
343         browser_open_data_file("eug_html_chunked/ChCapCaptureOptions.html");
344         break;
345     case(HELP_CAPTURE_FILTERS_DIALOG):
346         browser_open_data_file("eug_html_chunked/ChWorkDefineFilterSection.html");
347         break;
348     case(HELP_DISPLAY_FILTERS_DIALOG):
349         browser_open_data_file("eug_html_chunked/ChWorkDefineFilterSection.html");
350         break;
351     case(HELP_COLORING_RULES_DIALOG):
352         browser_open_data_file("eug_html_chunked/ChCustColorizationSection.html");
353         break;
354     case(HELP_PRINT_DIALOG):
355         browser_open_data_file("eug_html_chunked/ChIOPrintSection.html");
356         break;
357     case(HELP_FIND_DIALOG):
358         browser_open_data_file("eug_html_chunked/ChWorkFindPacketSection.html");
359         break;
360     case(HELP_GOTO_DIALOG):
361         browser_open_data_file("eug_html_chunked/ChWorkGoToPacketSection.html");
362         break;
363     case(HELP_CAPTURE_INTERFACES_DIALOG):
364         browser_open_data_file("eug_html_chunked/ChCapInterfaceSection.html");
365         break;
366     case(HELP_ENABLED_PROTOCOLS_DIALOG):
367         browser_open_data_file("eug_html_chunked/ChCustProtocolDissectionSection.html");
368         break;
369     case(HELP_DECODE_AS_DIALOG):
370         browser_open_data_file("eug_html_chunked/ChCustProtocolDissectionSection.html");
371         break;
372     case(HELP_DECODE_AS_SHOW_DIALOG):
373         browser_open_data_file("eug_html_chunked/ChCustProtocolDissectionSection.html");
374         break;
375     case(HELP_FOLLOW_TCP_STREAM_DIALOG):
376         browser_open_data_file("eug_html_chunked/ChAdvFollowTCPSection.html");
377         break;
378     case(HELP_STATS_SUMMARY_DIALOG):
379         browser_open_data_file("eug_html_chunked/ChStatSummary.html");
380         break;
381     case(HELP_STATS_PROTO_HIERARCHY_DIALOG):
382         browser_open_data_file("eug_html_chunked/ChStatHierarchy.html");
383         break;
384     case(HELP_STATS_ENDPOINTS_DIALOG):
385         browser_open_data_file("eug_html_chunked/ChStatEndpoints.html");
386         break;
387     case(HELP_STATS_CONVERSATIONS_DIALOG):
388         browser_open_data_file("eug_html_chunked/ChStatConversations.html");
389         break;
390     case(HELP_STATS_IO_GRAPH_DIALOG):
391         browser_open_data_file("eug_html_chunked/ChStatIOGraphs.html");
392         break;
393 #else
394     /* only some help pages are available for offline reading */
395     case(HELP_CONTENT):
396         help_topic("Overview");
397         break;
398     case(HELP_GETTING_STARTED):
399         help_topic("Getting Started");
400         break;
401     case(HELP_CAPTURE_OPTIONS_DIALOG):
402         help_topic("Capturing");
403         break;
404     case(HELP_CAPTURE_FILTERS_DIALOG):
405         help_topic("Capture Filters");
406         break;
407     case(HELP_DISPLAY_FILTERS_DIALOG):
408         help_topic("Display Filters");
409         break;
410 #endif
411
412     default:
413         g_assert_not_reached();
414     }
415 }
416
417
418 void 
419 topic_cb(GtkWidget *w _U_, topic_action_e action)
420 {
421     topic_action(action);
422 }
423
424 void 
425 topic_menu_cb(GtkWidget *w _U_, gpointer data _U_, topic_action_e action) {
426     topic_action(action);
427 }
428