Added help button in expert info and expert info composite dialogs.
[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  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
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 "gui_utils.h"
41 #include "compat_macros.h"
42 #include "dlg_utils.h"
43 #include "simple_dialog.h"
44 #include "webbrowser.h"
45 #include "file_util.h"
46
47 #ifdef HHC_DIR
48 #include <windows.h>
49 #include <htmlhelp.h>
50 #include "epan/unicode-utils.h"
51 #endif
52
53
54 #define HELP_DIR        "help"
55
56
57 #define NOTEBOOK_KEY    "notebook_key"
58
59 /*
60  * Keep a static pointer to the current "Help" window, if any, so that
61  * if somebody tries to do "Help->Help" while there's already a
62  * "Help" window up, we just pop up the existing one, rather than
63  * creating a new one.
64 */
65 static GtkWidget *help_w = NULL;
66
67 /*
68  * Keep a list of text widgets and corresponding file names as well
69  * (for text format changes).
70  */
71 typedef struct {
72   char *topic;
73   char *pathname;
74   GtkWidget *page;
75 } help_page_t;
76
77 static GSList *help_text_pages = NULL;
78
79
80
81 gboolean topic_available(topic_action_e action) {
82
83 #if (GLIB_MAJOR_VERSION >= 2)
84     if(action == HELP_CAPTURE_INTERFACES_DETAILS_DIALOG) {
85         /* XXX - add the page HELP_CAPTURE_INTERFACES_DETAILS_DIALOG and remove this if */
86         /* page currently not existing in user's guide */
87         return FALSE;
88     }
89     /* online: we have almost all possible pages available */
90     return TRUE;
91 #else
92     /* offline: we have only some pages available */
93     switch(action) {
94     case(HELP_CONTENT):
95         return TRUE;
96         break;
97     case(HELP_GETTING_STARTED):
98         return TRUE;
99         break;
100     case(HELP_CAPTURE_OPTIONS_DIALOG):
101         return TRUE;
102         break;
103     case(HELP_CAPTURE_FILTERS_DIALOG):
104         return TRUE;
105         break;
106     case(HELP_DISPLAY_FILTERS_DIALOG):
107         return TRUE;
108         break;
109     default:
110         return FALSE;
111     }
112 #endif
113 }
114
115
116 #if (GLIB_MAJOR_VERSION >= 2)
117 /*
118  * Open the help dialog and show a specific HTML help page.
119  */
120 void help_topic_html(const gchar *topic) {
121     GString *url;
122
123
124     /* try to open local .chm file */
125 #ifdef HHC_DIR
126     HWND hw;
127
128     url = g_string_new("");
129
130     g_string_append_printf(url, "%s\\user-guide.chm::/wsug_chm/%s>Wireshark Help",
131         get_datafile_dir(), topic);
132
133     hw = HtmlHelpW(NULL,
134         utf_8to16(url->str),
135         HH_DISPLAY_TOPIC, 0);
136
137     g_string_free(url, TRUE /* free_segment */);
138
139     /* if the .chm file could be opened, stop here */
140     if(hw != NULL) {
141         return;
142     }
143 #endif /* HHC_DIR */
144
145     url = g_string_new("");
146
147     /* try to open the HTML page from wireshark.org instead */
148     g_string_append_printf(url, "http://www.wireshark.org/docs/wsug_html_chunked/%s", topic);
149
150     browser_open_url(url->str);
151
152     g_string_free(url, TRUE /* free_segment */);
153 }
154 #endif
155
156
157 #if (GLIB_MAJOR_VERSION < 2)
158 /*
159  * Helper function to show a simple help text page.
160  */
161 static GtkWidget * help_page(const char *topic, const char *filename)
162 {
163   GtkWidget *text_page;
164   char *relative_path, *absolute_path;
165   help_page_t *page;
166
167   relative_path = g_strconcat(HELP_DIR, G_DIR_SEPARATOR_S, filename, NULL);
168   absolute_path = get_datafile_path(relative_path);
169   text_page = text_page_new(absolute_path);
170   g_free(relative_path);
171   gtk_widget_show(text_page);
172
173   page = g_malloc(sizeof (help_page_t));
174   page->topic = g_strdup(topic);
175   page->pathname = absolute_path;
176   page->page = text_page;
177   help_text_pages = g_slist_append(help_text_pages, page);
178
179   return text_page;
180 }
181
182
183 /*
184  * Help dialog is closed now.
185  */
186 static void help_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
187 {
188   GSList *help_page_ent;
189   help_page_t *page;
190
191   /* Free up the list of help pages. */
192   for (help_page_ent = help_text_pages; help_page_ent != NULL;
193        help_page_ent = g_slist_next(help_page_ent)) {
194     page = (help_page_t *)help_page_ent->data;
195     g_free(page->topic);
196     g_free(page->pathname);
197     g_free(page);
198   }
199   g_slist_free(help_text_pages);
200   help_text_pages = NULL;
201
202   /* Note that we no longer have a Help window. */
203   help_w = NULL;
204 }
205
206
207 /*
208  * Create and show help dialog.
209  */
210 static
211 void help_dialog(void)
212 {
213   GtkWidget *main_vb, *bbox, *help_nb, *close_bt, *label, *topic_vb;
214   char line[4096+1];    /* XXX - size? */
215   char *p;
216   char *filename;
217   char *help_toc_file_path;
218   FILE *help_toc_file;
219
220   if (help_w != NULL) {
221     /* There's already a "Help" dialog box; reactivate it. */
222     reactivate_window(help_w);
223     return;
224   }
225
226   help_toc_file_path = get_datafile_path(HELP_DIR G_DIR_SEPARATOR_S "toc");
227   help_toc_file = eth_fopen(help_toc_file_path, "r");
228   if (help_toc_file == NULL) {
229     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not open file \"%s\": %s",
230                   help_toc_file_path, strerror(errno));
231     g_free(help_toc_file_path);
232     return;
233   }
234
235   help_w = window_new_with_geom(GTK_WINDOW_TOPLEVEL, "Wireshark: Help", "help");
236   gtk_window_set_default_size(GTK_WINDOW(help_w), DEF_WIDTH, DEF_HEIGHT);
237   gtk_container_border_width(GTK_CONTAINER(help_w), 2);
238
239   /* Container for each row of widgets */
240   main_vb = gtk_vbox_new(FALSE, 1);
241   gtk_container_border_width(GTK_CONTAINER(main_vb), 1);
242   gtk_container_add(GTK_CONTAINER(help_w), main_vb);
243
244   /* help topics container */
245   help_nb = gtk_notebook_new();
246   gtk_container_add(GTK_CONTAINER(main_vb), help_nb);
247   OBJECT_SET_DATA(help_w, NOTEBOOK_KEY, help_nb);
248
249   /* help topics */
250   while (fgets(line, sizeof line, help_toc_file) != NULL) {
251     /* Strip off line ending. */
252     p = strpbrk(line, "\r\n");
253     if (p == NULL)
254       break;            /* last line has no line ending */
255     *p = '\0';
256     /* {Topic title}:{filename of help file} */
257     p = strchr(line, ':');
258     if (p != NULL) {
259       *p++ = '\0';
260       filename = p;
261
262       /*
263        * "line" refers to the topic now, and "filename" refers to the
264        * file name.
265        */
266       topic_vb = help_page(line, filename);
267       label = gtk_label_new(line);
268       gtk_notebook_append_page(GTK_NOTEBOOK(help_nb), topic_vb, label);
269     }
270   }
271   if(ferror(help_toc_file)) {
272     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Error reading file \"%s\": %s",
273                   help_toc_file_path, strerror(errno));
274   }
275   fclose(help_toc_file);
276
277
278   /* Button row */
279   bbox = dlg_button_row_new(GTK_STOCK_OK, NULL);
280   gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
281
282   close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
283   window_set_cancel_button(help_w, close_bt, window_cancel_button_cb);
284
285   SIGNAL_CONNECT(help_w, "delete_event", window_delete_event_cb, NULL);
286   SIGNAL_CONNECT(help_w, "destroy", help_destroy_cb, NULL);
287
288   gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(help_w));
289
290   gtk_widget_show_all(help_w);
291   window_present(help_w);
292 } /* help_dialog */
293
294
295 /*
296  * Open the help dialog and show a specific GTK help page.
297  */
298 static void help_topic_gtk(const gchar *topic) {
299     gchar       *page_topic;
300     GtkWidget   *help_nb;
301     GSList      *help_page_ent;
302     gint        page_num = 0;
303     help_page_t *page;
304
305
306     /* show help dialog, if not already opened */
307     help_dialog();
308
309     help_nb = OBJECT_GET_DATA(help_w, NOTEBOOK_KEY);
310
311     /* find page to display */
312     for (help_page_ent = help_text_pages; help_page_ent != NULL;
313          help_page_ent = g_slist_next(help_page_ent))
314     {
315         page = (help_page_t *)help_page_ent->data;
316         page_topic = page->topic;
317         if (strcmp (page_topic, topic) == 0) {
318             /* topic page found, switch to notebook page */
319             gtk_notebook_set_page(GTK_NOTEBOOK(help_nb), page_num);
320             return;
321         }
322         page_num++;
323     }
324
325     /* topic page not found, default (first page) will be shown */
326 }
327 #endif  /* GLIB_MAJOR_VERSION < 2 */
328
329
330 /**
331  * Redraw all help pages, to use a new font.
332  */
333 void help_redraw(void)
334 {
335   GSList *help_page_ent;
336   help_page_t *help_page;
337
338   if (help_w != NULL) {
339     for (help_page_ent = help_text_pages; help_page_ent != NULL;
340         help_page_ent = g_slist_next(help_page_ent))
341     {
342       help_page = (help_page_t *)help_page_ent->data;
343       text_page_redraw(help_page->page, help_page->pathname);
344     }
345   }
346 }
347
348
349 static void
350 topic_action(topic_action_e action)
351 {
352     /* pages online at www.wireshark.org */
353     switch(action) {
354     case(ONLINEPAGE_HOME):
355         browser_open_url ("http://www.wireshark.org");
356         break;
357     case(ONLINEPAGE_WIKI):
358         browser_open_url ("http://wiki.wireshark.org");
359         break;
360     case(ONLINEPAGE_DOWNLOAD):
361         browser_open_url ("http://www.wireshark.org/download/");
362         break;
363     case(ONLINEPAGE_USERGUIDE):
364         browser_open_url ("http://www.wireshark.org/docs/wsug_html_chunked/");
365         break;
366     case(ONLINEPAGE_FAQ):
367         browser_open_url ("http://www.wireshark.org/faq.html");
368         break;
369     case(ONLINEPAGE_SAMPLE_FILES):
370         browser_open_url ("http://wiki.wireshark.org/SampleCaptures");
371         break;
372
373     /* local manual pages */
374     case(LOCALPAGE_MAN_WIRESHARK):
375         browser_open_data_file("wireshark.html");
376         break;
377     case(LOCALPAGE_MAN_WIRESHARK_FILTER):
378         browser_open_data_file("wireshark-filter.html");
379         break;
380     case(LOCALPAGE_MAN_TSHARK):
381         browser_open_data_file("tshark.html");
382         break;
383     case(LOCALPAGE_MAN_DUMPCAP):
384         browser_open_data_file("dumpcap.html");
385         break;
386     case(LOCALPAGE_MAN_MERGECAP):
387         browser_open_data_file("mergecap.html");
388         break;
389     case(LOCALPAGE_MAN_EDITCAP):
390         browser_open_data_file("editcap.html");
391         break;
392     case(LOCALPAGE_MAN_TEXT2PCAP):
393         browser_open_data_file("text2pcap.html");
394         break;
395
396 #if (GLIB_MAJOR_VERSION >= 2)
397     /* local help pages (User's Guide) */
398     case(HELP_CONTENT):
399         help_topic_html( "index.html");
400         break;
401     case(HELP_CAPTURE_OPTIONS_DIALOG):
402         help_topic_html("ChCapCaptureOptions.html");
403         break;
404     case(HELP_CAPTURE_FILTERS_DIALOG):
405         help_topic_html("ChWorkDefineFilterSection.html");
406         break;
407     case(HELP_DISPLAY_FILTERS_DIALOG):
408         help_topic_html("ChWorkDefineFilterSection.html");
409         break;
410     case(HELP_COLORING_RULES_DIALOG):
411         help_topic_html("ChCustColorizationSection.html");
412         break;
413     case(HELP_CONFIG_PROFILES_DIALOG):
414         help_topic_html("ChCustConfigProfilesSection.html");
415         break;
416     case(HELP_PRINT_DIALOG):
417         help_topic_html("ChIOPrintSection.html");
418         break;
419     case(HELP_FIND_DIALOG):
420         help_topic_html("ChWorkFindPacketSection.html");
421         break;
422     case(HELP_GOTO_DIALOG):
423         help_topic_html("ChWorkGoToPacketSection.html");
424         break;
425     case(HELP_CAPTURE_INTERFACES_DIALOG):
426         help_topic_html("ChCapInterfaceSection.html");
427         break;
428     case(HELP_CAPTURE_INFO_DIALOG):
429         help_topic_html("ChCapRunningSection.html");
430         break;
431     case(HELP_ENABLED_PROTOCOLS_DIALOG):
432         help_topic_html("ChCustProtocolDissectionSection.html");
433         break;
434     case(HELP_DECODE_AS_DIALOG):
435         help_topic_html("ChCustProtocolDissectionSection.html");
436         break;
437     case(HELP_DECODE_AS_SHOW_DIALOG):
438         help_topic_html("ChCustProtocolDissectionSection.html");
439         break;
440     case(HELP_FOLLOW_TCP_STREAM_DIALOG):
441         help_topic_html("ChAdvFollowTCPSection.html");
442         break;
443     case(HELP_EXPERT_INFO_DIALOG):
444         help_topic_html("ChAdvExpert.html");
445         break;
446     case(HELP_STATS_SUMMARY_DIALOG):
447         help_topic_html("ChStatSummary.html");
448         break;
449     case(HELP_STATS_PROTO_HIERARCHY_DIALOG):
450         help_topic_html("ChStatHierarchy.html");
451         break;
452     case(HELP_STATS_ENDPOINTS_DIALOG):
453         help_topic_html("ChStatEndpoints.html");
454         break;
455     case(HELP_STATS_CONVERSATIONS_DIALOG):
456         help_topic_html("ChStatConversations.html");
457         break;
458     case(HELP_STATS_IO_GRAPH_DIALOG):
459         help_topic_html("ChStatIOGraphs.html");
460         break;
461     case(HELP_STATS_WLAN_TRAFFIC_DIALOG):
462         help_topic_html("ChStatWLANTraffic.html");
463         break;
464     case(HELP_FILESET_DIALOG):
465         help_topic_html("ChIOFileSetSection.html");
466         break;
467     case(HELP_CAPTURE_INTERFACES_DETAILS_DIALOG):
468         help_topic_html("ChCapInterfaceDetailsSection.html");
469         break;
470     case(HELP_PREFERENCES_DIALOG):
471         help_topic_html("ChCustPreferencesSection.html");
472         break;
473     case(HELP_EXPORT_FILE_DIALOG):
474     case(HELP_EXPORT_FILE_WIN32_DIALOG):
475         help_topic_html("ChIOExportSection.html");
476         break;
477     case(HELP_EXPORT_BYTES_DIALOG):
478     case(HELP_EXPORT_BYTES_WIN32_DIALOG):
479         help_topic_html("ChIOExportSection.html#ChIOExportSelectedDialog");
480         break;
481     case(HELP_EXPORT_OBJECT_LIST):
482         help_topic_html("ChIOExportSection.html#ChIOExportObjectsDialog");
483         break;
484     case(HELP_OPEN_DIALOG):
485     case(HELP_OPEN_WIN32_DIALOG):
486         help_topic_html("ChIOOpenSection.html");
487         break;
488     case(HELP_MERGE_DIALOG):
489     case(HELP_MERGE_WIN32_DIALOG):
490         help_topic_html("ChIOMergeSection.html");
491         break;
492     case(HELP_SAVE_DIALOG):
493     case(HELP_SAVE_WIN32_DIALOG):
494         help_topic_html("ChIOSaveSection.html");
495         break;
496 #else
497     /* only some help pages are available for offline reading */
498     case(HELP_CONTENT):
499         help_topic_gtk("Overview");
500         break;
501     case(HELP_GETTING_STARTED):
502         help_topic_gtk("Getting Started");
503         break;
504     case(HELP_CAPTURE_OPTIONS_DIALOG):
505         help_topic_gtk("Capturing");
506         break;
507     case(HELP_CAPTURE_FILTERS_DIALOG):
508         help_topic_gtk("Capture Filters");
509         break;
510     case(HELP_DISPLAY_FILTERS_DIALOG):
511         help_topic_gtk("Display Filters");
512         break;
513 #endif /* GLIB_MAJOR_VERSION */
514
515     default:
516         g_assert_not_reached();
517     }
518 }
519
520
521 void
522 topic_cb(GtkWidget *w _U_, topic_action_e action)
523 {
524     topic_action(action);
525 }
526
527 void
528 topic_menu_cb(GtkWidget *w _U_, gpointer data _U_, topic_action_e action) {
529     topic_action(action);
530 }
531