/* * Copyright (c) by Allin Cottrell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* helpfiles.c for gretl */ #include "gretl.h" #include "textbuf.h" #include "gretl_www.h" #include "treeutils.h" #include "dlgutils.h" #ifdef G_OS_WIN32 # include "gretlwin32.h" #else # include # include # include # include # include #endif #define HDEBUG 0 static int translated_helpfile = -1; static char *en_gui_helpfile; static char *en_cli_helpfile; typedef struct help_head_t help_head; struct help_head_t { char *name; /* name of heading, e.g. "Testing" */ int *topics; /* array of topics under heading by command number */ char **topicnames; /* array of descriptive topic names (GUI help only) */ int *pos; /* array of byte offsets into file for topics */ int ntalloc; /* number of topics initally allocated */ int ntopics; /* actual number of topics under this heading */ }; static help_head **cli_heads, **gui_heads; static help_head **en_cli_heads, **en_gui_heads; static windata_t *helpwin (int cli, int en); static void real_do_help (int hcode, int pos, int cli, int en); static void en_text_cmdref (gpointer p, guint u, GtkWidget *w); /* searching stuff */ static void find_in_text (GtkWidget *widget, gpointer data); static void find_in_listbox (GtkWidget *widget, gpointer data); static void find_string_dialog (void (*findfunc)(), gpointer data); static GtkWidget *find_window = NULL; static GtkWidget *find_entry; static char *needle; GtkItemFactoryEntry help_menu_items[] = { { N_("/_Topics"), NULL, NULL, 0, "", GNULL }, { N_("/_Find"), NULL, NULL, 0, "", GNULL }, { N_("/Find/_Find in window"), NULL, menu_find, 0, "", GTK_STOCK_FIND }, { NULL, NULL, NULL, 0, NULL, GNULL } }; struct gui_help_item { int code; char *string; }; static struct gui_help_item gui_help_items[] = { { 0, "nothing" }, { GR_PLOT, "graphing" }, { GR_XY, "graphing" }, { GR_DUMMY, "factorized" }, { BXPLOT, "boxplots" }, { GR_BOX, "boxplots" }, { GR_NBOX, "boxplots" }, { GR_3D, "3-D" }, { ONLINE, "online" }, { MARKERS, "markers" }, { EXPORT, "export" }, { SMPLBOOL, "sampling" }, { SMPLDUM, "sampling" }, { COMPACT, "compact" }, { EXPAND, "expand" }, { VSETMISS, "missing" }, { GSETMISS, "missing" }, { GUI_HELP, "dialog" }, { MODELTABLE, "modeltab" }, { GRAPHPAGE, "graphpag" }, { GENR_RANDOM, "genrand" }, { SEED_RANDOM, "genseed" }, { KERNEL_DENSITY, "density" }, { HCCME, "hccme" }, { IRF_BOOT, "irfboot" }, { HTEST, "gui-htest" }, { HTESTNP, "gui-htest-np" }, { MODEL_RESTR, "restrict-model" }, { SYS_RESTR, "restrict-system" }, { VECM_RESTR, "restrict-vecm" }, { LAGS_DIALOG, "lags-dialog" }, { COPY_FORMATS, "copy-formats" }, { MINIBUF, "minibuffer" }, { VLAGSEL, "VAR-lagselect" }, { VAROMIT, "VAR-omit" }, { PANEL_MODE, "panel-mode" }, { PANEL_WLS, "panel-wls" }, { PANEL_B, "panel-between" }, { BOOTSTRAP, "bootstrap" }, { -1, NULL }, }; /* state the topic headings from the help files so they can be translated */ const char *intl_topics[] = { N_("Dataset"), N_("Estimation"), N_("Graphs"), N_("Prediction"), N_("Printing"), N_("Programming"), N_("Statistics"), N_("Tests"), N_("Transformations"), N_("Utilities") }; static int extra_command_number (const char *s) { int i; for (i=1; gui_help_items[i].code > 0; i++) { if (!strcmp(s, gui_help_items[i].string)) { return gui_help_items[i].code; } } return -1; } static char *help_string_from_cmd (int cmd) { int i; for (i=1; gui_help_items[i].code > 0; i++) { if (cmd == gui_help_items[i].code) { return gui_help_items[i].string; } } return NULL; } static void set_en_help_file (int gui) { char *helpfile, *tmp, *p; if (gui) { helpfile = paths.helpfile; } else { helpfile = paths.cmd_helpfile; } tmp = malloc(strlen(helpfile) + 1); if (tmp != NULL) { strcpy(tmp, helpfile); #ifdef G_OS_WIN32 p = strrchr(tmp, '_'); if (p != NULL) strcpy(p, ".txt"); #else p = strrchr(tmp, '.'); if (p != NULL) *p = 0; #endif if (gui) { en_gui_helpfile = tmp; } else { en_cli_helpfile = tmp; } } } static void set_translated_helpfile (void) { char *p; #ifdef G_OS_WIN32 p = strrchr(paths.helpfile, '_'); if (p != NULL && strncmp(p, "_hlp", 4)) { translated_helpfile = 1; } else { translated_helpfile = 0; } #else p = strrchr(paths.helpfile, '.'); if (p != NULL && strcmp(p, ".hlp")) { translated_helpfile = 1; } else { translated_helpfile = 0; } #endif if (translated_helpfile == 1) { set_en_help_file(0); set_en_help_file(1); } } char *quoted_help_string (const char *s) { const char *p, *q; p = strchr(s, '"'); q = strrchr(s, '"'); if (p != NULL && q != NULL && q - p > 1) { p++; return g_strndup(p, q - p); } return g_strdup("Missing string"); } /* extract the word following "# " at the beginning of a new line in a gretl help file (up to a max length of len) */ static int get_following_word (char *s, int len, int *b, FILE *fp) { int c, i = 0; memset(s, 0, len); /* skip one space */ if ((c = getc(fp)) == EOF) { return 1; } while ((c = getc(fp)) != EOF && i < len) { if (c == ' ' || c == '\n') { i++; break; } else { s[i++] = c; } } *b += i + 1; return (*s == 0); } static int help_topic_number (const char *word, int gui) { int hnum = gretl_command_number(word); if (hnum == 0 && gui) { hnum = extra_command_number(word); } return hnum; } static int get_help_word (char *s, help_head **heads, int nh, int gui, int *pi, int *pj) { int hnum; int i, j; hnum = help_topic_number(s, gui); if (hnum == 0) { *pi = -1; *pj = -1; return 0; } for (i=0; intopics; j++) { if (hnum == heads[i]->topics[j]) { *pi = i; *pj = j; return 0; } } } return 1; } static int get_byte_positions (help_head **heads, int nh, int gui, FILE *fp) { char word[16]; int m = 0, n = 0; int c, cbak = 0; int i, j, b = 0; int err = 0; rewind(fp); for (i=0; intopics; } while ((c = getc(fp)) != EOF) { if (c == '#' && cbak == '\n') { int pos = b; err = get_following_word(word, 16, &b, fp); if (!err) { /* look up 'test' and set pos */ err = get_help_word(word, heads, nh, gui, &i, &j); } if (!err && i >= 0 && j >= 0) { heads[i]->pos[j] = pos; m++; } #if HDEBUG if (i >= 0 && j >= 0) { fprintf(stderr, "%s: setting heads[%d]->pos[%d] = %d\n", word, i, j, pos); } else { fprintf(stderr, "%s: pos = %d\n", word, pos); } #endif if (err || m == n) { break; } } b++; cbak = c; } #if HDEBUG fprintf(stderr, "get_byte_positions: n = %d, m = %d, returning %d\n", n, m, err); #endif return err; } static void free_help_head (help_head *head) { int i; free(head->name); free(head->topics); free(head->pos); if (head->topicnames != NULL) { for (i=0; intalloc; i++) { free(head->topicnames[i]); } free(head->topicnames); } free(head); } static int head_allocate_topicnames (help_head *head) { int i, n = head->ntopics; head->topicnames = malloc(n * sizeof *head->topicnames); if (head->topicnames == NULL) { return 1; } for (i=0; itopicnames[i] = NULL; } head->ntalloc = n; return 0; } static help_head *help_head_new (const char *name, int nt, int gui) { help_head *head = malloc(sizeof *head); if (head != NULL) { head->ntopics = nt; head->name = NULL; head->topics = NULL; head->pos = NULL; head->topicnames = NULL; } head->name = gretl_strdup(name); head->topics = malloc(nt * sizeof *head->topics); head->pos = malloc(nt * sizeof *head->pos); if (head->name == NULL || head->topics == NULL || head->pos == NULL) { free_help_head(head); head = NULL; } else if (gui && head_allocate_topicnames(head)) { free_help_head(head); head = NULL; } return head; } static help_head **allocate_heads (int n) { help_head **heads; int i; heads = malloc(n * sizeof *heads); if (heads != NULL) { for (i=0; i 0) { head->topics[*i] = hnum; if (label != NULL && head->topicnames != NULL) { head->topicnames[*i] = label; } *i += 1; #if HDEBUG fprintf(stderr, "add_topic_to_head: topic %d: word = %s: hnum = %d\n", *i, word, hnum); #endif } else { fprintf(stderr, "helpfile error: word='%s' not recognized\n", word); head->ntopics -= 1; if (label != NULL) { free(label); } } } static int get_helpfile_structure (help_head ***pheads, int gui, const char *fname) { help_head **heads = NULL; FILE *fp; char line[128]; char tmp[32]; int i, j, k, nh2; int nh = 0; int err = 0; fp = gretl_fopen(fname, "r"); if (fp == NULL) { fprintf(stderr, I_("help file %s is not accessible\n"), fname); return 1; } if (fgets(line, sizeof line, fp) == NULL) { err = 1; goto bailout; } if (!sscanf(line, "headings %d", &nh) || nh <= 0) { fprintf(stderr, "Couldn't reading number of headings in helpfile\n"); err = 1; goto bailout; } heads = allocate_heads(nh + 1); /* NULL sentinel at end */ if (heads == NULL) { err = 1; goto bailout; } #if HDEBUG fprintf(stderr, "Found %d topic headings\n", nh); #endif nh2 = 0; /* loop across the headings */ for (i=0; intopics; j++) { if (pos == gui_heads[i]->pos[j]) { return help_string_from_cmd(gui_heads[i]->topics[j]); } } } return NULL; } static int gui_pos_from_cmd (int cmd, int en) { help_head **heads; char *helpstr; int i, j; heads = (en)? en_gui_heads : gui_heads; if (heads == NULL) { return -1; } for (i=0; heads[i] != NULL; i++) { for (j=0; jntopics; j++) { if (cmd == heads[i]->topics[j]) { return heads[i]->pos[j]; } } } /* special for gui-specific help items */ helpstr = help_string_from_cmd(cmd); if (helpstr != NULL) { int altcode = extra_command_number(helpstr); for (i=0; heads[i] != NULL; i++) { for (j=0; jntopics; j++) { if (altcode == heads[i]->topics[j]) { return heads[i]->pos[j]; } } } } return -1; } static int cli_pos_from_cmd (int cmd, int en) { help_head **heads; int i, j; heads = (en)? en_cli_heads : cli_heads; if (heads == NULL) { return -1; } for (i=0; heads[i] != NULL; i++) { for (j=0; jntopics; j++) { if (cmd == heads[i]->topics[j]) { return heads[i]->pos[j]; } } } return -1; } static void en_help_callback (gpointer p, int cli, GtkWidget *w) { windata_t *hwin = (windata_t *) p; int pos, hc = hwin->active_var; if (cli) { pos = cli_pos_from_cmd(hc, 1); if (pos < 0) { pos = 0; } } else { pos = gui_pos_from_cmd(hc, 1); } real_do_help(hc, pos, cli, 1); } static void add_en_help_item (windata_t *hwin, int cli) { GtkItemFactoryEntry item; item.accelerator = NULL; item.item_type = ""; item.callback = NULL; item.callback_action = 0; item.path = "/_English"; gtk_item_factory_create_item(hwin->ifac, &item, NULL, 1); item.item_type = NULL; item.callback = en_help_callback; item.callback_action = cli; item.path = g_strdup_printf("/English/%s", _("Show English help")); gtk_item_factory_create_item(hwin->ifac, &item, hwin, 1); g_free(item.path); } static void add_help_topics (windata_t *hwin, int cli, int en) { GtkItemFactoryEntry hitem; const gchar *mpath = N_("/_Topics"); help_head **hds; int i, j; if (en) { hds = (cli)? en_cli_heads : en_gui_heads; } else { hds = (cli)? cli_heads : gui_heads; } /* Are there any topics to add? */ if (hds == NULL) { return; } hitem.accelerator = NULL; if (cli) { /* Add general index as "topic" */ hitem.callback_action = 0; hitem.item_type = NULL; hitem.path = g_strdup_printf("%s/%s", mpath, (en)? "Index" : _("Index")); hitem.callback = (en)? en_text_cmdref : plain_text_cmdref; gtk_item_factory_create_item(hwin->ifac, &hitem, GINT_TO_POINTER(0), 1); g_free(hitem.path); } /* put the topics under the menu heading */ for (i=0; hds[i] != NULL; i++) { const char *headname = (en)? hds[i]->name : _(hds[i]->name); if (hds[i]->ntopics == 0) { continue; } hitem.callback_action = 0; hitem.item_type = ""; hitem.path = g_strdup_printf("%s/%s", mpath, headname); hitem.callback = NULL; gtk_item_factory_create_item(hwin->ifac, &hitem, NULL, 1); g_free(hitem.path); for (j=0; jntopics; j++) { int tnum = -1; int topic_ok = 1; hitem.callback_action = hds[i]->pos[j]; hitem.item_type = NULL; hitem.path = NULL; tnum = hds[i]->topics[j]; if (hds[i]->topicnames != NULL) { hitem.path = g_strdup_printf("%s/%s/%s", mpath, headname, hds[i]->topicnames[j]); #if HDEBUG fprintf(stderr, "(1) Built help topic path from\n" " '%s', '%s' and '%s'\n", mpath, headname, hds[i]->topicnames[j]); #endif } else { if (tnum < NC) { /* a regular gretl command */ hitem.path = g_strdup_printf("%s/%s/%s", mpath, headname, gretl_command_word(tnum)); #if HDEBUG fprintf(stderr, "(2) Built help topic path from\n" " '%s', '%s' and '%s'\n", mpath, headname, gretl_command_word(tnum)); #endif } else if (!cli) { /* a gui special item? */ char *gstr = get_gui_help_string(hds[i]->pos[j]); if (gstr != NULL) { hitem.path = g_strdup_printf("%s/%s/%s", mpath, headname, gstr); #if HDEBUG fprintf(stderr, "(3) Built help topic path from\n" " '%s', '%s' and '%s'\n", mpath, headname, gstr); #endif } else { topic_ok = 0; } } else { topic_ok = 0; } } if (topic_ok) { if (en) { hitem.callback = (cli)? do_en_cli_help : do_en_gui_help; } else { hitem.callback = (cli)? do_cli_help : do_gui_help; } gtk_item_factory_create_item(hwin->ifac, &hitem, GINT_TO_POINTER(tnum), 1); g_free(hitem.path); } } } } static windata_t *helpwin (int cli, int en) { windata_t *vwin = NULL; char *helpfile = NULL; int role; if (cli) { helpfile = (en)? en_cli_helpfile : paths.cmd_helpfile; role = (en)? CLI_HELP_EN : CLI_HELP; } else { helpfile = (en)? en_gui_helpfile : paths.helpfile; role = (en)? GUI_HELP_EN : GUI_HELP; } if (helpfile == NULL) return NULL; vwin = view_help_file(helpfile, role, help_menu_items); add_help_topics(vwin, cli, en); if (translated_helpfile && !en) { add_en_help_item(vwin, cli); } return vwin; } void context_help (GtkWidget *widget, gpointer data) { int pos, hcode = GPOINTER_TO_INT(data); int en = 0; pos = gui_pos_from_cmd(hcode, 0); if (pos < 0 && translated_helpfile) { en = 1; pos = gui_pos_from_cmd(hcode, en); } #if HDEBUG fprintf(stderr, "context_help: hcode=%d, pos=%d, en=%d\n", hcode, pos, en); #endif real_do_help(hcode, pos, 0, en); } static gboolean nullify_hwin (GtkWidget *w, windata_t **phwin) { *phwin = NULL; return FALSE; } static void real_do_help (int hcode, int pos, int cli, int en) { static windata_t *gui_hwin; static windata_t *cli_hwin; static windata_t *en_gui_hwin; static windata_t *en_cli_hwin; windata_t *hwin; if (pos < 0) { dummy_call(); return; } #if HDEBUG fprintf(stderr, "real_do_help: hcode=%d, pos=%d, cli=%d, en=%d\n", hcode, pos, cli, en); fprintf(stderr, "gui_hwin = %p\n", (void *) gui_hwin); fprintf(stderr, "cli_hwin = %p\n", (void *) cli_hwin); fprintf(stderr, "en_gui_hwin = %p\n", (void *) en_gui_hwin); fprintf(stderr, "en_cli_hwin = %p\n", (void *) en_cli_hwin); #endif if (en) { hwin = (cli)? en_cli_hwin : en_gui_hwin; } else { hwin = (cli)? cli_hwin : gui_hwin; } if (hwin == NULL) { hwin = helpwin(cli, en); if (hwin != NULL) { windata_t **phwin; if (en) { if (cli) { en_cli_hwin = hwin; phwin = &en_cli_hwin; } else { en_gui_hwin = hwin; phwin = &en_gui_hwin; } } else { if (cli) { cli_hwin = hwin; phwin = &cli_hwin; } else { gui_hwin = hwin; phwin = &gui_hwin; } } g_signal_connect(G_OBJECT(hwin->w), "destroy", G_CALLBACK(nullify_hwin), phwin); } } else { gdk_window_show(hwin->w->parent->window); gdk_window_raise(hwin->w->parent->window); } #if HDEBUG fprintf(stderr, "real_do_help: doing set_help_topic_buffer:\n" " hwin=%p, hcode=%d, pos=%d, en=%d\n", (void *) hwin, hcode, pos, en); #endif set_help_topic_buffer(hwin, hcode, pos, en); } /* called from main menu in gretl.c; also used as callback from command ref index in textbuf.c (gtk2 version only) */ void plain_text_cmdref (gpointer p, guint cmdnum, GtkWidget *w) { /* pos = 0 gives index of commands */ int pos = 0; int en = 0; int cli = 1; if (w == NULL && p != NULL) { en = GPOINTER_TO_INT(p); } #if HDEBUG fprintf(stderr, "plain_text_cmdref: p=%p, cmdnum=%d, w=%p\n", (void *) p, cmdnum, (void *) w); #endif if (cmdnum > 0) { pos = cli_pos_from_cmd(cmdnum, en); if (pos < 0 && !en && translated_helpfile == 1) { /* no translated entry: fall back on English */ en = 1; pos = cli_pos_from_cmd(cmdnum, en); } } real_do_help(cmdnum, pos, cli, en); } static void en_text_cmdref (gpointer p, guint u, GtkWidget *w) { real_do_help(0, 0, 1, 1); } gint edit_script_help (GtkWidget *widget, GdkEventButton *b, windata_t *vwin) { if (!window_help_is_active(vwin)) { /* command help not activated */ return FALSE; } else { gchar *text = NULL; int pos = -1; int hcode = 0; int en = 0; GtkTextBuffer *buf; GtkTextIter iter; buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(vwin->w)); gtk_text_buffer_get_iter_at_mark(buf, &iter, gtk_text_buffer_get_insert(buf)); if (gtk_text_iter_inside_word(&iter)) { GtkTextIter w_start, w_end; w_start = iter; w_end = iter; if (!gtk_text_iter_starts_word(&iter)) { gtk_text_iter_backward_word_start(&w_start); } if (!gtk_text_iter_ends_word(&iter)) { gtk_text_iter_forward_word_end(&w_end); } text = gtk_text_buffer_get_text(buf, &w_start, &w_end, FALSE); /* "coint2" command! */ if (text != NULL && !strcmp(text, "coint") && gtk_text_iter_forward_char(&w_end)) { gchar *s = gtk_text_buffer_get_text(buf, &w_start, &w_end, FALSE); if (s != NULL) { if (!strcmp(s, "coint2")) { g_free(text); text = s; } else { g_free(s); } } } } if (text != NULL && *text != '\0') { char word[9]; *word = '\0'; strncat(word, text, 8); hcode = gretl_command_number(word); pos = cli_pos_from_cmd(hcode, en); if (pos < 0 && translated_helpfile) { en = 1; pos = cli_pos_from_cmd(hcode, en); } } g_free(text); unset_window_help_active(vwin); text_set_cursor(vwin->w, 0); real_do_help(hcode, pos, 1, en); } return FALSE; } void menu_find (gpointer data, guint db, GtkWidget *widget) { if (db) { find_string_dialog(find_in_listbox, data); } else { find_string_dialog(find_in_text, data); } } void datafile_find (GtkWidget *widget, gpointer data) { find_string_dialog(find_in_listbox, data); } void find_var (gpointer p, guint u, GtkWidget *w) { find_string_dialog(find_in_listbox, mdata); } static gint close_find_dialog (GtkWidget *widget, gpointer data) { find_window = NULL; return FALSE; } static int look_for_string (const char *haystack, const char *needle, int start) { int hlen = strlen(haystack); int nlen = strlen(needle); int pos; for (pos = start; pos < hlen; pos++) { if (strncmp(&haystack[pos], needle, nlen) == 0) { return pos; } } return -1; } /* case-insensitive search in text buffer */ static gboolean real_find_in_text (GtkTextView *view, const gchar *s, gboolean from_cursor) { GtkTextBuffer *buf; GtkTextIter iter, start, end; GtkTextMark *vis; int found = 0; int wrapped = 0; int n = strlen(s); gchar *got; buf = gtk_text_view_get_buffer(view); text_search_wrap: if (from_cursor) { GtkTextIter sel_bound; gtk_text_buffer_get_iter_at_mark(buf, &iter, gtk_text_buffer_get_mark(buf, "insert")); gtk_text_buffer_get_iter_at_mark(buf, &sel_bound, gtk_text_buffer_get_mark(buf, "selection_bound")); gtk_text_iter_order(&sel_bound, &iter); } else { gtk_text_buffer_get_iter_at_offset(buf, &iter, 0); } start = end = iter; if (!gtk_text_iter_forward_chars(&end, n)) { return 0; } while (!found) { got = gtk_text_buffer_get_text(buf, &start, &end, FALSE); if (g_ascii_strcasecmp(got, s) == 0) { found = 1; } g_free(got); if (found || !gtk_text_iter_forward_char(&start) || !gtk_text_iter_forward_char(&end)) { break; } } if (found) { gtk_text_buffer_place_cursor(buf, &start); gtk_text_buffer_move_mark_by_name(buf, "selection_bound", &end); vis = gtk_text_buffer_create_mark(buf, "vis", &end, FALSE); gtk_text_view_scroll_to_mark(view, vis, 0.0, TRUE, 0.1, 0.0); } else if (from_cursor && !wrapped) { /* try wrapping */ from_cursor = FALSE; wrapped = 1; goto text_search_wrap; } if (found && wrapped) { infobox(_("Search wrapped")); } return found; } static void find_in_text (GtkWidget *widget, gpointer data) { windata_t *vwin = g_object_get_data(G_OBJECT(data), "windat"); gboolean found; needle = gtk_editable_get_chars(GTK_EDITABLE(find_entry), 0, -1); if (needle == NULL || *needle == '\0') { return; } found = real_find_in_text(GTK_TEXT_VIEW(vwin->w), needle, TRUE); if (!found) { infobox(_("String was not found.")); } } static void get_tree_model_haystack (GtkTreeModel *mod, GtkTreeIter *iter, int col, char *haystack) { gchar *tmp; gtk_tree_model_get(mod, iter, col, &tmp, -1); if (tmp != NULL) { strcpy(haystack, tmp); lower(haystack); g_free(tmp); } else { *haystack = '\0'; } } static void find_in_listbox (GtkWidget *w, gpointer p) { windata_t *win = g_object_get_data(G_OBJECT(p), "windat"); int minvar, wrapped = 0; char haystack[MAXLEN]; char pstr[16]; GtkTreeModel *model; GtkTreeIter iter; int found = -1; /* if searching in the main gretl window, start on line 1 */ minvar = (win == mdata)? 1 : 0; if (needle != NULL) { g_free(needle); needle = NULL; } needle = gtk_editable_get_chars(GTK_EDITABLE(find_entry), 0, -1); lower(needle); model = gtk_tree_view_get_model(GTK_TREE_VIEW(win->listbox)); /* if possible, try searching downward from the current line plus one; failing start, start from the top */ sprintf(pstr, "%d", win->active_var); if (!gtk_tree_model_get_iter_from_string(model, &iter, pstr) || !gtk_tree_model_iter_next(model, &iter)) { gtk_tree_model_get_iter_first(model, &iter); } search_wrap: while (found < 0) { /* try looking in column 1 first */ get_tree_model_haystack(model, &iter, 1, haystack); found = look_for_string(haystack, needle, 0); if (found < 0) { if (win == mdata) { /* then column 2 */ get_tree_model_haystack(model, &iter, 2, haystack); } else { /* then column 0 */ get_tree_model_haystack(model, &iter, 0, haystack); } found = look_for_string(haystack, needle, 0); } if (found >= 0 || !gtk_tree_model_iter_next(model, &iter)) { break; } } if (found < 0 && win->active_var > minvar && !wrapped) { /* try wrapping to start */ gtk_tree_model_get_iter_first(model, &iter); if (minvar > 0 && !gtk_tree_model_iter_next(model, &iter)) { ; /* do nothing: there's only one line in the box */ } else { wrapped = 1; goto search_wrap; } } if (found >= 0) { GtkTreePath *path = gtk_tree_model_get_path(model, &iter); gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(win->listbox), path, NULL, FALSE, 0, 0); gtk_tree_view_set_cursor(GTK_TREE_VIEW(win->listbox), path, NULL, FALSE); win->active_var = tree_path_get_row_number(path); gtk_tree_path_free(path); if (wrapped) { infobox(_("Search wrapped")); } } else { infobox(_("String was not found.")); } } static void cancel_find (GtkWidget *widget, gpointer data) { if (find_window != NULL) { gtk_widget_destroy(GTK_WIDGET(data)); find_window = NULL; } } static void parent_find (GtkWidget *finder, windata_t *caller) { GtkWidget *w = NULL; if (caller->dialog != NULL) { w = caller->dialog; } else if (caller->w != NULL) { w = caller->w; } if (w != NULL) { gtk_window_set_transient_for(GTK_WINDOW(finder), GTK_WINDOW(w)); gtk_window_set_destroy_with_parent(GTK_WINDOW(finder), TRUE); } } static void find_string_dialog (void (*findfunc)(), gpointer p) { windata_t *mydat = (windata_t *) p; GtkWidget *label; GtkWidget *button; GtkWidget *hbox; if (find_window != NULL) { g_object_set_data(G_OBJECT(find_window), "windat", mydat); parent_find(find_window, mydat); gdk_window_raise(find_window->window); return; } find_window = gretl_dialog_new(_("gretl: find"), NULL, 0); g_object_set_data(G_OBJECT(find_window), "windat", mydat); parent_find(find_window, mydat); g_signal_connect(G_OBJECT(find_window), "destroy", G_CALLBACK(close_find_dialog), find_window); hbox = gtk_hbox_new(TRUE, TRUE); label = gtk_label_new(_(" Find what:")); gtk_widget_show (label); find_entry = gtk_entry_new(); if (needle != NULL) { gtk_entry_set_text(GTK_ENTRY(find_entry), needle); gtk_editable_select_region(GTK_EDITABLE(find_entry), 0, -1); } g_signal_connect(G_OBJECT(find_entry), "activate", G_CALLBACK(findfunc), find_window); gtk_widget_show(find_entry); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), find_entry, TRUE, TRUE, 0); gtk_widget_show(hbox); gtk_box_pack_start(GTK_BOX (GTK_DIALOG(find_window)->vbox), hbox, TRUE, TRUE, 0); hbox = GTK_DIALOG(find_window)->action_area; /* cancel button */ button = cancel_button(hbox); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(cancel_find), find_window); gtk_widget_show(button); /* find button */ button = gtk_button_new_from_stock(GTK_STOCK_FIND); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_container_add(GTK_CONTAINER(hbox), button); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(findfunc), find_window); gtk_widget_grab_default(button); gtk_widget_show(button); gtk_widget_grab_focus(find_entry); gtk_widget_show(find_window); } void text_find_callback (GtkWidget *w, gpointer data) { find_string_dialog(find_in_text, data); } static GtkTooltips *gretl_tips; void gretl_tooltips_init (void) { gretl_tips = gtk_tooltips_new(); gtk_tooltips_enable(gretl_tips); /* redundant? */ } void gretl_tooltips_add (GtkWidget *w, const gchar *str) { gtk_tooltips_set_tip(gretl_tips, w, str, NULL); } enum { EN_LETTER, EN_A4, ITALIAN, SPANISH }; static int get_writable_path (char *path, const char *fname) { static int sysdoc_writable = -1; static int userdoc_writable = -1; FILE *fp; int err = 0; if (sysdoc_writable < 0) { sysdoc_writable = 0; sprintf(path, "%sdoc", paths.gretldir); if (gretl_mkdir(path) == 0) { sprintf(path, "%sdoc%c%s", paths.gretldir, SLASH, fname); fp = gretl_fopen(path, "w"); if (fp != NULL) { sysdoc_writable = 1; fclose(fp); remove(path); } } } if (!sysdoc_writable && userdoc_writable < 0) { userdoc_writable = 0; sprintf(path, "%sdoc", paths.userdir); if (gretl_mkdir(path) == 0) { sprintf(path, "%sdoc%c%s", paths.userdir, SLASH, fname); fp = gretl_fopen(path, "w"); if (fp != NULL) { userdoc_writable = 1; fclose(fp); remove(path); } } } if (!sysdoc_writable && !userdoc_writable) { err = 1; } return err; } static int find_or_download_pdf (int uguide, int i, char *fullpath) { const char *guide_files[] = { "gretl-guide.pdf", "gretl-guide-a4.pdf", "gretl-guide-it.pdf", "gretl-guide-es.pdf" }; const char *ref_files[] = { "gretl-ref.pdf", "gretl-ref-a4.pdf", "gretl-ref-it.pdf", "gretl-ref-es.pdf" }; const char *fname; FILE *fp; int err = 0; if (i < 0 || i > 3) { i = 0; } fname = (uguide)? guide_files[i] : ref_files[i]; /* is the file available in public dir? */ sprintf(fullpath, "%sdoc%c%s", paths.gretldir, SLASH, fname); fp = gretl_fopen(fullpath, "r"); if (fp != NULL) { fclose(fp); return 0; } /* or maybe in user dir? */ sprintf(fullpath, "%sdoc%c%s", paths.userdir, SLASH, fname); fp = gretl_fopen(fullpath, "r"); if (fp != NULL) { fclose(fp); return 0; } /* check for download location */ err = get_writable_path(fullpath, fname); /* do actual download */ if (!err) { err = retrieve_manfile(fname, fullpath); } if (err) { const char *buf = gretl_errmsg_get(); if (*buf) { errbox(buf); } else { errbox(_("Failed to download file")); } } return err; } void display_pdf_help (gpointer p, guint uguide, GtkWidget *w) { char fname[FILENAME_MAX]; int pref, err = 0; pref = get_manpref(); err = find_or_download_pdf(uguide, pref, fname); if (err) { return; } #if defined(G_OS_WIN32) win32_open_file(fname); #elif defined(OSX_BUILD) osx_open_file(fname); #else gretl_fork(viewpdf, fname); #endif }