1 /*
2  *  gretl -- Gnu Regression, Econometrics and Time-series Library
3  *  Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "gretl.h"
21 #include "var.h"
22 #include "johansen.h"
23 #include "varprint.h"
24 #include "forecast.h"
25 #include "objstack.h"
26 #include "gretl_xml.h"
27 #include "gretl_func.h"
28 #include "system.h"
29 #include "matrix_extra.h"
30 #include "bootstrap.h"
31 #include "gretl_foreign.h"
32 #include "gretl_typemap.h"
33 #include "uservar.h"
34 #include "gretl_string_table.h"
35 #include "gretl_panel.h"
36 #include "csvdata.h"
37 #include "kalman.h"
38 #include "libset.h"
39 
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <errno.h>
43 
44 #include "model_table.h"
45 #include "series_view.h"
46 #include "session.h"
47 #include "textbuf.h"
48 #include "textutil.h"
49 #include "cmdstack.h"
50 #include "filelists.h"
51 #include "menustate.h"
52 #include "dlgutils.h"
53 #include "ssheet.h"
54 #include "datafiles.h"
55 #include "gpt_control.h"
56 #include "fileselect.h"
57 #include "toolbar.h"
58 #include "winstack.h"
59 #include "fnsave.h"
60 #include "datawiz.h"
61 #include "selector.h"
62 #include "guiprint.h"
63 #include "fncall.h"
64 #include "tabwin.h"
65 #include "join-gui.h"
66 #include "gretl_ipc.h"
67 
68 #ifdef G_OS_WIN32
69 # include <windows.h>
70 # include "gretlwin32.h"
71 #endif
72 
73 static void set_up_model_view_menu (windata_t *vwin);
74 static void add_system_menu_items (windata_t *vwin, int role);
75 static void add_x12_output_menu_item (windata_t *vwin);
76 static gint check_model_menu (GtkWidget *w, GdkEventButton *eb,
77 			      gpointer data);
78 static gint check_VAR_menu (GtkWidget *w, GdkEventButton *eb,
79 			    gpointer data);
80 static void model_copy_callback (GtkAction *action, gpointer p);
81 static int set_sample_from_model (void *ptr, int role);
82 static gboolean maybe_set_sample_from_model (windata_t *vwin);
83 
close_model(GtkAction * action,gpointer data)84 static void close_model (GtkAction *action, gpointer data)
85 {
86     windata_t *vwin = (windata_t *) data;
87 
88     gretl_viewer_destroy(vwin);
89 }
90 
arma_by_x12a(const MODEL * pmod)91 static int arma_by_x12a (const MODEL *pmod)
92 {
93     int ret = 0;
94 
95     if (pmod->ci == ARMA) {
96 	int acode = gretl_model_get_int(pmod, "arma_flags");
97 
98 	if (acode & ARMA_X12A) {
99 	    ret = 1;
100 	}
101     }
102 
103     return ret;
104 }
105 
latex_is_ok(void)106 int latex_is_ok (void)
107 {
108     static int latex_ok = -1;
109 
110     if (latex_ok == -1) {
111 	latex_ok = check_for_program(latex);
112     }
113 
114     return latex_ok;
115 }
116 
model_output_save(GtkAction * action,gpointer p)117 static void model_output_save (GtkAction *action, gpointer p)
118 {
119     copy_format_dialog((windata_t *) p, W_SAVE);
120 }
121 
122 static gretlopt tex_eqn_opt;
123 
set_tex_eqn_opt(GtkRadioAction * action)124 static void set_tex_eqn_opt (GtkRadioAction *action)
125 {
126     int v = gtk_radio_action_get_current_value(action);
127 
128     tex_eqn_opt = (v)? OPT_T : OPT_NONE;
129 }
130 
get_tex_eqn_opt(void)131 gretlopt get_tex_eqn_opt (void)
132 {
133     return tex_eqn_opt;
134 }
135 
model_get_t1_t2(void * ptr,int role,int * t1,int * t2)136 static int model_get_t1_t2 (void *ptr, int role, int *t1, int *t2)
137 {
138     int err = 0;
139 
140     if (role == VIEW_MODEL) {
141 	MODEL *pmod = ptr;
142 
143 	*t1 = pmod->smpl.t1;
144 	*t2 = pmod->smpl.t2;
145     } else if (role == VAR || role == VECM) {
146 	GRETL_VAR *var = ptr;
147 
148 	err = gretl_var_get_sample(var, t1, t2);
149     } else if (role == SYSTEM) {
150 	equation_system *sys = ptr;
151 
152 	err = gretl_system_get_sample(sys, t1, t2);
153     }
154 
155     return err;
156 }
157 
158 /* Called from menu in model window, but not necessarily
159    a single-equation model */
160 
model_revise_callback(GtkAction * action,gpointer p)161 static void model_revise_callback (GtkAction *action, gpointer p)
162 {
163     windata_t *vwin = (windata_t *) p;
164     int ok = 1, t1 = 0, t2 = 0;
165     int err = 0;
166 
167     if (vwin->role == VIEW_MODEL) {
168 	MODEL *pmod = vwin->data;
169 
170 	err = model_sample_problem(pmod, dataset);
171     }
172 
173     if (!err) {
174 	err = model_get_t1_t2(vwin->data, vwin->role, &t1, &t2);
175     }
176 
177     if (!err && (t1 != dataset->t1 || t2 != dataset->t2)) {
178 	ok = maybe_set_sample_from_model(vwin);
179     }
180 
181     if (ok) {
182 	selector_from_model(vwin);
183     }
184 }
185 
gretl_window_title(const char * s)186 gchar *gretl_window_title (const char *s)
187 {
188     if (s != NULL) {
189 	return g_strdup_printf("gretl: %s", s);
190     } else {
191 	return g_strdup("gretl: untitled");
192     }
193 }
194 
text_eqn_callback(GtkAction * action,gpointer p)195 static void text_eqn_callback (GtkAction *action, gpointer p)
196 {
197     windata_t *vwin = (windata_t *) p;
198     MODEL *pmod = vwin->data;
199     PRN *prn;
200     int err;
201 
202     if (bufopen(&prn)) {
203 	return;
204     }
205 
206     err = text_print_equation(pmod, dataset, OPT_NONE, prn);
207 
208     if (err) {
209 	gui_errmsg(err);
210     } else {
211 	gchar *title = gretl_window_title(_("equation"));
212 
213 	view_buffer_with_parent(vwin, prn, 78, 200, title, PRINT, NULL);
214 	g_free(title);
215     }
216 }
217 
218 static GtkActionEntry model_items[] = {
219     { "File", NULL, N_("_File"), NULL, NULL, NULL },
220     { "SaveAs", GTK_STOCK_SAVE_AS, N_("_Save as..."), NULL, NULL, G_CALLBACK(model_output_save) },
221     { "SaveAsIcon", NULL, N_("Save to session as _icon"), NULL, NULL, G_CALLBACK(model_add_as_icon) },
222     { "SaveAndClose", NULL, N_("Save as icon and cl_ose"), NULL, NULL, G_CALLBACK(model_add_as_icon) },
223     { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, NULL, G_CALLBACK(window_print) },
224     { "TextEqn", NULL, N_("View as equation"), NULL, NULL, G_CALLBACK(text_eqn_callback) },
225     { "Close", GTK_STOCK_CLOSE, N_("_Close"), NULL, NULL, G_CALLBACK(close_model) },
226     { "Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
227     { "Copy", GTK_STOCK_COPY, N_("_Copy"), NULL, NULL, G_CALLBACK(model_copy_callback) },
228     { "Revise", GTK_STOCK_EDIT, N_("_Modify model..."), NULL, NULL,
229       G_CALLBACK(model_revise_callback) },
230 #if 0
231     { "Restore", NULL, N_("_Restore model sample"), NULL, NULL, G_CALLBACK(model_sample_callback) },
232 #endif
233     { "Tests", NULL, N_("_Tests"), NULL, NULL, NULL },
234     { "Save", NULL, N_("_Save"), NULL, NULL, NULL },
235     { "Graphs", NULL, N_("_Graphs"), NULL, NULL, NULL },
236     { "ResidPlot", NULL, N_("_Residual plot"), NULL, NULL, NULL },
237     { "FittedActualPlot", NULL, N_("_Fitted, actual plot"), NULL, NULL, NULL },
238     { "Analysis", NULL, N_("_Analysis"), NULL, NULL, NULL },
239     { "DisplayAFR", NULL, N_("_Display actual, fitted, residual"), NULL, NULL,
240       G_CALLBACK(display_fit_resid) },
241     { "Forecasts", NULL, N_("_Forecasts..."), NULL, NULL, G_CALLBACK(gui_do_forecast) },
242     { "ConfIntervals", NULL, N_("_Confidence intervals for coefficients"), NULL, NULL,
243       G_CALLBACK(do_coeff_intervals) },
244     { "ConfEllipse", NULL, N_("Confidence _ellipse..."), NULL, NULL, G_CALLBACK(selector_callback) },
245     { "Covariance", NULL, N_("Coefficient covariance _matrix"), NULL, NULL, G_CALLBACK(do_outcovmx) },
246     { "Collinearity", NULL, N_("_Collinearity"), NULL, NULL, G_CALLBACK(do_collin) },
247     { "Leverage", NULL, N_("_Influential observations"), NULL, NULL, G_CALLBACK(do_leverage) },
248     { "ANOVA", NULL, N_("_ANOVA"), NULL, NULL, G_CALLBACK(do_anova) },
249     { "Bootstrap", NULL, N_("_Bootstrap..."), NULL, NULL, G_CALLBACK(do_bootstrap) }
250 };
251 
252 static GtkActionEntry model_test_items[] = {
253     { "omit", NULL, N_("_Omit variables"), NULL, NULL, G_CALLBACK(selector_callback) },
254     { "add", NULL, N_("_Add variables"), NULL, NULL, G_CALLBACK(selector_callback) },
255     { "coeffsum", NULL, N_("_Sum of coefficients"), NULL, NULL, G_CALLBACK(selector_callback) },
256     { "restrict", NULL, N_("_Linear restrictions"), NULL, NULL, G_CALLBACK(gretl_callback) },
257     { "modtest:s", NULL, N_("Non-linearity (s_quares)"), NULL, NULL, G_CALLBACK(do_modtest) },
258     { "modtest:l", NULL, N_("Non-linearity (_logs)"), NULL, NULL, G_CALLBACK(do_modtest) },
259     { "reset", NULL, N_("_Ramsey's RESET"), NULL, NULL, G_CALLBACK(do_reset) },
260     { "Hsk", NULL, N_("_Heteroskedasticity"), NULL, NULL, NULL },
261     { "modtest:n", NULL, N_("_Normality of residual"), NULL, NULL, G_CALLBACK(do_resid_freq) },
262     { "chow", NULL, N_("_Chow test"), NULL, NULL, G_CALLBACK(do_chow_cusum) },
263     { "modtest:a", NULL, N_("_Autocorrelation"), NULL, NULL, G_CALLBACK(do_autocorr) },
264     { "dwpval", NULL, N_("_Durbin-Watson p-value"), NULL, NULL, G_CALLBACK(do_dwpval) },
265     { "modtest:h", NULL, N_("A_RCH"), NULL, NULL, G_CALLBACK(do_arch) },
266     { "bds", NULL, N_("Non-linearity (_BDS)"), NULL, NULL, G_CALLBACK(do_resid_freq) },
267     { "qlrtest", NULL, N_("_QLR test"), NULL, NULL, G_CALLBACK(do_chow_cusum) },
268     { "cusum", NULL, N_("_CUSUM test"), NULL, NULL, G_CALLBACK(do_chow_cusum) },
269     { "cusum:r", NULL, N_("CUSUM_SQ test"), NULL, NULL, G_CALLBACK(do_chow_cusum) },
270     { "modtest:c", NULL, N_("_Common factor"), NULL, NULL, G_CALLBACK(do_modtest) },
271     { "modtest:d", NULL, N_("_Cross-sectional dependence"), NULL, NULL, G_CALLBACK(do_modtest) },
272     { "panspec", NULL, N_("_Panel specification"), NULL, NULL, G_CALLBACK(do_panel_tests) }
273 };
274 
275 static GtkActionEntry base_hsk_items[] = {
276     { "White", NULL, N_("White's test"), NULL, NULL, G_CALLBACK(do_modtest) },
277     { "WhiteSquares", NULL, N_("White's test (squares only)"), NULL, NULL, G_CALLBACK(do_modtest) },
278     { "BreuschPagan", NULL, "Breusch-Pagan", NULL, NULL, G_CALLBACK(do_modtest) },
279     { "Koenker", NULL, "Koenker", NULL, NULL, G_CALLBACK(do_modtest) }
280 };
281 
282 static GtkActionEntry panel_hsk_items[] = {
283     { "White", NULL, N_("White's test"), NULL, NULL, G_CALLBACK(do_modtest) },
284     { "Groupwise", NULL, N_("_groupwise"), NULL, NULL, G_CALLBACK(do_modtest) }
285 };
286 
287 static GtkActionEntry ivreg_hsk_items[] = {
288     { "White", NULL, N_("Pesaran-Taylor test"), NULL, NULL, G_CALLBACK(do_modtest) }
289 };
290 
291 const gchar *model_tex_ui =
292     "<ui>"
293     "  <menubar>"
294     "    <menu action='LaTeX'>"
295     "      <menu action='TeXView'>"
296     "        <menuitem action='TabView'/>"
297     "        <menuitem action='EqnView'/>"
298     "      </menu>"
299     "      <menu action='TeXCopy'>"
300     "        <menuitem action='TabCopy'/>"
301     "        <menuitem action='EqnCopy'/>"
302     "      </menu>"
303     "      <menu action='TeXSave'>"
304     "        <menuitem action='TabSave'/>"
305     "        <menuitem action='EqnSave'/>"
306     "      </menu>"
307     "      <menu action='EqnOpts'>"
308     "        <menuitem action='TeXstderrs'/>"
309     "        <menuitem action='TeXtratios'/>"
310     "      </menu>"
311     "      <menuitem action='TabOpts'/>"
312     "    </menu>"
313     "  </menubar>"
314     "</ui>";
315 
316 const gchar *missing_tex_ui =
317     "<ui>"
318     "  <menubar>"
319     "    <menu action='LaTeX'>"
320     "      <menuitem action='notex'/>"
321     "    </menu>"
322     "  </menubar>"
323     "</ui>";
324 
325 static GtkActionEntry model_tex_items[] = {
326     { "LaTeX",   NULL, N_("_LaTeX"), NULL, NULL, NULL },
327     { "TeXView", NULL, N_("_View"), NULL, NULL, NULL },
328     { "TabView", NULL, N_("_Tabular"), NULL, NULL, G_CALLBACK(model_tex_view) },
329     { "EqnView", NULL, N_("_Equation"), NULL, NULL, G_CALLBACK(model_tex_view) },
330     { "TeXCopy", NULL, N_("_Copy"), NULL, NULL, NULL },
331     { "TabCopy", NULL, N_("_Tabular"), NULL, NULL, G_CALLBACK(model_tex_copy) },
332     { "EqnCopy", NULL, N_("_Equation"), NULL, NULL, G_CALLBACK(model_tex_copy) },
333     { "TeXSave", NULL, N_("_Save"), NULL, NULL, NULL },
334     { "TabSave", NULL, N_("_Tabular"), NULL, NULL, G_CALLBACK(model_tex_save) },
335     { "EqnSave", NULL, N_("_Equation"), NULL, NULL, G_CALLBACK(model_tex_save) },
336     { "EqnOpts", NULL, N_("_Equation options"), NULL, NULL, NULL },
337     { "TabOpts", NULL, N_("_Tabular options..."), NULL, NULL, G_CALLBACK(tex_format_dialog) }
338 };
339 
340 static GtkRadioActionEntry tex_eqn_items[] = {
341     { "TeXstderrs", NULL, N_("Show _standard errors"), NULL, NULL, 0 },
342     { "TeXtratios", NULL, N_("Show _t-ratios"), NULL, NULL, 1 },
343 };
344 
345 static GtkActionEntry missing_tex_items[] = {
346     { "LaTeX", NULL, N_("_LaTeX"), NULL, NULL, NULL },
347     { "notex", NULL, "No TeX", NULL, NULL, G_CALLBACK(dummy_call) }
348 };
349 
350 static GtkActionEntry system_items[] = {
351     { "File", NULL, N_("_File"), NULL, NULL, NULL },
352     { "SaveAs", GTK_STOCK_SAVE_AS, N_("_Save as..."), NULL, NULL, G_CALLBACK(model_output_save) },
353     { "SaveAsIcon", NULL, N_("Save to session as _icon"), NULL, NULL, G_CALLBACK(model_add_as_icon) },
354     { "SaveAndClose", NULL, N_("Save as icon and cl_ose"), NULL, NULL, G_CALLBACK(model_add_as_icon) },
355     { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, NULL, G_CALLBACK(window_print) },
356     { "Close", GTK_STOCK_CLOSE, N_("_Close"), NULL, NULL, G_CALLBACK(close_model) },
357     { "Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
358     { "Copy", GTK_STOCK_COPY, N_("_Copy"), NULL, NULL, G_CALLBACK(model_copy_callback) },
359     { "Revise", GTK_STOCK_EDIT, N_("_Revise specification..."), NULL, NULL,
360       G_CALLBACK(model_revise_callback) },
361     { "Save", NULL, N_("_Save"), NULL, NULL, NULL },
362     { "Tests", NULL, N_("_Tests"), NULL, NULL, NULL },
363     { "Graphs", NULL, N_("_Graphs"), NULL, NULL, NULL },
364     { "Analysis", NULL, N_("_Analysis"), NULL, NULL, NULL },
365     { "Forecasts", NULL, N_("_Forecasts"), NULL, NULL, NULL },
366 };
367 
368 static gint n_system_items = G_N_ELEMENTS(system_items);
369 
370 static GtkActionEntry sys_tex_items[] = {
371     { "LaTeX",   NULL, N_("_LaTeX"), NULL, NULL, NULL },
372     { "TeXView", NULL, N_("_View"),  NULL, NULL, G_CALLBACK(model_tex_view) },
373     { "TeXCopy", NULL, N_("_Copy"),  NULL, NULL, G_CALLBACK(model_tex_copy) },
374     { "TeXSave", NULL, N_("_Save"),  NULL, NULL, G_CALLBACK(model_tex_save) },
375 };
376 
377 static const gchar *sys_ui =
378     "<ui>"
379     "  <menubar>"
380     "    <menu action='File'>"
381     "      <menuitem action='SaveAs'/>"
382     "      <menuitem action='SaveAsIcon'/>"
383     "      <menuitem action='SaveAndClose'/>"
384     "      <menuitem action='Print'/>"
385     "      <menuitem action='Close'/>"
386     "    </menu>"
387     "    <menu action='Edit'>"
388     "      <menuitem action='Copy'/>"
389     "      <menuitem action='Revise'/>"
390     "    </menu>"
391     "    <menu action='Tests'/>"
392     "    <menu action='Save'/>"
393     "    <menu action='Graphs'/>"
394     "    <menu action='Analysis'>"
395     "      <menu action='Forecasts'/>"
396     "    </menu>"
397     "  </menubar>"
398     "</ui>";
399 
model_copy_callback(GtkAction * action,gpointer p)400 static void model_copy_callback (GtkAction *action, gpointer p)
401 {
402     copy_format_dialog((windata_t *) p, W_COPY);
403 }
404 
copyfile(const char * src,const char * dest)405 int copyfile (const char *src, const char *dest)
406 {
407     FILE *srcfd, *destfd;
408     char buf[GRETL_BUFSIZE];
409     size_t n;
410 
411     if (!strcmp(src, dest)) {
412 	return 0;
413     }
414 
415     if ((srcfd = gretl_fopen(src, "rb")) == NULL) {
416 	file_read_errbox(src);
417 	return E_FOPEN;
418     }
419 
420     if ((destfd = gretl_fopen(dest, "wb")) == NULL) {
421 	file_write_errbox(dest);
422 	fclose(srcfd);
423 	return E_FOPEN;
424     }
425 
426     while ((n = fread(buf, 1, sizeof buf, srcfd)) > 0) {
427 	fwrite(buf, 1, n, destfd);
428     }
429 
430     fclose(srcfd);
431     fclose(destfd);
432 
433     return 0;
434 }
435 
gretl_tempfile_open(char * fname)436 FILE *gretl_tempfile_open (char *fname)
437 {
438     FILE *fp;
439 
440     strcat(fname, ".XXXXXX");
441     fp = gretl_mktemp(fname, "w+");
442 
443     if (fp == NULL) {
444 	errbox(_("Couldn't open temp file"));
445     }
446 
447     return fp;
448 }
449 
delete_file(GtkWidget * widget,char * fname)450 static void delete_file (GtkWidget *widget, char *fname)
451 {
452     gretl_remove(fname);
453     g_free(fname);
454 }
455 
delete_widget(GtkWidget * widget,gpointer data)456 void delete_widget (GtkWidget *widget, gpointer data)
457 {
458     gtk_widget_destroy(GTK_WIDGET(data));
459 }
460 
set_wait_cursor(GdkWindow ** pcwin)461 void set_wait_cursor (GdkWindow **pcwin)
462 {
463     GdkDisplay *disp = gdk_display_get_default();
464     GdkWindow *w;
465 
466     if (*pcwin == NULL) {
467 	gint x, y;
468 
469 	*pcwin = w = gdk_display_get_window_at_pointer(disp, &x, &y);
470     } else {
471 	w = *pcwin;
472     }
473 
474     if (w != NULL) {
475 	GdkCursor *cursor = gdk_cursor_new(GDK_WATCH);
476 
477 	if (cursor != NULL) {
478 	    gdk_window_set_cursor(w, cursor);
479 	    gdk_display_sync(disp);
480 	    gdk_cursor_unref(cursor);
481 	}
482     }
483 }
484 
unset_wait_cursor(GdkWindow * cwin)485 void unset_wait_cursor (GdkWindow *cwin)
486 {
487     if (cwin != NULL) {
488 	gdk_window_set_cursor(cwin, NULL);
489     }
490 }
491 
not_space(gunichar c,gpointer p)492 static gboolean not_space (gunichar c, gpointer p)
493 {
494     return !g_unichar_isspace(c);
495 }
496 
vwin_subselection_present(windata_t * vwin)497 int vwin_subselection_present (windata_t *vwin)
498 {
499     GtkTextIter selstart, selend;
500     GtkTextBuffer *buf;
501     int ret = 0;
502 
503     buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(vwin->text));
504 
505     if (gtk_text_buffer_get_selection_bounds(buf, &selstart, &selend)) {
506 	GtkTextIter start, end;
507 
508 	gtk_text_buffer_get_bounds(buf, &start, &end);
509 	if (gtk_text_iter_equal(&selstart, &start) &&
510 	    gtk_text_iter_equal(&selend, &end)) {
511 	    ret = 0;
512 	} else {
513 	    gtk_text_iter_forward_find_char(&start, not_space,
514 					    NULL, &selstart);
515 	    gtk_text_iter_backward_find_char(&end, not_space,
516 					     NULL, &selend);
517 	    if (!gtk_text_iter_equal(&selstart, &start) ||
518 		!gtk_text_iter_equal(&selend, &end)) {
519 		ret = 1;
520 	    }
521 	}
522     }
523 
524     return ret;
525 }
526 
vwin_is_editing(windata_t * vwin)527 int vwin_is_editing (windata_t *vwin)
528 {
529     if (vwin != NULL && vwin->text != NULL) {
530 	return gtk_text_view_get_editable(GTK_TEXT_VIEW(vwin->text));
531     } else {
532 	return 0;
533     }
534 }
535 
vwin_copy_callback(GtkWidget * w,windata_t * vwin)536 gboolean vwin_copy_callback (GtkWidget *w, windata_t *vwin)
537 {
538     if (vwin_subselection_present(vwin)) {
539 	window_copy(vwin, GRETL_FORMAT_SELECTION);
540     } else if (vwin_is_editing(vwin)) {
541 	window_copy(vwin, GRETL_FORMAT_TXT);
542     } else {
543 	copy_format_dialog(vwin, W_COPY);
544     }
545 
546     return TRUE;
547 }
548 
numeric_keyval(guint key)549 static int numeric_keyval (guint key)
550 {
551     if (key >= GDK_1 && key <= GDK_9) {
552 	return key - GDK_0;
553     } else if (key >= GDK_KP_1 && key <= GDK_KP_9) {
554 	return key - GDK_KP_0;
555     } else {
556 	return 0;
557     }
558 }
559 
560 #define nav_key(k) (k==GDK_Up || k==GDK_Down || \
561 		    k==GDK_Page_Up || k==GDK_Page_Down || \
562 		    k==GDK_End || k==GDK_Begin || k==GDK_Home)
563 
jump_to_finder(guint keyval,windata_t * vwin)564 static gint jump_to_finder (guint keyval, windata_t *vwin)
565 {
566     if (!nav_key(keyval)) {
567 	gchar *letter = gdk_keyval_name(keyval);
568 
569 	if (letter != NULL) {
570 	    /* snap to search box */
571 	    gtk_widget_grab_focus(vwin->finder);
572 	    gtk_entry_set_text(GTK_ENTRY(vwin->finder), letter);
573 	    gtk_editable_set_position(GTK_EDITABLE(vwin->finder), -1);
574 	    return TRUE; /* handled */
575 	}
576     }
577 
578     return FALSE;
579 }
580 
vwin_select_all(windata_t * vwin)581 static void vwin_select_all (windata_t *vwin)
582 {
583     if (vwin != NULL && vwin->text != NULL) {
584 	GtkTextBuffer *tbuf;
585 
586 	tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(vwin->text));
587 
588 	if (tbuf != NULL) {
589 	    GtkTextIter start, end;
590 
591 	    gtk_text_buffer_get_start_iter(tbuf, &start);
592 	    gtk_text_buffer_get_end_iter(tbuf, &end);
593 	    gtk_text_buffer_select_range(tbuf, &start, &end);
594 	}
595     }
596 }
597 
598 /* GDK_KEY_A 0x041 .. GDK_KEY_Z 0x05a
599    GDK_KEY_a 0x061 .. GDK_KEY_z 0x07a
600 */
601 
602 struct greek_map {
603     guint key; /* Latin letter key */
604     guint grk; /* "corresponding" Greek letter */
605 };
606 
607 static struct greek_map greek_keys[] = {
608     { GDK_A, 0x91 }, /* alpha */
609     { GDK_B, 0x92 }, /* beta */
610     { GDK_C, 0xa7 }, /* chi */
611     { GDK_D, 0x94 }, /* delta */
612     { GDK_E, 0x95 }, /* epsilon */
613     { GDK_F, 0xa6 }, /* phi */
614     { GDK_G, 0x93 }, /* gamma */
615     { GDK_H, 0x97 }, /* eta */
616     { GDK_I, 0x99 }, /* iota */
617     { GDK_J, 0xa8 }, /* psi */
618     { GDK_K, 0x9a }, /* kappa */
619     { GDK_L, 0x9b }, /* lambda */
620     { GDK_M, 0x9c }, /* mu */
621     { GDK_N, 0x9d }, /* nu */
622     { GDK_O, 0x9f }, /* omicron */
623     { GDK_P, 0xa0 }, /* pi */
624     { GDK_Q, 0x98 }, /* theta */
625     { GDK_R, 0xa1 }, /* rho */
626     { GDK_S, 0xa3 }, /* sigma */
627     { GDK_T, 0xa4 }, /* tau */
628     { GDK_U, 0xa5 }, /* upsilon */
629     { GDK_V, 0x9d }, /* nu (again) */
630     { GDK_W, 0xa9 }, /* omega */
631     { GDK_X, 0x9e }, /* xi */
632     { GDK_Y, 0xa5 }, /* upsilon (again) */
633     { GDK_Z, 0x96 }  /* zeta */
634 };
635 
636 /* Note: exclude Greek capital letters that are indistinguishable from
637    Latin caps.
638 */
639 
640 #define ok_greek_cap(k) (k == GDK_D || k == GDK_F || k == GDK_G || \
641 			 k == GDK_J || k == GDK_L || k == GDK_P || \
642 			 k == GDK_Q || k == GDK_S || k == GDK_U || \
643 			 k == GDK_W || k == GDK_X || k == GDK_Y)
644 
maybe_insert_greek(guint key,windata_t * vwin)645 static int maybe_insert_greek (guint key, windata_t *vwin)
646 {
647     guint lc = 0, ukey = 0;
648 
649     if (key >= GDK_a && key <= GDK_z) {
650 	ukey = gdk_keyval_to_upper(key);
651 	lc = 1;
652     } else if (key >= GDK_A && key <= GDK_Z) {
653 	if (ok_greek_cap(key)) {
654 	    ukey = key;
655 	} else {
656 	    /* insert the look-alike? */
657 	    textview_insert_text(vwin->text, gdk_keyval_name(key));
658 	    return 1;
659 	}
660     }
661 
662     if (ukey > 0) {
663 	int i, n = G_N_ELEMENTS(greek_keys);
664 	unsigned char g, ins[3] = {0};
665 
666 	for (i=0; i<n; i++) {
667 	    if (ukey == greek_keys[i].key) {
668 		g = greek_keys[i].grk;
669 		if (lc) {
670 		    ins[0] = g > 0x9f ? 0xCF : 0xCE;
671 		    ins[1] = g > 0x9f ? g - 0x20 : g + 0x20;
672 		} else {
673 		    ins[0] = 0xCE;
674 		    ins[1] = g;
675 		}
676 		textview_insert_text(vwin->text, (char *) ins);
677 		return 1;
678 	    }
679 	}
680     }
681 
682     return 0;
683 }
684 
685 /* Signal attached to editor/viewer windows. Note that @w is
686    generally the top-level GtkWidget vwin->main; exceptions
687    are (a) tabbed windows, where @w is the embedding window,
688    and (b) help windows, where @w is the text area.
689 */
690 
catch_viewer_key(GtkWidget * w,GdkEventKey * event,windata_t * vwin)691 gint catch_viewer_key (GtkWidget *w, GdkEventKey *event,
692 		       windata_t *vwin)
693 {
694     int Ctrl = (event->state & GDK_CONTROL_MASK);
695     int Alt = (event->state & GDK_MOD1_MASK);
696     guint upkey = event->keyval;
697     int editing = vwin_is_editing(vwin);
698     int console = vwin->role == CONSOLE;
699 
700     if (vwin_is_busy(vwin)) {
701 	return TRUE;
702     }
703 
704 #if 0
705     fprintf(stderr, "HERE catch_viewer_key\n"
706 	    " editing=%d, console=%d, Ctrl=%d, Alt=%d, key=%s\n",
707 	    editing, console, Ctrl, Alt, gdk_keyval_name(upkey));
708 #endif
709 
710     if (editing && Alt && !Ctrl) {
711 	/* "Alt" specials for editor */
712 	if (maybe_insert_greek(upkey, vwin)) {
713 	    return TRUE;
714 	} else if (upkey == GDK_minus) {
715 	    textview_insert_text(vwin->text, "~");
716 	    return TRUE;
717 	}
718     }
719 
720     if (is_control_key(event->keyval)) {
721 	return FALSE;
722     }
723 
724     if (!gdk_keyval_is_upper(event->keyval)) {
725 	upkey = gdk_keyval_to_upper(event->keyval);
726     }
727 
728 #ifdef OS_OSX
729     if (!Ctrl && cmd_key(event)) {
730 	/* treat Command as Ctrl */
731 	Ctrl = 1;
732     }
733 #endif
734 
735     if (Ctrl && !Alt) {
736 	if (upkey == GDK_F) {
737 	    text_find(NULL, vwin);
738 	    return TRUE;
739 	} else if (upkey == GDK_G) {
740 	    text_find_again(NULL, vwin);
741 	    return TRUE;
742 	} else if (upkey == GDK_C) {
743 	    /* Ctrl-C: copy */
744 	    return vwin_copy_callback(NULL, vwin);
745 	} else if (editing && !console) {
746 	    /* note that the standard Ctrl-key sequences for editing
747 	       are handled by GTK, so we only need to put our own
748 	       "specials" here
749 	    */
750 	    if (upkey == GDK_H) {
751 		text_replace(NULL, vwin);
752 		return TRUE;
753 	    } else if (upkey == GDK_S) {
754 		/* Ctrl-S: save */
755 		vwin_save_callback(NULL, vwin);
756 		return TRUE;
757 	    } else if (upkey == GDK_Q || upkey == GDK_W) {
758 		if (!window_is_tab(vwin)) {
759 		    /* Ctrl-Q or Ctrl-W, quit: but not for tabbed windows */
760 		    if (vwin_content_changed(vwin)) {
761 			/* conditional: we have unsaved changes */
762 			if (query_save_text(NULL, NULL, vwin) == FALSE) {
763 			    gtk_widget_destroy(w);
764 			}
765 		    } else {
766 			/* unconditional */
767 			gtk_widget_destroy(w);
768 		    }
769 		    return TRUE;
770 		}
771 	    } else if (upkey == GDK_T && window_is_tab(vwin)) {
772 		/* Ctrl-T: open new tab */
773 		do_new_script(vwin->role, NULL);
774 		return TRUE;
775 	    }
776 	}
777 	if (window_is_tab(vwin)) {
778 	    /* note: still conditional on Ctrl */
779 	    if (upkey == GDK_greater || upkey == GDK_less ||
780 		upkey == GDK_Page_Up || upkey == GDK_Page_Down) {
781 		tabwin_navigate(vwin, upkey);
782 		return TRUE;
783 	    }
784 	} else if (upkey == GDK_Q || upkey == GDK_W) {
785 	    gtk_widget_destroy(vwin->main);
786 	    return TRUE;
787 	}
788     } else if (Alt && !console) {
789 	if (upkey == GDK_C && vwin->role == SCRIPT_OUT) {
790 	    cascade_session_windows();
791 	    return TRUE;
792 	} else if (window_is_tab(vwin)) {
793 	    int k = numeric_keyval(upkey);
794 
795 	    if (k > 0) {
796 		tabwin_navigate(vwin, k);
797 		return TRUE;
798 	    }
799 	}
800     }
801 
802     if (editing || (vwin->finder != NULL && gtk_widget_has_focus(vwin->finder))) {
803 	/* we set up "special" responses to some plain keystrokes
804 	   below: this won't do if we're in editing/typing mode
805 	*/
806 	return FALSE;
807     }
808 
809     if (!event->state && vwin->finder != NULL && GTK_IS_ENTRY(vwin->finder)) {
810 	if (jump_to_finder(event->keyval, vwin)) {
811 	    /* FIXME is this really wanted? */
812 	    return TRUE;
813 	}
814     }
815 
816     if (!Alt) {
817 	if (upkey == GDK_A && Ctrl) {
818 	    vwin_select_all(vwin);
819 	    return TRUE;
820 	} else if (upkey == GDK_Q || (upkey == GDK_W && Ctrl)) {
821 	    if (w == vwin->main) {
822 		gtk_widget_destroy(w);
823 	    }
824 	} else if (upkey == GDK_S && data_status && vwin->role == VIEW_MODEL) {
825 	    model_add_as_icon(NULL, vwin);
826 	}
827     }
828 
829     return FALSE;
830 }
831 
nomem(void)832 void nomem (void)
833 {
834     errbox(_("Out of memory!"));
835 }
836 
mymalloc(size_t size)837 void *mymalloc (size_t size)
838 {
839     void *mem;
840 
841     if ((mem = malloc(size)) == NULL) {
842 	nomem();
843     }
844 
845     return mem;
846 }
847 
myrealloc(void * ptr,size_t size)848 void *myrealloc (void *ptr, size_t size)
849 {
850     void *mem;
851 
852     if ((mem = realloc(ptr, size)) == NULL) {
853 	nomem();
854     }
855 
856     return mem;
857 }
858 
mark_dataset_as_modified(void)859 void mark_dataset_as_modified (void)
860 {
861     data_status |= MODIFIED_DATA;
862     set_sample_label(dataset);
863 
864     if (session_file_is_open()) {
865 	mark_session_changed();
866     }
867 }
868 
path_last_slash_const(const char * path)869 const char *path_last_slash_const (const char *path)
870 {
871     return (const char *) strrslash(path);
872 }
873 
gretl_basename(char * dest,const char * src,int addscore)874 char *gretl_basename (char *dest, const char *src, int addscore)
875 {
876     const char *p = path_last_slash_const(src);
877     const char *s = (p != NULL)? p + 1 : src;
878 
879     if (dest == NULL) {
880 	/* allocate return value */
881 	size_t len = strlen(s) + 1;
882 
883 	dest = calloc(len, 1);
884 	addscore = 0;
885     }
886 
887     if (dest != NULL) {
888 	strcpy(dest, s);
889     }
890 
891     if (addscore) {
892 	/* double any underscores in @dest */
893 	char mod[MAXSTR];
894 	int n = strlen(dest);
895 	int i, j = 0;
896 
897 	for (i=0; i<=n; i++) {
898 	    if (dest[i] == '_') {
899 		mod[j++] = '_';
900 	    }
901 	    mod[j++] = dest[i];
902 	}
903 	strcpy(dest, mod);
904     }
905 
906     return dest;
907 }
908 
gui_record_data_opening(const char * fname,const int * list)909 static void gui_record_data_opening (const char *fname,
910 				     const int *list)
911 {
912     const char *recname = (fname != NULL)? fname : datafile;
913 
914     if (data_status & BOOK_DATA) {
915 	/* don't print the (platform-dependent) full
916 	   path to a datafile packaged with gretl
917 	*/
918 	char basename[MAXSTR];
919 
920 	gretl_basename(basename, recname, 0);
921 	lib_command_sprintf("open %s", basename);
922     } else if (strchr(recname, ' ') != NULL) {
923 	lib_command_sprintf("open \"%s\"", recname);
924     } else {
925 	lib_command_sprintf("open %s", recname);
926     }
927 
928     if (list != NULL && list[0] == 3) {
929 	/* record spreadsheet parameters */
930 	char parm[32];
931 
932 	if (list[1] > 1) {
933 	    sprintf(parm, " --sheet=%d", list[1]);
934 	    lib_command_strcat(parm);
935 	}
936 	if (list[2] > 0) {
937 	    sprintf(parm, " --coloffset=%d", list[2]);
938 	    lib_command_strcat(parm);
939 	}
940 	if (list[3] > 0) {
941 	    sprintf(parm, " --rowoffset=%d", list[3]);
942 	    lib_command_strcat(parm);
943 	}
944     }
945 
946     record_command_verbatim();
947 
948     if (*datafile != '\0') {
949 	mkfilelist(FILE_LIST_DATA, datafile, 0);
950     }
951 }
952 
953 #define file_opened(f) (f == DATAFILE_OPENED || \
954 	                f == OPENED_VIA_CLI || \
955                         f == OPENED_VIA_SESSION)
956 
real_register_data(int flag,const char * user_fname,const int * list)957 static void real_register_data (int flag, const char *user_fname,
958 				const int *list)
959 {
960     /* basic accounting */
961     data_status |= HAVE_DATA;
962     orig_vars = dataset->v;
963 
964     /* set appropriate data_status bits */
965     if (file_opened(flag)) {
966 	if (!(data_status & IMPORT_DATA)) {
967 	    /* we opened a native data file */
968 	    if (has_system_prefix(datafile, DATA_SEARCH)) {
969 		data_status |= BOOK_DATA;
970 		data_status &= ~USER_DATA;
971 	    } else {
972 		data_status &= ~BOOK_DATA;
973 		data_status |= USER_DATA;
974 	    }
975 	    if (is_gzipped(datafile)) {
976 		data_status |= GZIPPED_DATA;
977 	    } else {
978 		data_status &= ~GZIPPED_DATA;
979 	    }
980 	    if (flag == OPENED_VIA_SESSION) {
981 		data_status |= SESSION_DATA;
982 	    } else {
983 		data_status &= ~SESSION_DATA;
984 	    }
985 	}
986     } else {
987 	/* we modified the current dataset somehow */
988 	data_status |= GUI_DATA;
989 	mark_dataset_as_modified();
990     }
991 
992     /* sync main window with datafile */
993     if (mdata != NULL) {
994 	populate_varlist();
995 	set_sample_label(dataset);
996 	dataset_menubar_state(TRUE);
997 	session_menu_state(TRUE);
998     }
999 
1000     /* Record the opening of the data file in the GUI recent files
1001        list and command log; note that we don't do this if the file
1002        was opened via script or console, or if it was opened as a
1003        side effect of re-opening a saved session. And we can't do
1004        it if the data file was opened via the initial command line,
1005        and the gretl GUI is not yet built.
1006     */
1007     if (mdata != NULL && flag == DATAFILE_OPENED) {
1008 	gui_record_data_opening(user_fname, list);
1009     }
1010 
1011     if (mdata != NULL) {
1012 	if (flag != OPENED_VIA_CLI) {
1013 	    /* focus the data window */
1014 	    gtk_widget_grab_focus(mdata->listbox);
1015 	}
1016 	/* invalidate "remove extra obs" menu item */
1017 	drop_obs_state(FALSE);
1018     }
1019 }
1020 
register_data(int flag)1021 void register_data (int flag)
1022 {
1023     real_register_data(flag, NULL, NULL);
1024 }
1025 
register_startup_data(const char * fname)1026 void register_startup_data (const char *fname)
1027 {
1028     real_register_data(DATAFILE_OPENED, fname, NULL);
1029 }
1030 
maybe_offer_daily_options(void)1031 static void maybe_offer_daily_options (void)
1032 {
1033     gretlopt purge_opt = 0;
1034     PRN *prn = NULL;
1035 
1036     bufopen(&prn);
1037 
1038     if (prn != NULL) {
1039 	int chk = analyse_daily_import(dataset, prn);
1040 	const char *buf = NULL;
1041 	int resp;
1042 
1043 	if (chk > 0) {
1044 	    buf = gretl_print_get_buffer(prn);
1045 	}
1046 
1047 	if (chk == 1) {
1048 	    const char *opts[] = {
1049 		N_("Leave the dataset as it is"),
1050 		N_("Delete the weekend rows")
1051 	    };
1052 
1053 	    resp = radio_dialog("gretl", _(buf), opts, 2,
1054 				1, DAILY_PURGE, NULL);
1055 	    if (resp == 1) {
1056 		purge_opt = OPT_W;
1057 	    }
1058 	} else if (chk == 2) {
1059 	    const char *opts[] = {
1060 		N_("Leave the dataset as it is"),
1061 		N_("Delete the weekend rows"),
1062 		N_("Delete all blank rows")
1063 	    };
1064 
1065 	    resp = radio_dialog("gretl", _(buf), opts, 3,
1066 				2, DAILY_PURGE, NULL);
1067 	    if (resp == 1) {
1068 		purge_opt = OPT_W;
1069 	    } else if (resp == 2) {
1070 		purge_opt = OPT_A;
1071 	    }
1072 	} else if (chk == 3) {
1073 	    const char *opts[] = {
1074 		N_("Leave the dataset as it is"),
1075 		N_("Delete all blank rows")
1076 	    };
1077 
1078 	    resp = radio_dialog("gretl", _(buf), opts, 2,
1079 				1, DAILY_PURGE, NULL);
1080 	    if (resp == 1) {
1081 		purge_opt = OPT_A;
1082 	    }
1083 	}
1084 
1085 	gretl_print_destroy(prn);
1086     }
1087 
1088     if (purge_opt) {
1089 	purge_opt |= OPT_T;
1090 	bool_subsample(NULL, purge_opt, NULL);
1091     }
1092 }
1093 
finalize_data_open(const char * fname,int ftype,int import,int append,const int * list)1094 static void finalize_data_open (const char *fname, int ftype,
1095 				int import, int append,
1096 				const int *list)
1097 {
1098     if (import) {
1099 	if (ftype == GRETL_CSV || ftype == GRETL_DTA ||
1100 	    ftype == GRETL_SAV || ftype == GRETL_SAS ||
1101 	    ftype == GRETL_XLSX || ftype == GRETL_ODS ||
1102 	    ftype == GRETL_GNUMERIC || ftype == GRETL_XLS) {
1103 	    maybe_display_string_table();
1104 	}
1105 	data_status |= IMPORT_DATA;
1106     }
1107 
1108     if (append) {
1109 	register_data(DATA_APPENDED);
1110 	return;
1111     }
1112 
1113     if (strstr(fname, CLIPTEMP)) {
1114 	real_register_data(DATA_PASTED, NULL, list);
1115     } else {
1116 	if (fname != datafile) {
1117 	    strcpy(datafile, fname);
1118 	}
1119 	real_register_data(DATAFILE_OPENED, NULL, list);
1120     }
1121 
1122     if (import && !dataset_is_time_series(dataset) &&
1123 	!dataset_is_panel(dataset) && ftype != GRETL_MAP &&
1124 	mdata != NULL) {
1125 	int resp;
1126 
1127 	resp = yes_no_dialog(_("gretl: open data"),
1128 			     _("The imported data have been interpreted as undated\n"
1129 			       "(cross-sectional).  Do you want to give the data a\n"
1130 			       "time-series or panel interpretation?"),
1131 			     NULL);
1132 	if (resp == GRETL_YES) {
1133 	    data_structure_dialog();
1134 	}
1135     } else if (import && dated_daily_data(dataset) &&
1136 	       !dataset->markers) {
1137 	maybe_offer_daily_options();
1138     }
1139 }
1140 
datafile_missing(const char * fname)1141 static int datafile_missing (const char *fname)
1142 {
1143     FILE *fp = gretl_fopen(fname, "r");
1144     int err = 0;
1145 
1146     if (fp == NULL) {
1147 	delete_from_filelist(FILE_LIST_DATA, fname);
1148 	file_read_errbox(fname);
1149 	err = E_FOPEN;
1150     } else {
1151 	fclose(fp);
1152     }
1153 
1154     return err;
1155 }
1156 
1157 /* below: get data of a sort that requires an import plugin */
1158 
get_imported_data(char * fname,int ftype,int append)1159 int get_imported_data (char *fname, int ftype, int append)
1160 {
1161     PRN *prn = NULL;
1162     int list[4] = {3, 0, 0, 0};
1163     int *plist = NULL;
1164     int (*ss_importer) (const char *, int *, char *, DATASET *,
1165 			gretlopt, PRN *);
1166     int (*misc_importer) (const char *, DATASET *,
1167 			  gretlopt, PRN *);
1168     int err = 0;
1169 
1170     if (datafile_missing(fname)) {
1171 	return E_FOPEN;
1172     }
1173 
1174     import_na_init();
1175     ss_importer = NULL;
1176     misc_importer = NULL;
1177 
1178     if (ftype == GRETL_XLS) {
1179 	ss_importer = gui_get_plugin_function("xls_get_data");
1180 	plist = list;
1181     } else if (ftype == GRETL_XLSX) {
1182 	ss_importer = gui_get_plugin_function("xlsx_get_data");
1183 	plist = list;
1184     } else if (ftype == GRETL_GNUMERIC) {
1185 	ss_importer = gui_get_plugin_function("gnumeric_get_data");
1186 	plist = list;
1187     } else if (ftype == GRETL_ODS) {
1188 	ss_importer = gui_get_plugin_function("ods_get_data");
1189 	plist = list;
1190     } else if (ftype == GRETL_DTA) {
1191 	misc_importer = gui_get_plugin_function("dta_get_data");
1192     } else if (ftype == GRETL_SAV) {
1193 	misc_importer = gui_get_plugin_function("sav_get_data");
1194     } else if (ftype == GRETL_SAS) {
1195 	misc_importer = gui_get_plugin_function("xport_get_data");
1196      } else if (ftype == GRETL_JMULTI) {
1197 	misc_importer = gui_get_plugin_function("jmulti_get_data");
1198     } else if (ftype == GRETL_WF1) {
1199 	misc_importer = gui_get_plugin_function("wf1_get_data");
1200     } else if (ftype == GRETL_MAP) {
1201 	misc_importer = gui_get_plugin_function("map_get_data");
1202     } else {
1203 	errbox(_("Unrecognized data type"));
1204 	err = 1;
1205 	goto bailout;
1206     }
1207 
1208     if (!err && ss_importer == NULL && misc_importer == NULL) {
1209 	/* failed to open plugin */
1210         err = 1;
1211 	goto bailout;
1212     }
1213 
1214     if (bufopen(&prn)) {
1215         err = 1;
1216 	goto bailout;
1217     }
1218 
1219     /* call the actual importer function */
1220     if (SPREADSHEET_IMPORT(ftype)) {
1221 	err = (*ss_importer)(fname, plist, NULL, dataset,
1222 			     OPT_G, prn);
1223     } else {
1224 	err = (*misc_importer)(fname, dataset, OPT_G, prn);
1225     }
1226 
1227     if (err == -1) {
1228 	fprintf(stderr, "data import canceled\n");
1229 	err = E_CANCEL;
1230 	goto bailout;
1231     } else {
1232 	const char *buf = gretl_print_get_buffer(prn);
1233 
1234 	if (err) {
1235 	    if (buf != NULL && *buf != '\0') {
1236 		errbox(buf);
1237 	    } else {
1238 		gui_errmsg(err);
1239 	    }
1240 	    if (err == E_FOPEN) {
1241 		delete_from_filelist(FILE_LIST_DATA, fname);
1242 	    }
1243 	} else {
1244 	    /* Do we want to be showing this? There's no error
1245 	       but it might look sort of scary!
1246 	    */
1247 #if 0 /* masked out 2020-07-11 */
1248 	    if (buf != NULL && *buf != '\0') {
1249 		infobox(buf);
1250 	    }
1251 #endif
1252 	    finalize_data_open(fname, ftype, 1, append, plist);
1253 	}
1254     }
1255 
1256  bailout:
1257 
1258     gretl_print_destroy(prn);
1259 
1260     return err;
1261 }
1262 
1263 /* get "CSV" (or more generally, ASCII) data or GNU octave data:
1264    plugin is not required
1265 */
1266 
get_csv_data(char * fname,int ftype,int append)1267 static int get_csv_data (char *fname, int ftype, int append)
1268 {
1269     windata_t *vwin;
1270     PRN *prn;
1271     gchar *title = NULL;
1272     gretlopt opt = OPT_NONE;
1273     int err = 0;
1274 
1275     if (datafile_missing(fname)) {
1276 	return E_FOPEN;
1277     }
1278 
1279     if (ftype == GRETL_CSV) {
1280 	const char *msg =
1281 	    N_("Usually gretl tries to interpret the first column of a CSV\n"
1282 	       "data file as containing observation information (for example,\n"
1283 	       "dates), if the column heading looks suitable.\n\n"
1284 	       "Do you want to force gretl to treat the first column as just\n"
1285 	       "an ordinary data series (regardless of the column heading)?");
1286 
1287 	if (no_yes_dialog(NULL, _(msg)) == GRETL_YES) {
1288 	    opt = OPT_A;
1289 	}
1290     }
1291 
1292     if (bufopen(&prn)) {
1293 	return 1;
1294     }
1295 
1296     if (ftype == GRETL_OCTAVE) {
1297 	err = import_other(fname, ftype, dataset, opt, prn);
1298 	title = g_strdup_printf(_("gretl: import %s data"), "Octave");
1299     } else {
1300 	err = import_csv(fname, dataset, opt, prn);
1301 	title = g_strdup_printf(_("gretl: import %s data"), "CSV");
1302     }
1303 
1304     /* show details regarding the import */
1305     vwin = view_buffer(prn, 78, 350, title, IMPORT, NULL);
1306     gtk_window_set_transient_for(GTK_WINDOW(vwin->main),
1307 				 GTK_WINDOW(mdata->main));
1308     g_free(title);
1309 
1310     if (err) {
1311 	delete_from_filelist(FILE_LIST_DATA, fname);
1312     } else {
1313 	finalize_data_open(fname, ftype, 1, append, NULL);
1314     }
1315 
1316     return err;
1317 }
1318 
get_native_data(char * fname,int ftype,int append,windata_t * fwin)1319 static int get_native_data (char *fname, int ftype, int append,
1320 			    windata_t *fwin)
1321 {
1322     PRN *prn = NULL;
1323     char *buf = NULL;
1324     int err;
1325 
1326     if (bufopen(&prn)) {
1327 	return 1;
1328     }
1329 
1330     if (ftype == GRETL_XML_DATA) {
1331 	err = gretl_read_gdt(fname, dataset, OPT_B, prn);
1332     } else {
1333 	err = gretl_get_data(fname, dataset, OPT_NONE, prn);
1334     }
1335 
1336     buf = gretl_print_steal_buffer(prn);
1337     gretl_print_destroy(prn);
1338 
1339     if (fwin != NULL) {
1340 	/* close the files browser window that launched the query */
1341 	gtk_widget_destroy(fwin->main);
1342     }
1343 
1344     if (err) {
1345 	if (err == E_FOPEN) {
1346 	    file_read_errbox(fname);
1347 	} else if (buf != NULL && *buf != '\0') {
1348 	    errbox(buf);
1349 	} else {
1350 	    gui_errmsg(err);
1351 	}
1352 	delete_from_filelist(FILE_LIST_DATA, fname);
1353     } else {
1354 #if 0
1355 	if (check_gretl_warning()) {
1356 	    gui_warnmsg(0);
1357 	}
1358 #endif
1359 	finalize_data_open(fname, ftype, 0, append, NULL);
1360 	if (append) {
1361 	    infobox(_("Data appended OK\n"));
1362 	}
1363 	fputs(buf, stderr);
1364     }
1365 
1366     free(buf);
1367 
1368     return err;
1369 }
1370 
maybe_use_join(void)1371 static int maybe_use_join (void)
1372 {
1373     const char *opts[] = {
1374 	N_("simple append"),
1375 	N_("\"join\" (advanced)")
1376     };
1377 
1378     return radio_dialog(_("gretl: append data"), NULL,
1379 		        opts, 2, 0, 0, NULL);
1380 }
1381 
1382 /* The gretl.c variable @tryfile will contain the name
1383    of the data file to be opened.
1384 */
1385 
do_open_data(windata_t * fwin,int code)1386 gboolean do_open_data (windata_t *fwin, int code)
1387 {
1388     int append = (code == APPEND_DATA);
1389     char *fname = get_tryfile();
1390     char tmp[MAXLEN];
1391     GretlFileType ftype;
1392     int use_join = 0;
1393     int err = 0;
1394 
1395     if (g_path_is_absolute(fname)) {
1396 	strcpy(tmp, fname);
1397 	ftype = data_file_type_from_name(tmp);
1398     } else {
1399 	strcpy(tmp, fname);
1400 	ftype = detect_filetype(tmp, OPT_P);
1401     }
1402 
1403     /* destroy the current data set, etc., unless we're
1404        explicitly appending */
1405     if (!append) {
1406 	close_session(OPT_NONE); /* FIXME opt? */
1407     }
1408 
1409     if (append && (ftype == GRETL_CSV || ftype == GRETL_XML_DATA ||
1410 		   ftype == GRETL_BINARY_DATA)) {
1411 	use_join = maybe_use_join();
1412 	if (use_join < 0) {
1413 	    /* canceled */
1414 	    return 0;
1415 	}
1416     }
1417 
1418     if (use_join) {
1419 	err = gui_join_data(tmp, ftype);
1420     } else if (ftype == GRETL_CSV || ftype == GRETL_OCTAVE) {
1421 	err = get_csv_data(tmp, ftype, append);
1422     } else if (SPREADSHEET_IMPORT(ftype) || OTHER_IMPORT(ftype)) {
1423 	err = get_imported_data(tmp, ftype, append);
1424     } else {
1425 	err = get_native_data(tmp, ftype, append, fwin);
1426     }
1427 
1428     return !err;
1429 }
1430 
1431 /* give user choice of not opening selected datafile, if there's
1432    already a datafile open */
1433 
verify_open_data(windata_t * vwin,int code)1434 gboolean verify_open_data (windata_t *vwin, int code)
1435 {
1436     if (dataset_locked()) {
1437 	return FALSE;
1438     }
1439 
1440     if (data_status) {
1441 	int resp =
1442 	    yes_no_dialog(_("gretl: open data"),
1443 			  _("Opening a new data file will automatically\n"
1444 			    "close the current one.  Any unsaved work\n"
1445 			    "will be lost.  Proceed to open data file?"),
1446 			  vwin_toplevel(vwin));
1447 
1448 	if (resp != GRETL_YES) {
1449 	    return FALSE;
1450 	}
1451     }
1452 
1453     return do_open_data(vwin, code);
1454 }
1455 
1456 /* give user choice of not opening session file, if there's already a
1457    datafile open */
1458 
verify_open_session(void)1459 gboolean verify_open_session (void)
1460 {
1461     char *fname = get_tryfile();
1462 
1463     if (!gretl_is_pkzip_file(fname)) {
1464 	/* not a zipped session file */
1465 	return do_open_script(EDIT_HANSL);
1466     }
1467 
1468     if (data_status) {
1469 	int resp =
1470 	    yes_no_dialog(_("gretl: open session"),
1471 			  _("Opening a new session file will automatically\n"
1472 			    "close the current session.  Any unsaved work\n"
1473 			    "will be lost.  Proceed to open session file?"),
1474 			  NULL);
1475 
1476 	if (resp != GRETL_YES) {
1477 	    return FALSE;
1478 	}
1479     }
1480 
1481     return do_open_session();
1482 }
1483 
mark_vwin_content_changed(windata_t * vwin)1484 void mark_vwin_content_changed (windata_t *vwin)
1485 {
1486     if (vwin->active_var == 0) {
1487 	GtkWidget *w = g_object_get_data(G_OBJECT(vwin->mbar), "save_button");
1488 
1489 	if (w != NULL) {
1490 	    gtk_widget_set_sensitive(w, TRUE);
1491 	}
1492 	vwin->flags |= VWIN_CONTENT_CHANGED;
1493 	if (window_is_tab(vwin)) {
1494 	    tabwin_tab_set_status(vwin);
1495 	}
1496     }
1497 }
1498 
mark_vwin_content_saved(windata_t * vwin)1499 void mark_vwin_content_saved (windata_t *vwin)
1500 {
1501     GtkWidget *w = g_object_get_data(G_OBJECT(vwin->mbar), "save_button");
1502 
1503     if (w != NULL) {
1504 	gtk_widget_set_sensitive(w, FALSE);
1505     }
1506 
1507     vwin->flags &= ~VWIN_CONTENT_CHANGED;
1508     if (window_is_tab(vwin)) {
1509 	tabwin_tab_set_status(vwin);
1510     }
1511 
1512     w = g_object_get_data(G_OBJECT(vwin->mbar), "save_as_button");
1513     if (w != NULL) {
1514 	gtk_widget_set_sensitive(w, TRUE);
1515     }
1516 }
1517 
1518 /* save content function for an editor window that is hooked
1519    up to a given text buffer rather than in the business of
1520    saving to file
1521 */
1522 
buf_edit_save(GtkWidget * w,windata_t * vwin)1523 static void buf_edit_save (GtkWidget *w, windata_t *vwin)
1524 {
1525     char **pbuf = (char **) vwin->data;
1526     gchar *text;
1527 
1528     text = textview_get_text(vwin->text);
1529 
1530     if (text == NULL || *text == '\0') {
1531 	errbox(_("Buffer is empty"));
1532 	g_free(text);
1533 	return;
1534     }
1535 
1536     /* swap the edited text into the buffer */
1537     free(*pbuf);
1538     *pbuf = text;
1539 
1540     if (vwin->role == EDIT_HEADER) {
1541 	mark_vwin_content_saved(vwin);
1542 	mark_dataset_as_modified();
1543     } else if (vwin->role == EDIT_NOTES) {
1544 	mark_vwin_content_saved(vwin);
1545 	mark_session_changed();
1546     }
1547 }
1548 
file_edit_save(GtkWidget * w,windata_t * vwin)1549 static void file_edit_save (GtkWidget *w, windata_t *vwin)
1550 {
1551     if (vwin->role == EDIT_PKG_SAMPLE) {
1552 	/* function package editor, sample script window */
1553 	update_sample_script(vwin);
1554     } else if (vwin->role == EDIT_PKG_CODE) {
1555 	/* function package editor, function code window */
1556 	update_func_code(vwin);
1557     } else if (vwin->role == EDIT_PKG_HELP ||
1558 	       vwin->role == EDIT_PKG_GHLP) {
1559 	/* function package editor, help text window */
1560 	update_gfn_help_text(vwin);
1561     } else if (*vwin->fname == '\0' || strstr(vwin->fname, "script_tmp")) {
1562 	/* no real filename is available yet */
1563 	if (vwin->role == EDIT_HANSL) {
1564 	    file_selector(SAVE_SCRIPT, FSEL_DATA_VWIN, vwin);
1565 	} else if (vwin->role == EDIT_GP) {
1566 	    file_selector(SAVE_GP_CMDS, FSEL_DATA_VWIN, vwin);
1567 	} else if (vwin->role == EDIT_R) {
1568 	    file_selector(SAVE_R_CMDS, FSEL_DATA_VWIN, vwin);
1569 	} else if (vwin->role == EDIT_OX) {
1570 	    file_selector(SAVE_OX_CMDS, FSEL_DATA_VWIN, vwin);
1571 	} else if (vwin->role == EDIT_OCTAVE) {
1572 	    file_selector(SAVE_OCTAVE_CMDS, FSEL_DATA_VWIN, vwin);
1573 	} else if (vwin->role == EDIT_PYTHON) {
1574 	    file_selector(SAVE_PYTHON_CMDS, FSEL_DATA_VWIN, vwin);
1575 	} else if (vwin->role == EDIT_JULIA) {
1576 	    file_selector(SAVE_JULIA_CODE, FSEL_DATA_VWIN, vwin);
1577 	} else if (vwin->role == EDIT_STATA) {
1578 	    file_selector(SAVE_STATA_CMDS, FSEL_DATA_VWIN, vwin);
1579 	} else if (vwin->role == EDIT_DYNARE) {
1580 	    file_selector(SAVE_DYNARE_CODE, FSEL_DATA_VWIN, vwin);
1581 	} else if (vwin->role == EDIT_LPSOLVE) {
1582 	    file_selector(SAVE_LPSOLVE_CODE, FSEL_DATA_VWIN, vwin);
1583 	} else if (vwin->role == CONSOLE) {
1584 	    file_selector(SAVE_CONSOLE, FSEL_DATA_VWIN, vwin);
1585 	}
1586     } else if ((vwin->flags & VWIN_SESSION_GRAPH) &&
1587 	       vwin->role == EDIT_GP) {
1588 	/* "auto-save" of session graph file */
1589 	gchar *text = textview_get_text(vwin->text);
1590 
1591 	dump_plot_buffer(text, vwin->fname, 0, NULL);
1592 	g_free(text);
1593 	mark_vwin_content_saved(vwin);
1594 	mark_session_changed();
1595     } else {
1596 	FILE *fp = gretl_fopen(vwin->fname, "wb");
1597 
1598 	if (fp == NULL) {
1599 	    file_write_errbox(vwin->fname);
1600 	} else {
1601 	    gchar *text = textview_get_text(vwin->text);
1602 
1603 	    system_print_buf(text, fp);
1604 	    fclose(fp);
1605 	    g_free(text);
1606 	    mark_vwin_content_saved(vwin);
1607 	}
1608     }
1609 }
1610 
vwin_save_callback(GtkWidget * w,windata_t * vwin)1611 void vwin_save_callback (GtkWidget *w, windata_t *vwin)
1612 {
1613     if (vwin_editing_buffer(vwin->role)) {
1614 	buf_edit_save(w, vwin);
1615     } else {
1616 	file_edit_save(w, vwin);
1617     }
1618 }
1619 
1620 /* Hook up child and parent viewers: this is used to help organize the
1621    window list menu (with, e.g., model-related output windows being
1622    marked as children of the model window itself).  It's also used for
1623    some more specialized cases, such as marking a script output window
1624    as child of the originating script window.
1625 */
1626 
vwin_add_child(windata_t * parent,windata_t * child)1627 void vwin_add_child (windata_t *parent, windata_t *child)
1628 {
1629     int n = parent->n_gretl_children;
1630     int i, done = 0, err = 0;
1631 
1632     for (i=0; i<n; i++) {
1633 	if (parent->gretl_children[i] == NULL) {
1634 	    /* reuse a vacant slot */
1635 	    parent->gretl_children[i] = child;
1636 	    done = 1;
1637 	    break;
1638 	}
1639     }
1640 
1641     if (!done) {
1642 	windata_t **children;
1643 
1644 	children = myrealloc(parent->gretl_children, (n + 1) * sizeof *children);
1645 
1646 	if (children != NULL) {
1647 	    parent->gretl_children = children;
1648 	    parent->gretl_children[n] = child;
1649 	    parent->n_gretl_children += 1;
1650 	} else {
1651 	    err = 1;
1652 	}
1653     }
1654 
1655     if (!err) {
1656 	child->gretl_parent = parent;
1657     }
1658 }
1659 
vwin_nullify_child(windata_t * parent,windata_t * child)1660 static void vwin_nullify_child (windata_t *parent, windata_t *child)
1661 {
1662     int i;
1663 
1664     for (i=0; i<parent->n_gretl_children; i++) {
1665 	if (child == parent->gretl_children[i]) {
1666 	    parent->gretl_children[i] = NULL;
1667 	}
1668     }
1669 }
1670 
vwin_first_child(windata_t * vwin)1671 windata_t *vwin_first_child (windata_t *vwin)
1672 {
1673     int i;
1674 
1675     for (i=0; i<vwin->n_gretl_children; i++) {
1676 	if (vwin->gretl_children[i] != NULL) {
1677 	    return vwin->gretl_children[i];
1678 	}
1679     }
1680 
1681     return NULL;
1682 }
1683 
free_windata(GtkWidget * w,gpointer data)1684 void free_windata (GtkWidget *w, gpointer data)
1685 {
1686     windata_t *vwin = (windata_t *) data;
1687 
1688 #if 0
1689     fprintf(stderr, "free_windata: vwin %p, gtk_window %p, role %d\n",
1690 	    data, (void *) vwin->main, vwin->role);
1691 #endif
1692 
1693     if (vwin != NULL) {
1694 	/* notify parent, if any, that child is gone */
1695 	if (vwin->gretl_parent != NULL) {
1696 	    vwin_nullify_child(vwin->gretl_parent, vwin);
1697 	}
1698 
1699 	/* notify children, if any, that parent is gone */
1700 	if (vwin->n_gretl_children > 0) {
1701 	    int i;
1702 
1703 	    for (i=0; i<vwin->n_gretl_children; i++) {
1704 		if (vwin->gretl_children[i] != NULL) {
1705 		    vwin->gretl_children[i]->gretl_parent = NULL;
1706 		}
1707 	    }
1708 	    free(vwin->gretl_children);
1709 	}
1710 
1711 	/* menu stuff */
1712 	if (vwin->popup != NULL) {
1713 	    gtk_widget_destroy(vwin->popup);
1714 	}
1715 	if (vwin->ui != NULL) {
1716 	    g_object_unref(vwin->ui);
1717 	}
1718 
1719 	/* toolbar popups? */
1720 	if (vwin->mbar != NULL) {
1721 	    vwin_free_toolbar_popups(vwin);
1722 	}
1723 
1724 	/* tabbed toolbar */
1725 	if (window_is_tab(vwin) && vwin->mbar != NULL) {
1726 	    g_object_unref(vwin->mbar);
1727 	}
1728 
1729 	/* data specific to certain windows */
1730 	if (vwin->role == SUMMARY) {
1731 	    free_summary(vwin->data);
1732 	} else if (vwin->role == CORR || vwin->role == PCA ||
1733 		   vwin->role == COVAR) {
1734 	    free_vmatrix(vwin->data);
1735 	} else if (vwin->role == FCAST || vwin->role == AFR) {
1736 	    free_fit_resid(vwin->data);
1737 	} else if (vwin->role == COEFFINT) {
1738 	    free_coeff_intervals(vwin->data);
1739 	} else if (vwin->role == VIEW_SERIES) {
1740 	    free_series_view(vwin->data);
1741 	} else if (vwin->role == VIEW_MODEL) {
1742 	    gretl_object_unref(vwin->data, GRETL_OBJ_EQN);
1743 	} else if (vwin->role == VAR || vwin->role == VECM) {
1744 	    gretl_object_unref(vwin->data, GRETL_OBJ_VAR);
1745 	} else if (vwin->role == LEVERAGE) {
1746 	    gretl_matrix_free(vwin->data);
1747 	} else if (vwin->role == MAHAL) {
1748 	    free_mahal_dist(vwin->data);
1749 	} else if (vwin->role == XTAB) {
1750 	    free_xtab(vwin->data);
1751 	} else if (vwin->role == COINT2) {
1752 	    gretl_VAR_free(vwin->data);
1753 	} else if (vwin->role == SYSTEM) {
1754 	    gretl_object_unref(vwin->data, GRETL_OBJ_SYS);
1755 	} else if (vwin->flags & VWIN_MULTI_SERIES) {
1756 	    free_series_view(vwin->data);
1757 	} else if (help_role(vwin->role)) {
1758 	    g_free(vwin->data); /* help file text */
1759 	} else if (vwin->role == VIEW_BUNDLE ||
1760 		   vwin->role == VIEW_DBNOMICS) {
1761 	    if (!get_user_var_by_data(vwin->data)) {
1762 		gretl_bundle_destroy(vwin->data);
1763 	    }
1764 	} else if (vwin->role == LOESS || vwin->role == NADARWAT) {
1765 	    gretl_bundle_destroy(vwin->data);
1766 	}
1767 
1768 	if (window_delete_filename(vwin)) {
1769 	    /* there's a temporary file associated */
1770 	    gretl_remove(vwin->fname);
1771 	}
1772 
1773 	free(vwin);
1774     }
1775 }
1776 
text_popup_handler(GtkWidget * w,GdkEventButton * event,gpointer p)1777 gboolean text_popup_handler (GtkWidget *w, GdkEventButton *event, gpointer p)
1778 {
1779     if (right_click(event)) {
1780 	windata_t *vwin = (windata_t *) p;
1781 
1782 	if (vwin->popup != NULL) {
1783 	    gtk_widget_destroy(vwin->popup);
1784 	    vwin->popup = NULL;
1785 	}
1786 
1787 	vwin->popup = build_text_popup(vwin);
1788 
1789 	if (vwin->popup != NULL) {
1790 	    gtk_menu_popup(GTK_MENU(vwin->popup), NULL, NULL, NULL, NULL,
1791 			   event->button, event->time);
1792 	    g_signal_connect(G_OBJECT(vwin->popup), "destroy",
1793 			     G_CALLBACK(gtk_widget_destroyed),
1794 			     &vwin->popup);
1795 	}
1796 
1797 	return TRUE;
1798     }
1799 
1800     return FALSE;
1801 }
1802 
title_from_filename(const char * fname,int role,gboolean prepend)1803 gchar *title_from_filename (const char *fname,
1804 			    int role,
1805 			    gboolean prepend)
1806 {
1807     gchar *base, *title = NULL;
1808 
1809     base = g_path_get_basename(fname);
1810 
1811     if (!strcmp(base, "session.inp") || !strncmp(base, "script_tmp.", 11)) {
1812 	if (role == EDIT_GP) {
1813 	    title = g_strdup(_("gretl: edit plot commands"));
1814 	} else if (role == EDIT_R) {
1815 	    title = g_strdup(_("gretl: edit R script"));
1816 	} else if (role == EDIT_OX) {
1817 	    title = g_strdup(_("gretl: edit Ox program"));
1818 	} else if (role == EDIT_OCTAVE) {
1819 	    title = g_strdup(_("gretl: edit Octave script"));
1820 	} else if (role == EDIT_PYTHON) {
1821 	    title = g_strdup(_("gretl: edit Python script"));
1822 	} else if (role == EDIT_JULIA) {
1823 	    title = g_strdup(_("gretl: edit Julia program"));
1824 	} else if (role == EDIT_STATA) {
1825 	    title = g_strdup(_("gretl: edit Stata program"));
1826 	} else if (role == EDIT_DYNARE) {
1827 	    title = g_strdup(_("gretl: edit Dynare script"));
1828 	} else if (role == EDIT_LPSOLVE) {
1829 	    title = g_strdup(_("gretl: edit lpsolve script"));
1830 	} else if (role == EDIT_SPEC) {
1831 	    title = g_strdup(_("gretl: edit package spec file"));
1832 	} else {
1833 	    title = g_strdup(_("gretl: untitled"));
1834 	}
1835     } else if (prepend) {
1836 	title = g_strdup_printf("gretl: %s", base);
1837     } else {
1838 	title = base;
1839 	base = NULL; /* don't free */
1840     }
1841 
1842     g_free(base);
1843 
1844     return title;
1845 }
1846 
1847 /* called when replacing a script in (non-tabbed) script
1848    editor, via the editor's "Open" button */
1849 
vwin_set_filename(windata_t * vwin,const char * fname)1850 void vwin_set_filename (windata_t *vwin, const char *fname)
1851 {
1852     gchar *title = title_from_filename(fname, vwin->role, TRUE);
1853 
1854     gtk_window_set_title(GTK_WINDOW(vwin->main), title);
1855     g_free(title);
1856     strcpy(vwin->fname, fname);
1857 }
1858 
script_output_title(void)1859 static gchar *script_output_title (void)
1860 {
1861     int n = get_script_output_number();
1862 
1863     if (n > 0) {
1864 	return g_strdup_printf(_("gretl: script output %d"), n+1);
1865     } else {
1866 	return g_strdup(_("gretl: script output"));
1867     }
1868 }
1869 
title_from_data(gpointer data)1870 static gchar *title_from_data (gpointer data)
1871 {
1872     gretl_bundle *b = data;
1873     const char *s = gretl_bundle_get_creator(b);
1874 
1875     if (s != NULL) {
1876 	return g_strdup_printf("gretl: %s bundle", s);
1877     } else {
1878 	return NULL;
1879     }
1880 }
1881 
make_viewer_title(int role,const char * fname,gpointer data)1882 static gchar *make_viewer_title (int role, const char *fname,
1883 				 gpointer data)
1884 {
1885     gchar *title = NULL;
1886 
1887     switch (role) {
1888     case CMD_HELP:
1889 	title = g_strdup(_("gretl: command reference")); break;
1890     case GUI_HELP:
1891 	title = g_strdup(_("gretl: help")); break;
1892     case FUNC_HELP:
1893 	title = g_strdup(_("gretl: function reference")); break;
1894     case CMD_HELP_EN:
1895 	title = g_strdup("gretl: command reference"); break;
1896     case GUI_HELP_EN:
1897 	title = g_strdup("gretl: help"); break;
1898     case FUNC_HELP_EN:
1899 	title = g_strdup("gretl: function reference"); break;
1900     case VIEW_LOG:
1901 	title = g_strdup(_("gretl: command log")); break;
1902     case EDIT_HANSL:
1903     case VIEW_SCRIPT:
1904     case VIEW_FILE:
1905     case VIEW_CODEBOOK:
1906     case VIEW_DOC:
1907     case EDIT_GP:
1908     case EDIT_R:
1909     case EDIT_OX:
1910     case EDIT_OCTAVE:
1911     case EDIT_PYTHON:
1912     case EDIT_JULIA:
1913     case EDIT_STATA:
1914     case EDIT_DYNARE:
1915     case EDIT_LPSOLVE:
1916     case EDIT_SPEC:
1917 	title = title_from_filename(fname, role, TRUE);
1918 	break;
1919     case EDIT_NOTES:
1920 	title = g_strdup(_("gretl: session notes")); break;
1921     case SCRIPT_OUT:
1922     case FNCALL_OUT:
1923 	title = script_output_title();
1924 	break;
1925     case VIEW_DATA:
1926 	title = g_strdup(_("gretl: display data")); break;
1927     case VIEW_BUNDLE:
1928 	title = title_from_data(data);
1929 	break;
1930     default:
1931 	break;
1932     }
1933 
1934     return title;
1935 }
1936 
content_changed(GtkWidget * w,windata_t * vwin)1937 static void content_changed (GtkWidget *w, windata_t *vwin)
1938 {
1939     mark_vwin_content_changed(vwin);
1940 }
1941 
attach_content_changed_signal(windata_t * vwin)1942 static void attach_content_changed_signal (windata_t *vwin)
1943 {
1944     GtkTextBuffer *tbuf;
1945 
1946     tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(vwin->text));
1947     g_signal_connect(G_OBJECT(tbuf), "changed",
1948 		     G_CALLBACK(content_changed), vwin);
1949 }
1950 
1951 #define viewing_source(r) (r == VIEW_PKG_CODE || \
1952 			   r == EDIT_PKG_CODE || \
1953 			   r == VIEW_LOG ||      \
1954 			   r == EDIT_PKG_SAMPLE || \
1955 			   r == VIEW_PKG_SAMPLE)
1956 
view_buffer_insert_text(windata_t * vwin,PRN * prn)1957 static void view_buffer_insert_text (windata_t *vwin, PRN *prn)
1958 {
1959     if (prn != NULL) {
1960 	const char *buf = gretl_print_get_trimmed_buffer(prn);
1961 	gchar *bconv = NULL;
1962 
1963 	if (!g_utf8_validate(buf, -1, NULL)) {
1964 	    gsize bytes;
1965 
1966 	    bconv = g_locale_to_utf8(buf, -1, NULL, &bytes, NULL);
1967 	    if (bconv != NULL) {
1968 		buf = (const char *) bconv;
1969 	    }
1970 	}
1971 
1972 	if (viewing_source(vwin->role)) {
1973 	    sourceview_insert_buffer(vwin, buf);
1974 	} else if (vwin->role == SCRIPT_OUT) {
1975 	    textview_set_text_colorized(vwin->text, buf);
1976 	} else if (vwin->role == BUILD_PKG) {
1977 	    textview_set_text_report(vwin->text, buf);
1978 	} else if (vwin->role == VIEW_DBSEARCH) {
1979 	    textview_set_text_dbsearch(vwin, buf);
1980 	} else {
1981 	    textview_set_text(vwin->text, buf);
1982 	}
1983 
1984 	g_free(bconv);
1985     }
1986 }
1987 
1988 /* for use with reuseable script output window */
1989 static windata_t *script_out_viewer;
1990 
nullify_script_out(GtkWidget * w,windata_t ** pvwin)1991 static gboolean nullify_script_out (GtkWidget *w, windata_t **pvwin)
1992 {
1993     *pvwin = NULL;
1994     return FALSE;
1995 }
1996 
set_reuseable_output_window(int policy,windata_t * vwin)1997 void set_reuseable_output_window (int policy, windata_t *vwin)
1998 {
1999     if (policy == OUTPUT_POLICY_NEW_WINDOW) {
2000 	script_out_viewer = NULL;
2001     } else {
2002 	script_out_viewer = vwin;
2003 	g_signal_connect(G_OBJECT(vwin->main), "destroy",
2004 			 G_CALLBACK(nullify_script_out),
2005 			 &script_out_viewer);
2006     }
2007 }
2008 
reuse_script_out(windata_t * vwin,PRN * prn)2009 static windata_t *reuse_script_out (windata_t *vwin, PRN *prn)
2010 {
2011     int policy = get_script_output_policy();
2012     GtkTextBuffer *buf;
2013     const char *newtext;
2014 
2015     newtext = gretl_print_get_buffer(prn);
2016     buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(vwin->text));
2017 
2018     if (policy == OUTPUT_POLICY_APPEND) {
2019 	GtkTextMark *mark;
2020 	GtkTextIter iter;
2021 
2022 	gtk_text_buffer_get_end_iter(buf, &iter);
2023 	mark = gtk_text_buffer_create_mark(buf, NULL, &iter, TRUE);
2024 	textview_append_text_colorized(vwin->text, newtext, 1);
2025 	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(vwin->text),
2026 				     mark, 0.0, TRUE, 0, 0.05);
2027 	gtk_text_buffer_delete_mark(buf, mark);
2028     } else {
2029 	/* replace previous content */
2030 	gtk_text_buffer_set_text(buf, "", -1);
2031 	textview_set_text_colorized(vwin->text, newtext);
2032 	cursor_to_top(vwin);
2033     }
2034 
2035     gretl_print_destroy(prn);
2036     gtk_window_present(GTK_WINDOW(vwin->main));
2037 
2038     return vwin;
2039 }
2040 
vwin_add_closer(windata_t * vwin)2041 static void vwin_add_closer (windata_t *vwin)
2042 {
2043     GtkWidget *b;
2044 
2045     b = gtk_button_new_with_label(_("Close"));
2046     g_signal_connect(G_OBJECT(b), "clicked",
2047 		     G_CALLBACK(delete_widget), vwin->main);
2048     gtk_widget_show(b);
2049     gtk_box_pack_end(GTK_BOX(vwin->vbox), b, FALSE, FALSE, 0);
2050 }
2051 
set_model_save_state(windata_t * vwin,gboolean s)2052 void set_model_save_state (windata_t *vwin, gboolean s)
2053 {
2054     flip(vwin->ui, "/menubar/File/SaveAsIcon", s);
2055     flip(vwin->ui, "/menubar/File/SaveAndClose", s);
2056 }
2057 
2058 windata_t *
view_buffer_with_parent(windata_t * parent,PRN * prn,int hsize,int vsize,const char * title,int role,gpointer data)2059 view_buffer_with_parent (windata_t *parent, PRN *prn,
2060 			 int hsize, int vsize,
2061 			 const char *title, int role,
2062 			 gpointer data)
2063 {
2064     int width = 0, nlines = 0;
2065     windata_t *vwin;
2066 
2067     if (role == SCRIPT_OUT && script_out_viewer != NULL) {
2068 	return reuse_script_out(script_out_viewer, prn);
2069     }
2070 
2071     if (title != NULL) {
2072 	vwin = gretl_viewer_new_with_parent(parent, role, title,
2073 					    data);
2074     } else {
2075 	gchar *tmp = make_viewer_title(role, NULL, data);
2076 
2077 	vwin = gretl_viewer_new_with_parent(parent, role, tmp,
2078 					    data);
2079 	g_free(tmp);
2080     }
2081 
2082     if (vwin == NULL) {
2083 	return NULL;
2084     }
2085 
2086     if (role == VAR || role == VECM || role == SYSTEM) {
2087 	/* special case: use a text-based menu bar */
2088 	vwin_add_ui(vwin, system_items, n_system_items, sys_ui);
2089 	set_model_save_state(vwin, !is_session_model(vwin->data));
2090 	add_system_menu_items(vwin, role);
2091 	vwin_pack_toolbar(vwin);
2092 	if (role == VAR || role == VECM) {
2093 	    g_signal_connect(G_OBJECT(vwin->mbar), "button-press-event",
2094 			     G_CALLBACK(check_VAR_menu), vwin);
2095 	}
2096 	gretl_object_ref(data, (role == SYSTEM)? GRETL_OBJ_SYS : GRETL_OBJ_VAR);
2097     } else if (role == VIEW_PKG_CODE ||
2098 	       role == VIEW_PKG_SAMPLE ||
2099 	       role == VIEW_LOG ||
2100 	       role == VIEW_DBSEARCH ||
2101 	       role == VIEW_MODELTABLE) {
2102 	vwin_add_viewbar(vwin, 0);
2103     } else if (role == EDIT_PKG_CODE ||
2104 	       role == EDIT_PKG_SAMPLE ||
2105 	       role == EDIT_PKG_HELP ||
2106 	       role == EDIT_PKG_GHLP) {
2107 	vwin_add_viewbar(vwin, VIEWBAR_EDITABLE);
2108     } else if (role == IMPORT || role == BUILD_PKG) {
2109 	vwin_add_closer(vwin);
2110     } else {
2111 	vwin_add_viewbar(vwin, VIEWBAR_HAS_TEXT);
2112     }
2113 
2114     if (role != VIEW_PKG_CODE &&
2115 	role != EDIT_PKG_CODE &&
2116 	role != VIEW_PKG_SAMPLE &&
2117 	role != VIEW_LOG &&
2118 	role != EDIT_PKG_HELP &&
2119 	role != EDIT_PKG_GHLP &&
2120 	role != SCRIPT_OUT) {
2121 	gretl_print_get_size(prn, &width, &nlines);
2122 	if (width > 0 && width + 2 < hsize) {
2123 	    hsize = width + 2;
2124 	}
2125     }
2126 
2127     if (role == VIEW_PKG_CODE || role == VIEW_PKG_SAMPLE || role == VIEW_LOG) {
2128 	create_source(vwin, hsize, vsize, FALSE);
2129     } else if (role == EDIT_PKG_CODE || role == EDIT_PKG_SAMPLE) {
2130 	create_source(vwin, hsize, vsize, TRUE);
2131     } else if (role == EDIT_PKG_HELP || role == EDIT_PKG_GHLP) {
2132 	/* editable text */
2133 	create_text(vwin, hsize, vsize, nlines, TRUE);
2134     } else {
2135 	/* non-editable text */
2136 	create_text(vwin, hsize, vsize, nlines, FALSE);
2137     }
2138 
2139     text_table_setup(vwin->vbox, vwin->text);
2140 
2141     if (role == SCRIPT_OUT) {
2142 	if (data != NULL) {
2143 	    /* partial output window for script */
2144 	    vwin_add_child((windata_t *) data, vwin);
2145 	    /* define "top-hbox" here? */
2146 	}
2147 	g_signal_connect(G_OBJECT(vwin->main), "destroy",
2148 			 G_CALLBACK(nullify_script_out),
2149 			 &script_out_viewer);
2150 	script_out_viewer = vwin;
2151     }
2152 
2153     /* insert and then free the text buffer */
2154     view_buffer_insert_text(vwin, prn);
2155     gretl_print_destroy(prn);
2156 
2157     g_signal_connect(G_OBJECT(vwin->main), "key-press-event",
2158 		     G_CALLBACK(catch_viewer_key), vwin);
2159 
2160     gtk_widget_show(vwin->vbox);
2161     gtk_widget_show(vwin->main);
2162 
2163     if (role == EDIT_PKG_CODE || role == EDIT_PKG_SAMPLE ||
2164 	role == EDIT_PKG_HELP || role == EDIT_PKG_GHLP) {
2165 	attach_content_changed_signal(vwin);
2166 	g_signal_connect(G_OBJECT(vwin->main), "delete-event",
2167 			 G_CALLBACK(query_save_text), vwin);
2168     } else if (role == SUMMARY) {
2169 	widget_set_int(vwin->text, "digits", get_gretl_digits());
2170     }
2171 
2172     if (role == BUILD_PKG) {
2173 	scroll_to_foot(vwin);
2174     } else {
2175 	g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2176 			 G_CALLBACK(text_popup_handler), vwin);
2177 	cursor_to_top(vwin);
2178     }
2179 
2180     gtk_widget_grab_focus(vwin->text);
2181 
2182     return vwin;
2183 }
2184 
view_buffer(PRN * prn,int hsize,int vsize,const char * title,int role,gpointer data)2185 windata_t *view_buffer (PRN *prn, int hsize, int vsize,
2186 			const char *title, int role,
2187 			gpointer data)
2188 {
2189     return view_buffer_with_parent(NULL, prn, hsize,
2190 				   vsize, title,
2191 				   role, data);
2192 }
2193 
2194 /* hansl_output_viewer_new: here we're creating a window
2195    that will display script output, allowing for the
2196    possibility that it may take a while for the (full)
2197    output to appear, and the script "flush" mechanism
2198    may be operating to produce incremental display.
2199 */
2200 
hansl_output_viewer_new(PRN * prn,int role,const char * title)2201 windata_t *hansl_output_viewer_new (PRN *prn, int role,
2202 				    const char *title)
2203 {
2204     windata_t *vwin;
2205     const char *buf;
2206 
2207     if (title != NULL) {
2208 	vwin = gretl_viewer_new_with_parent(NULL, role,
2209 					    title, NULL);
2210     } else {
2211 	gchar *tmp = make_viewer_title(role, NULL, NULL);
2212 
2213 	vwin = gretl_viewer_new_with_parent(NULL, role,
2214 					    tmp, NULL);
2215 	g_free(tmp);
2216     }
2217 
2218     if (vwin == NULL) {
2219 	return NULL;
2220     }
2221 
2222     vwin_add_tmpbar(vwin);
2223     create_text(vwin, SCRIPT_WIDTH, 450, 0, FALSE);
2224     text_table_setup(vwin->vbox, vwin->text);
2225 
2226     /* insert the text buffer from @prn */
2227     buf = gretl_print_get_buffer(prn);
2228     if (buf != NULL && *buf != '\0') {
2229 	textview_set_text_colorized(vwin->text, buf);
2230     }
2231 
2232     g_signal_connect(G_OBJECT(vwin->main), "key-press-event",
2233 		     G_CALLBACK(catch_viewer_key), vwin);
2234     g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2235 		     G_CALLBACK(text_popup_handler), vwin);
2236 
2237     gtk_widget_show(vwin->vbox);
2238     gtk_widget_show(vwin->main);
2239     gtk_widget_grab_focus(vwin->text);
2240 
2241     return vwin;
2242 }
2243 
2244 #define text_out_ok(r) (r == VIEW_DATA || r == VIEW_FILE)
2245 
2246 windata_t *
view_file_with_title(const char * filename,int editable,int del_file,int hsize,int vsize,int role,const char * given_title)2247 view_file_with_title (const char *filename, int editable, int del_file,
2248 		      int hsize, int vsize, int role,
2249 		      const char *given_title)
2250 {
2251     windata_t *vwin;
2252     FILE *fp;
2253     int ins = 0;
2254 
2255     /* first check that we can open the specified file */
2256     fp = gretl_fopen(filename, "r");
2257     if (fp == NULL) {
2258 	errbox_printf(_("Can't open %s for reading"), filename);
2259 	return NULL;
2260     } else {
2261 	fclose(fp);
2262     }
2263 
2264 #if 0
2265     /* experimental, not yet */
2266     if (swallow && role == EDIT_HANSL) {
2267 	ins = mainwin_get_vwin_insertion();
2268 	fprintf(stderr, "HERE ins=%d, title '%s'\n", ins, given_title);
2269 	if (ins) {
2270 	    preset_viewer_flag(VWIN_SWALLOW);
2271 	}
2272     }
2273 #endif
2274 
2275     if (!ins && role == EDIT_HANSL && use_tabbed_editor()) {
2276 	vwin = viewer_tab_new(role, filename, NULL);
2277     } else if (editing_alt_script(role) && use_tabbed_editor()) {
2278 	vwin = viewer_tab_new(role, filename, NULL);
2279     } else if (given_title != NULL) {
2280 	vwin = gretl_viewer_new(role, given_title, NULL);
2281     } else {
2282 	gchar *title = make_viewer_title(role, filename, NULL);
2283 
2284 	vwin = gretl_viewer_new(role, (title != NULL)? title : filename,
2285 				NULL);
2286 	g_free(title);
2287     }
2288 
2289     if (vwin == NULL) {
2290 	return NULL;
2291     }
2292 
2293     strcpy(vwin->fname, filename);
2294 
2295     if (role != VIEW_DOC) {
2296 	ViewbarFlags vflags = 0;
2297 
2298 	if (editable) {
2299 	    vflags = VIEWBAR_EDITABLE;
2300 	}
2301 	if (text_out_ok(role)) {
2302 	    vflags |= VIEWBAR_HAS_TEXT;
2303 	}
2304 	vwin_add_viewbar(vwin, vflags);
2305     }
2306 
2307     if (textview_use_highlighting(role) || editable) {
2308 	create_source(vwin, hsize, vsize, editable);
2309     } else {
2310 	create_text(vwin, hsize, vsize, 0, editable);
2311     }
2312 
2313     text_table_setup(vwin->vbox, vwin->text);
2314 
2315     if (textview_use_highlighting(role) || editable) {
2316 	sourceview_insert_file(vwin, filename);
2317     } else {
2318 	textview_insert_file(vwin, filename);
2319     }
2320 
2321     /* editing script or graph commands: grab the "changed" signal
2322        and set up alert for unsaved changes on exit */
2323     if (vwin_editing_script(role)) {
2324 	attach_content_changed_signal(vwin);
2325 	if (!window_is_tab(vwin)) {
2326 	    g_signal_connect(G_OBJECT(vwin->main), "delete-event",
2327 			     G_CALLBACK(query_save_text), vwin);
2328 	}
2329 	/* since 2021-05-18 */
2330 	vwin->flags |= VWIN_USE_FOOTER;
2331     }
2332 
2333     /* clean up when dialog is destroyed */
2334     if (del_file) {
2335 	gchar *fname = g_strdup(filename);
2336 
2337 	g_signal_connect(G_OBJECT(vwin->main), "destroy",
2338 			 G_CALLBACK(delete_file), (gpointer) fname);
2339     }
2340 
2341     if (window_is_tab(vwin)) {
2342 	show_tabbed_viewer(vwin);
2343     } else {
2344 	g_signal_connect(G_OBJECT(vwin->main), "key-press-event",
2345 			 G_CALLBACK(catch_viewer_key), vwin);
2346 	gtk_widget_show_all(vwin->main);
2347     }
2348 
2349     g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2350 		     G_CALLBACK(text_popup_handler), vwin);
2351 
2352     cursor_to_top(vwin);
2353     gtk_widget_grab_focus(vwin->text);
2354 
2355 #if 0 /* not yet */
2356     if (vwin->flags & VWIN_SWALLOW) {
2357 	mainwin_insert_vwin(vwin);
2358     }
2359 #endif
2360 
2361     return vwin;
2362 }
2363 
view_file(const char * filename,int editable,int del_file,int hsize,int vsize,int role)2364 windata_t *view_file (const char *filename, int editable, int del_file,
2365 		      int hsize, int vsize, int role)
2366 {
2367     return view_file_with_title(filename, editable, del_file,
2368 				hsize, vsize, role, NULL);
2369 }
2370 
view_script(const char * filename,int editable,int role)2371 windata_t *view_script (const char *filename, int editable,
2372 			int role)
2373 {
2374     if (editable) {
2375 	windata_t *vwin = get_editor_for_file(filename);
2376 
2377 	if (vwin != NULL) {
2378 	    gretl_viewer_present(vwin);
2379 	    return vwin;
2380 	}
2381     }
2382 
2383     return view_file_with_title(filename, editable, 0,
2384 				SCRIPT_WIDTH, SCRIPT_HEIGHT,
2385 				role, NULL);
2386 }
2387 
console_window(int hsize,int vsize)2388 windata_t *console_window (int hsize, int vsize)
2389 {
2390     windata_t *vwin;
2391 
2392     if (swallow) {
2393 	vwin = gretl_viewer_new(CONSOLE, NULL, NULL);
2394     } else {
2395 	gchar *title = NULL;
2396 #ifdef GRETL_PID_FILE
2397 	int seqno = gretl_sequence_number();
2398 
2399 	if (seqno > 1) {
2400 	    title = g_strdup_printf("%s (%d)", _("gretl console"), seqno);
2401 	}
2402 #endif
2403 	if (title != NULL) {
2404 	    vwin = gretl_viewer_new(CONSOLE, title, NULL);
2405 	    g_free(title);
2406 	} else {
2407 	    vwin = gretl_viewer_new(CONSOLE, _("gretl console"), NULL);
2408 	}
2409     }
2410 
2411     if (vwin == NULL) {
2412 	return NULL;
2413     }
2414 
2415     vwin->flags |= VWIN_USE_FOOTER;
2416     vwin_add_viewbar(vwin, VIEWBAR_EDITABLE);
2417     create_console(vwin, hsize, vsize);
2418     text_table_setup(vwin->vbox, vwin->text);
2419 
2420     /* catch some special keystrokes */
2421     g_signal_connect(G_OBJECT(vwin->text), "key-press-event",
2422 		     G_CALLBACK(catch_viewer_key), vwin);
2423 
2424     gtk_widget_show(vwin->vbox);
2425     if (vwin->main != vwin->vbox) {
2426 	gtk_widget_show(vwin->main);
2427     }
2428 
2429     g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2430 		     G_CALLBACK(text_popup_handler), vwin);
2431 
2432     return vwin;
2433 }
2434 
help_panes_setup(windata_t * vwin,GtkWidget * text)2435 void help_panes_setup (windata_t *vwin, GtkWidget *text)
2436 {
2437     GtkWidget *hp = gtk_hpaned_new();
2438     GtkWidget *sw;
2439 
2440     gtk_container_add(GTK_CONTAINER(vwin->vbox), hp);
2441 
2442     add_help_navigator(vwin, hp);
2443 
2444     sw = gtk_scrolled_window_new(NULL, NULL);
2445     gtk_paned_pack2(GTK_PANED(hp), sw, TRUE, TRUE);
2446     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
2447 				   GTK_POLICY_AUTOMATIC,
2448 				   GTK_POLICY_AUTOMATIC);
2449     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
2450 					GTK_SHADOW_IN);
2451     gtk_container_add(GTK_CONTAINER(sw), text);
2452 
2453     gtk_widget_show_all(hp);
2454 }
2455 
view_help_file(const char * filename,int role)2456 windata_t *view_help_file (const char *filename, int role)
2457 {
2458     windata_t *vwin;
2459     gchar *fbuf = NULL;
2460     gchar *title = NULL;
2461     int hsize = 82, vsize = 450;
2462 
2463     /* grab content of the appropriate help file into a buffer */
2464     gretl_file_get_contents(filename, &fbuf, NULL);
2465     if (fbuf == NULL) {
2466 	return NULL;
2467     }
2468 
2469     title = make_viewer_title(role, NULL, NULL);
2470     vwin = gretl_viewer_new(role, title, NULL);
2471     g_free(title);
2472 
2473     if (vwin == NULL) return NULL;
2474 
2475     strcpy(vwin->fname, filename);
2476     vwin->data = fbuf;
2477 
2478     if (role != GUI_HELP && role != GUI_HELP_EN) {
2479 	set_up_helpview_menu(vwin);
2480 	hsize += 4;
2481     }
2482 
2483     if (role == FUNC_HELP || role == FUNC_HELP_EN) {
2484 	vsize = 500;
2485     }
2486 
2487     create_text(vwin, hsize, vsize, 0, FALSE);
2488 
2489     if (role == GUI_HELP || role == GUI_HELP_EN) {
2490 	text_table_setup(vwin->vbox, vwin->text);
2491     } else {
2492 	help_panes_setup(vwin, vwin->text);
2493     }
2494 
2495     g_signal_connect(G_OBJECT(vwin->text), "key-press-event",
2496 		     G_CALLBACK(catch_viewer_key), vwin);
2497 
2498     if (vwin->role == CMD_HELP || vwin->role == CMD_HELP_EN ||
2499 	vwin->role == FUNC_HELP || vwin->role == FUNC_HELP_EN) {
2500 	g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2501 			 G_CALLBACK(help_popup_handler),
2502 			 vwin);
2503     } else {
2504 	g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2505 			 G_CALLBACK(text_popup_handler), vwin);
2506     }
2507 
2508     gtk_widget_show(vwin->vbox);
2509     gtk_widget_show(vwin->main);
2510 
2511     /* make the helpfile variant discoverable via vwin->text */
2512     g_object_set_data(G_OBJECT(vwin->text), "role",
2513 		      GINT_TO_POINTER(vwin->role));
2514 
2515     gtk_widget_grab_focus(vwin->text);
2516 
2517     return vwin;
2518 }
2519 
enter_close_button(GtkWidget * button,GdkEventCrossing * event,gpointer p)2520 static gboolean enter_close_button (GtkWidget *button,
2521 				    GdkEventCrossing *event,
2522 				    gpointer p)
2523 {
2524     /* remove text cursor: looks broken over a button */
2525     gdk_window_set_cursor(gtk_widget_get_window(button), NULL);
2526     return FALSE;
2527 }
2528 
leave_close_button(GtkWidget * button,GdkEventCrossing * event,gpointer p)2529 static gboolean leave_close_button (GtkWidget *button,
2530 				    GdkEventCrossing *event,
2531 				    gpointer p)
2532 {
2533     GdkCursor *cursor = gdk_cursor_new(GDK_XTERM);
2534 
2535     if (cursor != NULL) {
2536 	/* revert to text cursor */
2537 	gdk_window_set_cursor(gtk_widget_get_window(button), cursor);
2538 	gdk_cursor_unref(cursor);
2539     }
2540     return FALSE;
2541 }
2542 
small_close_button(GtkWidget * targ)2543 static GtkWidget *small_close_button (GtkWidget *targ)
2544 {
2545     GtkWidget *img = gtk_image_new_from_stock(GRETL_STOCK_CLOSE,
2546 					      GTK_ICON_SIZE_MENU);
2547     GtkWidget *button = gtk_button_new();
2548 
2549     gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
2550     gtk_container_add(GTK_CONTAINER(button), img);
2551 
2552     gtk_widget_add_events(button, GDK_ENTER_NOTIFY_MASK |
2553 			  GDK_LEAVE_NOTIFY_MASK);
2554     g_signal_connect(button, "enter-notify-event",
2555 		     G_CALLBACK(enter_close_button), NULL);
2556     g_signal_connect(button, "leave-notify-event",
2557 		     G_CALLBACK(leave_close_button), NULL);
2558     g_signal_connect_swapped(button, "clicked",
2559 			     G_CALLBACK(gtk_widget_destroy),
2560 			     targ);
2561     gtk_widget_show_all(button);
2562 
2563     return button;
2564 }
2565 
2566 /* Stick a little "close" button into a GtkTextBuffer */
2567 
add_text_closer(windata_t * vwin)2568 static void add_text_closer (windata_t *vwin)
2569 {
2570     GtkTextBuffer *tbuf;
2571     GtkTextIter iter, iend;
2572     GtkTextTag *tag;
2573     GtkTextChildAnchor *anchor;
2574     GtkWidget *button;
2575 
2576     tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(vwin->text));
2577     gtk_text_buffer_get_start_iter(tbuf, &iter);
2578     tag = gtk_text_buffer_create_tag(tbuf, NULL, "justification",
2579 				     GTK_JUSTIFY_RIGHT, NULL);
2580     anchor = gtk_text_buffer_create_child_anchor(tbuf, &iter);
2581     button = small_close_button(vwin->main);
2582     gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(vwin->text),
2583 				      button, anchor);
2584     gtk_text_buffer_get_iter_at_child_anchor(tbuf, &iend, anchor);
2585     gtk_text_iter_forward_char(&iend);
2586     gtk_text_buffer_insert(tbuf, &iend, "\n", -1);
2587     gtk_text_buffer_get_start_iter(tbuf, &iter);
2588     gtk_text_buffer_apply_tag(tbuf, tag, &iter, &iend);
2589 }
2590 
2591 /* For use when we want to display a piece of formatted text -- such
2592    as help for a gretl function package or a help bibliography entry
2593    -- in a window of its own, without any menu apparatus on the
2594    window. In the case of VIEW_BIBITEM, this should be a minimal window
2595    with no decorations and a simple "closer" button embedded in the
2596    GtkTextView (bibliographical popup).
2597 */
2598 
view_formatted_text_buffer(const gchar * title,const char * buf,int hsize,int vsize,int role)2599 windata_t *view_formatted_text_buffer (const gchar *title,
2600 				       const char *buf,
2601 				       int hsize, int vsize,
2602 				       int role)
2603 {
2604     windata_t *vwin;
2605 
2606     vwin = gretl_viewer_new_with_parent(NULL, role, title, NULL);
2607     if (vwin == NULL) return NULL;
2608 
2609     /* non-editable text */
2610     create_text(vwin, hsize, vsize, 0, FALSE);
2611 
2612     if (role == VIEW_BIBITEM) {
2613 	/* no scrolling apparatus */
2614 	gtk_container_add(GTK_CONTAINER(vwin->vbox), vwin->text);
2615 	gtk_widget_show(vwin->text);
2616 	gtk_window_set_decorated(GTK_WINDOW(vwin->main), FALSE);
2617     } else {
2618 	text_table_setup(vwin->vbox, vwin->text);
2619     }
2620 
2621     gretl_viewer_set_formatted_buffer(vwin, buf);
2622 
2623     if (role == VIEW_BIBITEM) {
2624 	add_text_closer(vwin);
2625     }
2626 
2627     gtk_widget_show(vwin->vbox);
2628 
2629     if (role != VIEW_BIBITEM) {
2630 	gtk_widget_show(vwin->main);
2631 	gtk_widget_grab_focus(vwin->text);
2632     }
2633 
2634     return vwin;
2635 }
2636 
2637 /* Called on destroying an editing window: give the user a chance
2638    to save if the content is changed, or to cancel the close.
2639 */
2640 
query_save_text(GtkWidget * w,GdkEvent * event,windata_t * vwin)2641 gint query_save_text (GtkWidget *w, GdkEvent *event, windata_t *vwin)
2642 {
2643     if (vwin_content_changed(vwin)) {
2644 	int resp = yes_no_cancel_dialog("gretl",
2645 					_("Save changes?"),
2646 					vwin_toplevel(vwin));
2647 
2648 	if (resp == GRETL_CANCEL) {
2649 	    /* cancel -> don't save, but also don't close */
2650 	    return TRUE;
2651 	} else if (resp == GRETL_YES) {
2652 	    vwin_save_callback(NULL, vwin);
2653 	}
2654     }
2655 
2656     return FALSE;
2657 }
2658 
edit_buffer(char ** pbuf,int hsize,int vsize,char * title,int role)2659 windata_t *edit_buffer (char **pbuf, int hsize, int vsize,
2660 			char *title, int role)
2661 {
2662     windata_t *vwin;
2663 
2664     vwin = gretl_viewer_new(role, title, pbuf);
2665     if (vwin == NULL) {
2666 	return NULL;
2667     }
2668 
2669     /* add a tool bar */
2670     vwin_add_viewbar(vwin, VIEWBAR_EDITABLE);
2671 
2672     create_source(vwin, hsize, vsize, TRUE);
2673     text_table_setup(vwin->vbox, vwin->text);
2674 
2675     /* insert the buffer text */
2676     if (pbuf != NULL && *pbuf != NULL) {
2677 	sourceview_insert_buffer(vwin, *pbuf);
2678     }
2679 
2680     g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2681 		     G_CALLBACK(text_popup_handler), vwin);
2682     g_signal_connect(G_OBJECT(vwin->main), "key-press-event",
2683 		     G_CALLBACK(catch_viewer_key), vwin);
2684 
2685     attach_content_changed_signal(vwin);
2686 
2687     /* alert for unsaved changes on exit */
2688     g_signal_connect(G_OBJECT(vwin->main), "delete-event",
2689 		     G_CALLBACK(query_save_text), vwin);
2690 
2691     gtk_widget_show(vwin->vbox);
2692     gtk_widget_show(vwin->main);
2693 
2694     cursor_to_top(vwin);
2695 
2696     return vwin;
2697 }
2698 
view_model(PRN * prn,MODEL * pmod,char * title)2699 windata_t *view_model (PRN *prn, MODEL *pmod, char *title)
2700 {
2701     int hsize = MODEL_WIDTH;
2702     int vsize = MODEL_HEIGHT;
2703     windata_t *vwin;
2704     const char *buf;
2705     gchar *tmp;
2706     int width, nlines, tabbed;
2707 
2708 #if 0
2709     fprintf(stderr, "view_model: pmod at %p, model %d\n",
2710 	    (void *) pmod, pmod->ID);
2711 #endif
2712 
2713     tabbed = use_tabbed_model_viewer();
2714 
2715     if (tabbed) {
2716 	tmp = g_strdup_printf(_("model %d"), pmod->ID);
2717 	vwin = viewer_tab_new(VIEW_MODEL, tmp, pmod);
2718 	g_free(tmp);
2719     } else if (title != NULL) {
2720 	vwin = gretl_viewer_new(VIEW_MODEL, title, pmod);
2721     } else {
2722 	tmp = g_strdup_printf(_("gretl: model %d"), pmod->ID);
2723 	vwin = gretl_viewer_new(VIEW_MODEL, tmp, pmod);
2724 	g_free(tmp);
2725     }
2726 
2727     if (vwin == NULL) {
2728 	return NULL;
2729     }
2730 
2731     /* Take responsibility for one reference to this model */
2732     gretl_object_ref(pmod, GRETL_OBJ_EQN);
2733 
2734     set_up_model_view_menu(vwin);
2735 
2736     gretl_print_get_size(prn, &width, &nlines);
2737     if (!tabbed && width > 0 && width + 2 < hsize) {
2738 	hsize = width + 2;
2739     }
2740 
2741     create_text(vwin, hsize, vsize, nlines, FALSE);
2742     text_table_setup(vwin->vbox, vwin->text);
2743 
2744     /* insert and then free the model results buffer */
2745     buf = gretl_print_get_trimmed_buffer(prn);
2746     textview_set_text(vwin->text, buf);
2747     gretl_print_destroy(prn);
2748 
2749     /* record digits in force */
2750     widget_set_int(vwin->text, "digits", get_gretl_digits());
2751 
2752     /* sync number of model tests */
2753     vwin->n_model_tests = pmod->ntests;
2754 
2755     /* attach popup */
2756     g_signal_connect(G_OBJECT(vwin->text), "button-press-event",
2757 		     G_CALLBACK(text_popup_handler), vwin);
2758 
2759     if (window_is_tab(vwin)) {
2760 	show_tabbed_viewer(vwin);
2761     } else {
2762 	g_signal_connect(G_OBJECT(vwin->main), "key-press-event",
2763 			 G_CALLBACK(catch_viewer_key), vwin);
2764 	gtk_widget_show_all(vwin->main);
2765     }
2766 
2767     cursor_to_top(vwin);
2768     gtk_widget_grab_focus(vwin->text);
2769 
2770     return vwin;
2771 }
2772 
mnl_probs_callback(GtkAction * action,gpointer p)2773 static void mnl_probs_callback (GtkAction *action, gpointer p)
2774 {
2775     windata_t *vwin = (windata_t *) p;
2776     MODEL *pmod = vwin->data;
2777     gretl_matrix *P = NULL;
2778     int err = 0;
2779 
2780     if (pmod == NULL) return;
2781 
2782     P = mn_logit_probabilities(pmod, dataset, &err);
2783 
2784     if (err) {
2785 	gui_errmsg(err);
2786     } else {
2787 	PRN *prn = NULL;
2788 
2789 	if (bufopen(&prn)) {
2790 	    gretl_matrix_free(P);
2791 	} else {
2792 	    gretl_matrix *yvals = gretl_model_get_data(pmod, "yvals");
2793 	    int obslen = max_obs_marker_length(dataset);
2794 	    int i, j, t = gretl_matrix_get_t1(P);
2795 	    int n = gretl_vector_get_length(yvals);
2796 	    double x;
2797 
2798 	    pprintf(prn, "\nEstimated outcome probabilities for %s\n\n",
2799 		    gretl_model_get_depvar_name(pmod, dataset));
2800 
2801 	    /* case values */
2802 	    bufspace(obslen, prn);
2803 	    for (j=0; j<n; j++) {
2804 		pprintf(prn, "%9g", yvals->val[j]);
2805 	    }
2806 	    pputc(prn, '\n');
2807 
2808 	    /* format the matrix content nicely, prepending
2809 	       observation strings */
2810 
2811 	    for (i=0; i<P->rows; i++) {
2812 		print_obs_marker(t, dataset, obslen, prn);
2813 		for (j=0; j<P->cols; j++) {
2814 		    x = gretl_matrix_get(P, i, j);
2815 		    if (na(x)) {
2816 			pprintf(prn, "%9s", " ");
2817 		    } else {
2818 			pprintf(prn, "%9.4f", x);
2819 		    }
2820 		}
2821 		pputc(prn, '\n');
2822 		t++;
2823 	    }
2824 
2825 	    view_buffer(prn, 78, 400, _("Outcome probabilities"), PRINT, NULL);
2826 	    gretl_matrix_free(P);
2827 	}
2828     }
2829 }
2830 
add_multinomial_probs_item(windata_t * vwin)2831 static void add_multinomial_probs_item (windata_t *vwin)
2832 {
2833     const gchar *mpath = "/menubar/Analysis";
2834     GtkActionEntry entry;
2835 
2836     action_entry_init(&entry);
2837     entry.name = "mnlprobs";
2838     entry.label = _("Outcome probabilities");
2839     entry.callback = G_CALLBACK(mnl_probs_callback);
2840     vwin_menu_add_item(vwin, mpath, &entry);
2841 }
2842 
dw_pval_ok(const MODEL * pmod)2843 static int dw_pval_ok (const MODEL *pmod)
2844 {
2845     if (na(pmod->dw)) {
2846 	return 0;
2847     } else if (pmod->ci == OLS) {
2848 	return 1;
2849     } else if (pmod->ci == PANEL) {
2850 	return panel_DW_pval_ok(pmod);
2851     } else {
2852 	return 0;
2853     }
2854 }
2855 
get_ci_and_opt(const gchar * s,int * ci,gretlopt * opt)2856 static void get_ci_and_opt (const gchar *s, int *ci, gretlopt *opt)
2857 {
2858     char c, word[9];
2859 
2860     sscanf(s, "%8[^:]:%c", word, &c);
2861     *ci = gretl_command_number(word);
2862     *opt = opt_from_flag((unsigned char) c);
2863 }
2864 
set_tests_menu_state(GtkUIManager * ui,const MODEL * pmod)2865 static void set_tests_menu_state (GtkUIManager *ui, const MODEL *pmod)
2866 {
2867     gretlopt opt;
2868     char path[128];
2869     const gchar *s;
2870     int i, n, ci;
2871 
2872     if (pmod->ci == MPOLS) {
2873 	/* can we relax this? */
2874 	flip(ui, "/menubar/Tests", FALSE);
2875 	return;
2876     }
2877 
2878     n = G_N_ELEMENTS(model_test_items);
2879 
2880     for (i=0; i<n; i++) {
2881 	int skip = 0;
2882 
2883 	opt = OPT_NONE;
2884 	s = model_test_items[i].name;
2885 	if (strchr(s, ':')) {
2886 	    get_ci_and_opt(s, &ci, &opt);
2887 	} else if (!strcmp(s, "dwpval")) {
2888 	    sprintf(path, "/menubar/Tests/%s", s);
2889 	    flip(ui, path, dw_pval_ok(pmod));
2890 	    continue;
2891 	} else if (!strcmp(s, "Hsk")) {
2892 	    ci = MODTEST;
2893 	    if (pmod->ci == PANEL && (pmod->opt & OPT_U)) {
2894 		/* random effects: not supported (FIXME?) */
2895 		skip = 1;
2896 	    } else {
2897 		opt = (dataset_is_panel(dataset))? OPT_P : OPT_W;
2898 	    }
2899 	} else {
2900 	    ci = gretl_command_number(s);
2901 	}
2902 	sprintf(path, "/menubar/Tests/%s", s);
2903 	if (skip) {
2904 	    flip(ui, path, FALSE);
2905 	} else {
2906 	    flip(ui, path, model_test_ok(ci, opt, pmod, dataset));
2907 	}
2908     }
2909 
2910     if (pmod->ci == GARCH) {
2911 	flip(ui, "/menubar/Tests/Hsk", FALSE);
2912     } else if (pmod->ci == PROBIT && (pmod->opt & OPT_E)) {
2913 	/* random effects probit */
2914 	flip(ui, "/menubar/Tests/modtest:n", FALSE);
2915     } else if (gretl_is_between_model(pmod)) {
2916 	flip(ui, "/menubar/Tests/coeffsum", FALSE);
2917 	flip(ui, "/menubar/Tests/Hsk", FALSE);
2918     }
2919 }
2920 
set_analysis_menu_state(windata_t * vwin,const MODEL * pmod)2921 static void set_analysis_menu_state (windata_t *vwin, const MODEL *pmod)
2922 {
2923     GtkUIManager *ui = vwin->ui;
2924     gboolean s;
2925 
2926     if (pmod->ci == MLE || pmod->ci == GMM || pmod->ci == BIPROBIT) {
2927 	/* can we relax some of this later? */
2928 	flip(ui, "/menubar/Analysis/DisplayAFR", FALSE);
2929 	flip(ui, "/menubar/Analysis/Forecasts", FALSE);
2930     } else if (pmod->ci == LOGIT && gretl_model_get_int(pmod, "multinom")) {
2931 	/* relax this? */
2932 	flip(ui, "/menubar/Analysis/Forecasts", FALSE);
2933 	add_multinomial_probs_item(vwin);
2934     } else if (pmod->ci == PROBIT && (pmod->opt & OPT_E)) {
2935 	/* random effects probit */
2936 	flip(ui, "/menubar/Analysis/Forecasts", FALSE);
2937     }
2938 
2939     if (pmod->ncoeff == 1) {
2940 	flip(ui, "/menubar/Analysis/ConfEllipse", FALSE);
2941     }
2942 
2943     if (pmod->ci == DPANEL || (pmod->ci == PANEL && !(pmod->opt & OPT_P))) {
2944 	flip(ui, "/menubar/Analysis/Forecasts", FALSE);
2945     }
2946 
2947     if (pmod->ci != OLS || !pmod->ifc || na(pmod->ess) || na(pmod->tss)) {
2948 	flip(ui, "/menubar/Analysis/ANOVA", FALSE);
2949     }
2950 
2951     if (!bootstrap_ok(pmod->ci)) {
2952 	flip(ui, "/menubar/Analysis/Bootstrap", FALSE);
2953     }
2954 
2955     if (gretl_model_get_int(pmod, "null-model")) {
2956 	flip(ui, "/menubar/Analysis/ConfIntervals", FALSE);
2957 	flip(ui, "/menubar/Analysis/Covariance", FALSE);
2958     }
2959 
2960     s = model_test_ok(VIF, OPT_NONE, pmod, dataset) ||
2961 	pmod->vcv != NULL;
2962     flip(ui, "/menubar/Analysis/Collinearity", s);
2963 
2964     if (!model_test_ok(LEVERAGE, OPT_NONE, pmod, dataset)) {
2965 	flip(ui, "/menubar/Analysis/Leverage", FALSE);
2966     }
2967 }
2968 
arma_x12_menu_mod(windata_t * vwin)2969 static void arma_x12_menu_mod (windata_t *vwin)
2970 {
2971     flip(vwin->ui, "/menubar/Analysis/Covariance", FALSE);
2972     add_x12_output_menu_item(vwin);
2973 }
2974 
rq_coeff_intervals_mod(windata_t * vwin)2975 static void rq_coeff_intervals_mod (windata_t *vwin)
2976 {
2977     flip(vwin->ui, "/menubar/Analysis/ConfIntervals", FALSE);
2978 }
2979 
midas_plot_callback(GtkAction * action,gpointer p)2980 static void midas_plot_callback (GtkAction *action, gpointer p)
2981 {
2982     windata_t *vwin = (windata_t *) p;
2983     MODEL *pmod = vwin->data;
2984     gretl_matrix *C = NULL;
2985     int err;
2986 
2987     if (pmod == NULL) return;
2988 
2989     C = gretl_model_get_data(pmod, "midas_coeffs");
2990 
2991     if (C != NULL) {
2992 	const char *literal =
2993 	    "{set title 'MIDAS coefficients';"
2994 	    " set xlabel 'high-frequency lag';"
2995 	    " set ylabel '';}";
2996 
2997 	err = matrix_plot(C, NULL, literal,  OPT_P | OPT_S | OPT_G);
2998 	gui_graph_handler(err);
2999     }
3000 }
3001 
arma_spectrum_callback(GtkAction * action,gpointer p)3002 static void arma_spectrum_callback (GtkAction *action, gpointer p)
3003 {
3004     windata_t *vwin = (windata_t *) p;
3005     MODEL *pmod = (MODEL *) vwin->data;
3006     int err;
3007 
3008     err = arma_spectrum_plot(pmod, dataset, OPT_NONE);
3009 
3010     gui_graph_handler(err);
3011 }
3012 
3013 #define intervals_model(m) (m->ci == LAD && \
3014 			    gretl_model_get_data(m, "coeff_intervals"))
3015 
adjust_model_menu_state(windata_t * vwin,const MODEL * pmod)3016 static void adjust_model_menu_state (windata_t *vwin, const MODEL *pmod)
3017 {
3018     /* disallow saving an already-saved model */
3019     if (is_session_model((void *) pmod)) {
3020 	set_model_save_state(vwin, FALSE);
3021     }
3022 
3023     if (RQ_SPECIAL_MODEL(pmod)) {
3024 	/* can we relax this later? */
3025 	flip(vwin->ui, "/menubar/Tests", FALSE);
3026 	flip(vwin->ui, "/menubar/Save", FALSE);
3027 	flip(vwin->ui, "/menubar/Analysis", FALSE);
3028 	return;
3029     }
3030 
3031     set_tests_menu_state(vwin->ui, pmod);
3032     set_analysis_menu_state(vwin, pmod);
3033 
3034     if (intervals_model(pmod)) {
3035 	rq_coeff_intervals_mod(vwin);
3036     }
3037 
3038     if (pmod->ci == ARMA && arma_by_x12a(pmod)) {
3039 	arma_x12_menu_mod(vwin);
3040     }
3041 
3042     if (pmod->ci == MLE || pmod->ci == GMM || pmod->ci == BIPROBIT) {
3043 	/* can we relax this later? */
3044 	flip(vwin->ui, "/menubar/Graphs", FALSE);
3045     } else if (gretl_is_between_model(pmod) &&
3046 	       pmod->dataset == NULL) {
3047 	flip(vwin->ui, "/menubar/Graphs", FALSE);
3048     }
3049 
3050     if (pmod->ci == GMM || pmod->ci == BIPROBIT) {
3051 	/* FIXME? */
3052 	flip(vwin->ui, "/menubar/Save", FALSE);
3053     }
3054 }
3055 
3056 static GtkActionEntry model_data_base_items[] = {
3057     { "bundle", NULL, N_("_Model as bundle"), NULL, NULL,
3058       G_CALLBACK(model_stat_callback) },
3059     { "yhat", NULL, N_("_Fitted values"), NULL, NULL,
3060       G_CALLBACK(fit_resid_callback) },
3061     { "uhat", NULL, N_("_Residuals"), NULL, NULL,
3062       G_CALLBACK(fit_resid_callback) },
3063     { "uhat2", NULL, N_("_Squared residuals"), NULL, NULL,
3064       G_CALLBACK(fit_resid_callback) }
3065 };
3066 
3067 static GtkActionEntry ess_items[] = {
3068     { "ess", NULL, N_("_Error sum of squares"), NULL, NULL,
3069       G_CALLBACK(model_stat_callback) },
3070     { "se", NULL, N_("_Standard error of the regression"), NULL, NULL,
3071       G_CALLBACK(model_stat_callback) }
3072 };
3073 
3074 static GtkActionEntry r_squared_items[] = {
3075     { "rsq", NULL, N_("_R-squared"), NULL, NULL, G_CALLBACK(model_stat_callback) },
3076     { "trsq", NULL, N_("_T*R-squared"), NULL, NULL, G_CALLBACK(model_stat_callback) }
3077 };
3078 
3079 static GtkActionEntry lnl_data_items[] = {
3080     { "lnL", NULL, N_("_Log likelihood"), NULL, NULL,
3081       G_CALLBACK(model_stat_callback) }
3082 };
3083 
3084 static GtkActionEntry criteria_items[] = {
3085     { "AIC", NULL, N_("_Akaike Information Criterion"), NULL, NULL,
3086       G_CALLBACK(model_stat_callback) },
3087     { "BIC", NULL, N_("_Bayesian Information Criterion"), NULL, NULL,
3088       G_CALLBACK(model_stat_callback) },
3089     { "HQC", NULL, N_("_Hannan-Quinn Information Criterion"), NULL, NULL,
3090       G_CALLBACK(model_stat_callback) }
3091 };
3092 
3093 static GtkActionEntry garch_data_items[] = {
3094     { "h", NULL, N_("_Predicted error variance"), NULL, NULL,
3095       G_CALLBACK(fit_resid_callback)
3096     }
3097 };
3098 
3099 static GtkActionEntry fixed_effects_data_items[] = {
3100     { "ahat", NULL, N_("Per-unit _constants"), NULL, NULL,
3101       G_CALLBACK(fit_resid_callback)
3102     }
3103 };
3104 
3105 static GtkActionEntry random_effects_data_items[] = {
3106     { "ahat", NULL, N_("Individual effects"), NULL, NULL,
3107       G_CALLBACK(fit_resid_callback)
3108     }
3109 };
3110 
3111 static GtkActionEntry define_var_items[] = {
3112     /* Under Save; Sep wanted */
3113     { "NewVar", NULL, N_("Define _new variable..."), NULL, NULL,
3114       G_CALLBACK(model_genr_callback) }
3115 };
3116 
criteria_available(const MODEL * pmod)3117 static int criteria_available (const MODEL *pmod)
3118 {
3119     int i;
3120 
3121     for (i=0; i<C_MAX; i++) {
3122 	if (na(pmod->criterion[i])) {
3123 	    return 0;
3124 	}
3125     }
3126 
3127     return 1;
3128 }
3129 
add_model_dataset_items(windata_t * vwin)3130 static void add_model_dataset_items (windata_t *vwin)
3131 {
3132     const gchar *path = "/menubar/Save";
3133     MODEL *pmod = vwin->data;
3134 
3135     vwin_menu_add_items(vwin, path, model_data_base_items,
3136 			G_N_ELEMENTS(model_data_base_items));
3137 
3138     if (gretl_model_get_data(pmod, "ahat") != NULL) {
3139 	if (pmod->opt & OPT_U) {
3140 	    vwin_menu_add_items(vwin, path, random_effects_data_items,
3141 				G_N_ELEMENTS(random_effects_data_items));
3142 	} else {
3143 	    vwin_menu_add_items(vwin, path, fixed_effects_data_items,
3144 				G_N_ELEMENTS(fixed_effects_data_items));
3145 	}
3146     }
3147 
3148     if (pmod->ci != GARCH && !(pmod->ci == LOGIT && (pmod->opt & OPT_M))) {
3149 	vwin_menu_add_items(vwin, path, ess_items,
3150 			    G_N_ELEMENTS(ess_items));
3151     }
3152 
3153     if (!ML_ESTIMATOR(pmod->ci) && pmod->ci != LAD && !na(pmod->rsq)) {
3154 	vwin_menu_add_items(vwin, path, r_squared_items,
3155 			    G_N_ELEMENTS(r_squared_items));
3156     }
3157 
3158     if (!na(pmod->lnL)) {
3159 	vwin_menu_add_items(vwin, path, lnl_data_items,
3160 			    G_N_ELEMENTS(lnl_data_items));
3161     }
3162 
3163     if (criteria_available(pmod)) {
3164 	vwin_menu_add_items(vwin, path, criteria_items,
3165 			    G_N_ELEMENTS(criteria_items));
3166     }
3167 
3168     if (pmod->ci == GARCH) {
3169 	vwin_menu_add_items(vwin, path, garch_data_items,
3170 			    G_N_ELEMENTS(garch_data_items));
3171     }
3172 
3173     vwin_menu_add_separator(vwin, path);
3174 
3175     vwin_menu_add_items(vwin, path, define_var_items,
3176 			G_N_ELEMENTS(define_var_items));
3177 }
3178 
add_model_tex_items(windata_t * vwin)3179 static void add_model_tex_items (windata_t *vwin)
3180 {
3181     MODEL *pmod = (MODEL *) vwin->data;
3182     int eqn_ok = command_ok_for_model(EQNPRINT, 0, pmod);
3183     GtkActionGroup *actions;
3184     GError *err = NULL;
3185     int imod = 0;
3186 
3187     gtk_ui_manager_add_ui_from_string(vwin->ui, model_tex_ui, -1, &err);
3188 
3189     if (err != NULL) {
3190 	g_message("building LaTeX menu failed: %s", err->message);
3191 	g_error_free(err);
3192 	return;
3193     }
3194 
3195     actions = gtk_action_group_new("ModelTeX");
3196     gtk_action_group_set_translation_domain(actions, "gretl");
3197     gtk_action_group_add_actions(actions, model_tex_items,
3198 				 G_N_ELEMENTS(model_tex_items),
3199 				 vwin);
3200     gtk_action_group_add_radio_actions(actions, tex_eqn_items,
3201 				       G_N_ELEMENTS(tex_eqn_items),
3202 				       (get_tex_eqn_opt() == OPT_T),
3203 				       G_CALLBACK(set_tex_eqn_opt),
3204 				       vwin);
3205     gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
3206     g_object_unref(actions);
3207 
3208     if (intervals_model(pmod)) {
3209 	eqn_ok = 0;
3210 	imod = 1;
3211     }
3212 
3213     if (!eqn_ok || pmod->errcode) {
3214 	flip(vwin->ui, "/menubar/LaTeX/TeXView/EqnView", FALSE);
3215 	flip(vwin->ui, "/menubar/LaTeX/TeXCopy/EqnCopy", FALSE);
3216 	flip(vwin->ui, "/menubar/LaTeX/TeXSave/EqnSave", FALSE);
3217 	flip(vwin->ui, "/menubar/LaTeX/EqnOpts", FALSE);
3218     }
3219 
3220     if (imod) {
3221 	flip(vwin->ui, "/menubar/LaTeX/TabOpts", FALSE);
3222     }
3223 }
3224 
3225 /* dummy placeholder, for when TeX is not supported */
3226 
add_missing_tex_items(windata_t * vwin)3227 static void add_missing_tex_items (windata_t *vwin)
3228 {
3229     GtkActionGroup *actions;
3230     GError *err = NULL;
3231 
3232     gtk_ui_manager_add_ui_from_string(vwin->ui, missing_tex_ui, -1, &err);
3233     if (err != NULL) {
3234 	g_message("building menus failed: %s", err->message);
3235 	g_error_free(err);
3236 	return;
3237     }
3238 
3239     actions = gtk_action_group_new("MissingTeX");
3240     gtk_action_group_add_actions(actions, missing_tex_items,
3241 				 G_N_ELEMENTS(missing_tex_items),
3242 				 vwin);
3243     gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
3244     g_object_unref(actions);
3245 
3246     flip(vwin->ui, "/menubar/LaTeX", FALSE);
3247 }
3248 
3249 #define VNAMELEN2 (2*VNAMELEN)
3250 
add_vars_to_plot_menu(windata_t * vwin)3251 static void add_vars_to_plot_menu (windata_t *vwin)
3252 {
3253     GtkActionEntry entry;
3254     const gchar *mpath[] = {
3255 	"/menubar/Graphs/ResidPlot",
3256 	"/menubar/Graphs/FittedActualPlot"
3257     };
3258     MODEL *pmod = vwin->data;
3259     char tmp[VNAMELEN2], aname[VNAMELEN];
3260     gchar *alabel;
3261     int *xlist;
3262     int v1, v2;
3263     int i, j;
3264 
3265     action_entry_init(&entry);
3266 
3267     /* non-time series: residual boxplot */
3268     if (!dataset_is_time_series(dataset)) {
3269 	entry.label = _("_Boxplot");
3270 	entry.name = "r:box";
3271 	entry.callback = G_CALLBACK(resid_plot);
3272 	vwin_menu_add_item(vwin, mpath[0], &entry);
3273     }
3274 
3275     xlist = gretl_model_get_x_list(pmod);
3276 
3277     for (i=0; i<2; i++) {
3278 	/* plot against time/obs number */
3279 	if (dataset_is_time_series(dataset)) {
3280 	    entry.label = _("_Against time");
3281 	} else {
3282 	    entry.label = _("By _observation number");
3283 	}
3284 	entry.name = (i == 0)? "r:byobs" : "f:byobs";
3285 	entry.callback = (i == 0)? G_CALLBACK(resid_plot) :
3286 	    G_CALLBACK(fit_actual_plot);
3287 	vwin_menu_add_item(vwin, mpath[i], &entry);
3288 
3289 	if (pmod->ci == NLS ||
3290 	    pmod->ci == MLE ||
3291 	    pmod->ci == GMM ||
3292 	    pmod->ci == PANEL) {
3293 	    continue;
3294 	}
3295 
3296 	/* if doing resid plot, put dependent var in menu */
3297 	if (i == 0) {
3298 	    v1 = gretl_model_get_depvar(pmod);
3299 	    if (v1 > 0) {
3300 		sprintf(aname, "r:xvar %d", v1); /* FIXME */
3301 		double_underscores(tmp, dataset->varname[v1]);
3302 		alabel = g_strdup_printf(_("_Against %s"), tmp);
3303 		entry.name = aname;
3304 		entry.label = alabel;
3305 		entry.callback = G_CALLBACK(resid_plot);
3306 		vwin_menu_add_item(vwin, mpath[0], &entry);
3307 		g_free(alabel);
3308 	    }
3309 	}
3310 
3311 	if (xlist != NULL) {
3312 	    /* put the independent vars on the menu list */
3313 	    for (j=1; j<=xlist[0]; j++) {
3314 		v1 = xlist[j];
3315 		if (v1 == 0) {
3316 		    continue;
3317 		}
3318 		if (!strcmp(dataset->varname[v1], "time")) {
3319 		    continue;
3320 		}
3321 		sprintf(aname, "%c:xvar %d", (i == 0)? 'r' : 'f', v1);
3322 		double_underscores(tmp, dataset->varname[v1]);
3323 		alabel = g_strdup_printf(_("_Against %s"), tmp);
3324 		entry.name = aname;
3325 		entry.label = alabel;
3326 		entry.callback = (i == 0)? G_CALLBACK(resid_plot) :
3327 		    G_CALLBACK(fit_actual_plot);
3328 		vwin_menu_add_item(vwin, mpath[i], &entry);
3329 		g_free(alabel);
3330 	    }
3331 	}
3332 
3333 	if (i == 1) {
3334 	    /* fitted values: offer Theil-type scatterplot */
3335 	    entry.name = "f:theil";
3336 	    entry.label = _("Actual vs. Fitted");
3337 	    entry.callback = G_CALLBACK(fit_actual_plot);
3338 	    vwin_menu_add_item(vwin, mpath[i], &entry);
3339 	}
3340     }
3341 
3342     /* time series models: residual correlogram, spectrum */
3343     if (dataset_is_time_series(dataset)) {
3344 	vwin_menu_add_separator(vwin, "/menubar/Graphs");
3345 	entry.name = "Correlogram";
3346 	entry.label = _("Residual _correlogram");
3347 	entry.callback = G_CALLBACK(residual_correlogram_callback);
3348 	vwin_menu_add_item(vwin, "/menubar/Graphs", &entry);
3349 	entry.name = "Spectrum";
3350 	entry.label = _("Residual _periodogram");
3351 	entry.callback = G_CALLBACK(residual_periodogram_callback);
3352 	vwin_menu_add_item(vwin, "/menubar/Graphs", &entry);
3353 	if (pmod->ci == ARMA && gretl_model_get_data(pmod, "ainfo") != NULL) {
3354 	    entry.name = "ARMAspectrum";
3355 	    entry.label = _("_Spectrum vs sample periodogram");
3356 	    entry.callback = G_CALLBACK(arma_spectrum_callback);
3357 	    vwin_menu_add_item(vwin, "/menubar/Graphs", &entry);
3358 	} else if (gretl_model_get_data(pmod, "midas_coeffs") != NULL) {
3359 	    entry.name = "MIDAScoeffs";
3360 	    entry.label = _("_MIDAS coefficients");
3361 	    entry.callback = G_CALLBACK(midas_plot_callback);
3362 	    vwin_menu_add_item(vwin, "/menubar/Graphs", &entry);
3363 	}
3364     } else {
3365 	vwin_menu_add_separator(vwin, "/menubar/Graphs");
3366     }
3367 
3368     /* residual Q-Q plot */
3369     entry.name = "QQPlot";
3370     entry.label = _("Residual _Q-Q plot");
3371     entry.callback = G_CALLBACK(residual_qq_plot);
3372     vwin_menu_add_item(vwin, "/menubar/Graphs", &entry);
3373 
3374     /* 3-D fitted versus actual plot? */
3375     if (xlist != NULL) {
3376 	int parnames = pmod->dataset != NULL;
3377 
3378 	v1 = v2 = -1;
3379 	if (pmod->ifc && xlist[0] == 3) {
3380 	    v1 = parnames ? 1 : xlist[2];
3381 	    v2 = parnames ? 2 : xlist[3];
3382 	} else if (!pmod->ifc && xlist[0] == 2) {
3383 	    v1 = parnames ? 0 : xlist[1];
3384 	    v2 = parnames ? 1 : xlist[2];
3385 	}
3386 	if (v1 >= 0 && v2 >= 0) {
3387 	    char tmp2[VNAMELEN2];
3388 
3389 	    if (parnames) {
3390 		char pname[VNAMELEN];
3391 
3392 		gretl_model_get_param_name(pmod, pmod->dataset,
3393 					   v1, pname);
3394 		double_underscores(tmp, pname);
3395 		gretl_model_get_param_name(pmod, pmod->dataset,
3396 					   v2, pname);
3397 		double_underscores(tmp2, pname);
3398 	    } else {
3399 		double_underscores(tmp, dataset->varname[v1]);
3400 		double_underscores(tmp2, dataset->varname[v2]);
3401 	    }
3402 	    vwin_menu_add_separator(vwin, mpath[1]);
3403 	    alabel = g_strdup_printf(_("_Against %s and %s"), tmp, tmp2);
3404 	    entry.name = "splot";
3405 	    entry.label = alabel;
3406 	    entry.callback = G_CALLBACK(fit_actual_splot);
3407 	    vwin_menu_add_item(vwin, mpath[1], &entry);
3408 	    g_free(alabel);
3409 	}
3410     }
3411 
3412     free(xlist);
3413 }
3414 
plot_dummy_call(GtkRadioAction * action,GtkRadioAction * current,windata_t * vwin)3415 static void plot_dummy_call (GtkRadioAction *action,
3416 			     GtkRadioAction *current,
3417 			     windata_t *vwin)
3418 {
3419     vwin->active_var = gtk_radio_action_get_current_value(action);
3420 }
3421 
radio_action_init(GtkRadioActionEntry * a)3422 static void radio_action_init (GtkRadioActionEntry *a)
3423 {
3424     a->stock_id = NULL;
3425     a->accelerator = NULL;
3426     a->tooltip = NULL;
3427 }
3428 
add_dummies_to_plot_menu(windata_t * vwin)3429 static void add_dummies_to_plot_menu (windata_t *vwin)
3430 {
3431     GtkActionEntry item;
3432     GtkRadioActionEntry *items;
3433     MODEL *pmod = vwin->data;
3434     const gchar *gpath = "/menubar/Graphs/ResidPlot";
3435     const gchar *spath = "/menubar/Graphs/ResidPlot/Separation";
3436     char tmp[VNAMELEN2];
3437     int *dlist = NULL;
3438     int i, vi, ndums;
3439 
3440     /* make a list of dummy independent variables */
3441     for (i=2; i<=pmod->list[0]; i++) {
3442 	vi = pmod->list[i];
3443 	if (vi == LISTSEP) {
3444 	    break;
3445 	} else if (vi > 0 && vi < dataset->v &&
3446 	    gretl_isdummy(dataset->t1, dataset->t2, dataset->Z[vi])) {
3447 	    gretl_list_append_term(&dlist, vi);
3448 	}
3449     }
3450 
3451     if (dlist == NULL) {
3452 	return;
3453     }
3454 
3455     ndums = dlist[0];
3456     items = malloc((ndums + 1) * sizeof *items);
3457     if (items == NULL) {
3458 	free(dlist);
3459 	return;
3460     }
3461 
3462     /* add separator */
3463     vwin_menu_add_separator(vwin, gpath);
3464 
3465     /* add menu branch */
3466     action_entry_init(&item);
3467     item.name = "Separation";
3468     item.label = _("Separation");
3469     vwin_menu_add_menu(vwin, gpath, &item);
3470 
3471     /* configure "none" radio option */
3472     radio_action_init(&items[0]);
3473     items[0].name = "none";
3474     items[0].label = _("none");
3475     items[0].value = 0;
3476 
3477     /* put the dummy independent vars on the menu list */
3478     for (i=1; i<=dlist[0]; i++) {
3479 	vi = dlist[i];
3480 	radio_action_init(&items[i]);
3481 	double_underscores(tmp, dataset->varname[vi]);
3482 	items[i].name = g_strdup_printf("dum %d", vi);
3483 	items[i].label = g_strdup_printf(_("By %s"), tmp);
3484 	items[i].value = vi;
3485     }
3486 
3487     vwin_menu_add_radios(vwin, spath, items, ndums + 1, 0,
3488 			 G_CALLBACK(plot_dummy_call));
3489 
3490     for (i=1; i<=dlist[0]; i++) {
3491 	g_free((gchar *) items[i].name);
3492 	g_free((gchar *) items[i].label);
3493     }
3494 
3495     free(items);
3496     free(dlist);
3497 }
3498 
varnum_from_action(GtkAction * action,int * i)3499 static void varnum_from_action (GtkAction *action, int *i)
3500 {
3501     const gchar *s = gtk_action_get_name(action);
3502 
3503     sscanf(s, "%*s %d", i);
3504 }
3505 
tau_plot_call(GtkAction * action,gpointer p)3506 static void tau_plot_call (GtkAction *action, gpointer p)
3507 {
3508     windata_t *vwin = (windata_t *) p;
3509     MODEL *pmod = (MODEL *) vwin->data;
3510     int v, err;
3511 
3512     varnum_from_action(action, &v);
3513     err = plot_tau_sequence(pmod, dataset, v);
3514     gui_graph_handler(err);
3515 }
3516 
add_tau_plot_menu(windata_t * vwin)3517 static void add_tau_plot_menu (windata_t *vwin)
3518 {
3519     GtkActionEntry item;
3520     MODEL *pmod = vwin->data;
3521     char tmp[VNAMELEN2], aname[VNAMELEN];
3522     int i;
3523 
3524     action_entry_init(&item);
3525     item.name = "TauMenu";
3526     item.label = _("tau sequence");
3527     vwin_menu_add_menu(vwin, "/menubar/Graphs", &item);
3528 
3529     item.callback = G_CALLBACK(tau_plot_call);
3530 
3531     /* put the independent vars on the menu list */
3532     for (i=2; i<=pmod->list[0]; i++) {
3533 	sprintf(aname, "tauseq %d", i - 2);
3534 	double_underscores(tmp, dataset->varname[pmod->list[i]]);
3535 	item.name = aname;
3536 	item.label = tmp;
3537 	vwin_menu_add_item(vwin, "/menubar/Graphs/TauMenu", &item);
3538     }
3539 
3540     /* and disable what we can't (yet) show */
3541     flip(vwin->ui, "/menubar/Graphs/ResidPlot", FALSE);
3542     flip(vwin->ui, "/menubar/Graphs/FittedActualPlot", FALSE);
3543 }
3544 
x12_output_callback(GtkAction * action,gpointer p)3545 static void x12_output_callback (GtkAction *action, gpointer p)
3546 {
3547     windata_t *vwin = (windata_t *) p;
3548     MODEL *pmod = vwin->data;
3549     char *fname;
3550 
3551     if (pmod == NULL) return;
3552 
3553     fname = gretl_model_get_data(pmod, "x12a_output");
3554 
3555     if (fname != NULL) {
3556 	char *p = strrchr(fname, '.');
3557 
3558 	if (p != NULL && strlen(p) == 7) {
3559 	    gchar *tmp = g_strdup(fname);
3560 
3561 	    sprintf(p, ".%d", pmod->ID);
3562 	    gretl_rename(tmp, fname);
3563 	    g_free(tmp);
3564 	}
3565 	view_file(fname, 0, 0, 78, 350, VIEW_FILE);
3566     }
3567 }
3568 
get_model_ui(void)3569 static gchar *get_model_ui (void)
3570 {
3571     gchar *ui = NULL;
3572     gchar *fname;
3573     int err;
3574 
3575     fname = g_strdup_printf("%sui%cgretlmodel.xml", gretl_home(), SLASH);
3576     err = gretl_file_get_contents(fname, &ui, NULL);
3577     g_free(fname);
3578 
3579     return err ? NULL : ui;
3580 }
3581 
set_up_model_view_menu(windata_t * vwin)3582 static void set_up_model_view_menu (windata_t *vwin)
3583 {
3584     static gchar *model_ui;
3585     MODEL *pmod = (MODEL *) vwin->data;
3586     GtkActionGroup *actions;
3587     GtkWidget *toplevel;
3588     GError *err = NULL;
3589 
3590     if (model_ui == NULL) {
3591 	model_ui = get_model_ui();
3592 	if (model_ui == NULL) {
3593 	    errbox("building menus failed");
3594 	    return;
3595 	}
3596     }
3597 
3598     actions = gtk_action_group_new("ModelActions");
3599     gtk_action_group_set_translation_domain(actions, "gretl");
3600 
3601     gtk_action_group_add_actions(actions, model_items,
3602 				 G_N_ELEMENTS(model_items),
3603 				 vwin);
3604     gtk_action_group_add_actions(actions, model_test_items,
3605 				 G_N_ELEMENTS(model_test_items),
3606 				 vwin);
3607 
3608     vwin->ui = gtk_ui_manager_new();
3609     gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
3610     g_object_unref(actions);
3611 
3612     gtk_ui_manager_add_ui_from_string(vwin->ui, model_ui, -1, &err);
3613     if (err != NULL) {
3614 	g_message("building menus failed: %s", err->message);
3615 	g_error_free(err);
3616     }
3617 
3618     if (pmod->ci != MLE && pmod->ci != GMM && pmod->ci != BIPROBIT) {
3619 	if (RQ_SPECIAL_MODEL(pmod)) {
3620 	    add_tau_plot_menu(vwin);
3621 	} else {
3622 	    add_vars_to_plot_menu(vwin);
3623 	}
3624 	add_model_dataset_items(vwin);
3625     }
3626 
3627     /* heteroskedasticity tests: the permissible options vary
3628        depending on the nature of the model
3629     */
3630 
3631     if (dataset_is_panel(dataset)) {
3632 	if (pmod->ci == OLS) {
3633 	    vwin_menu_add_items(vwin, "/menubar/Tests/Hsk",
3634 				panel_hsk_items,
3635 				G_N_ELEMENTS(panel_hsk_items));
3636 	} else if (pmod->ci == PANEL && (pmod->opt & OPT_F)) {
3637 	    /* fixed effects */
3638 	    vwin_menu_add_items(vwin, "/menubar/Tests/Hsk",
3639 				panel_hsk_items + 1, 1);
3640 	} else if (0 && pmod->ci == PANEL && (pmod->opt & OPT_U)) {
3641 	    /* random effects: is this OK?? */
3642 	    vwin_menu_add_items(vwin, "/menubar/Tests/Hsk",
3643 				panel_hsk_items + 1, 1);
3644 	}
3645     } else if (pmod->ci == IVREG) {
3646 	vwin_menu_add_items(vwin, "/menubar/Tests/Hsk",
3647 			    ivreg_hsk_items,
3648 			    G_N_ELEMENTS(ivreg_hsk_items));
3649     } else if (model_test_ok(MODTEST, OPT_W, pmod, dataset)) {
3650 	vwin_menu_add_items(vwin, "/menubar/Tests/Hsk",
3651 			    base_hsk_items,
3652 			    G_N_ELEMENTS(base_hsk_items));
3653 	if (pmod->ncoeff == 1 || (pmod->ifc && pmod->ncoeff == 2)) {
3654 	    flip(vwin->ui, "/menubar/Tests/Hsk/WhiteSquares", FALSE);
3655 	}
3656     }
3657 
3658     maybe_add_packages_to_model_menus(vwin);
3659 
3660     if (latex_is_ok() && !pmod->errcode && !RQ_SPECIAL_MODEL(pmod)) {
3661 	add_model_tex_items(vwin);
3662     } else {
3663 	add_missing_tex_items(vwin);
3664     }
3665 
3666     if (!text_equation_ok(pmod)) {
3667 	flip(vwin->ui, "/menubar/File/TextEqn", FALSE);
3668     }
3669 
3670     if (pmod->ci != ARMA && pmod->ci != GARCH &&
3671 	pmod->ci != NLS && pmod->ci != MLE && pmod->ci != GMM &&
3672 	pmod->ci != PANEL && pmod->ci != DPANEL &&
3673 	pmod->ci != BIPROBIT) {
3674 	add_dummies_to_plot_menu(vwin);
3675     }
3676 
3677     toplevel = vwin_toplevel(vwin);
3678     if (toplevel != NULL) {
3679 	/* FIXME tabbed case? */
3680 	gtk_window_add_accel_group(GTK_WINDOW(toplevel),
3681 				   gtk_ui_manager_get_accel_group(vwin->ui));
3682     }
3683 
3684     vwin->mbar = gtk_ui_manager_get_widget(vwin->ui, "/menubar");
3685 
3686     /* disable some menu items if need be */
3687     adjust_model_menu_state(vwin, pmod);
3688 
3689     g_signal_connect(G_OBJECT(vwin->mbar), "button-press-event",
3690 		     G_CALLBACK(check_model_menu), vwin);
3691 
3692     vwin_pack_toolbar(vwin);
3693 }
3694 
3695 enum {
3696     SYS_DATA_RESIDS,
3697     SYS_DATA_FITTED,
3698     SYS_DATA_SIGMA
3699 };
3700 
sys_data_code(GtkAction * action)3701 static int sys_data_code (GtkAction *action)
3702 {
3703     const gchar *s = gtk_action_get_name(action);
3704 
3705     if (!strcmp(s, "uhat")) {
3706 	return SYS_DATA_RESIDS;
3707     } else if (!strcmp(s, "yhat")) {
3708 	return SYS_DATA_FITTED;
3709     } else if (!strcmp(s, "sigma")) {
3710 	return SYS_DATA_SIGMA;
3711     } else {
3712 	return SYS_DATA_RESIDS;
3713     }
3714 }
3715 
system_data_callback(GtkAction * action,gpointer p)3716 static void system_data_callback (GtkAction *action, gpointer p)
3717 {
3718     windata_t *vwin = (windata_t *) p;
3719     GRETL_VAR *var = NULL;
3720     equation_system *sys = NULL;
3721     const gretl_matrix *M = NULL;
3722     gchar *wtitle = NULL;
3723     PRN *prn;
3724     int code, k = 0;
3725     int err = 0;
3726 
3727     if (vwin->role == SYSTEM) {
3728 	sys = (equation_system *) vwin->data;
3729     } else {
3730 	var = (GRETL_VAR *) vwin->data;
3731     }
3732 
3733     if ((var == NULL && sys == NULL) || bufopen(&prn)) {
3734 	return;
3735     }
3736 
3737     code = sys_data_code(action);
3738 
3739     if (code == SYS_DATA_SIGMA) {
3740 	if (var != NULL) {
3741 	    wtitle = g_strdup(_("gretl: VAR covariance matrix"));
3742 	    err = gretl_VAR_print_sigma(var, prn);
3743 	} else {
3744 	    wtitle = g_strdup(_("gretl: system covariance matrix"));
3745 	    err = system_print_sigma(sys, prn);
3746 	}
3747     } else if (code == SYS_DATA_RESIDS || code == SYS_DATA_FITTED) {
3748 	const char *titles[] = {
3749 	    N_("System residuals"),
3750 	    N_("System fitted values")
3751 	};
3752 	const char *title;
3753 	const char **heads = NULL;
3754 
3755 	if (var != NULL) {
3756 	    /* fitted values matrix not currently available */
3757 	    M = (code == SYS_DATA_RESIDS)? gretl_VAR_get_residual_matrix(var) :
3758 		NULL;
3759 	} else {
3760 	    M = (code == SYS_DATA_RESIDS)? sys->E : sys->yhat;
3761 	}
3762 
3763 	if (M == NULL) {
3764 	    err = E_DATA;
3765 	} else {
3766 	    k = gretl_matrix_cols(M);
3767 	    heads = malloc(k * sizeof *heads);
3768 	    if (heads == NULL) {
3769 		err = E_ALLOC;
3770 	    }
3771 	}
3772 
3773 	if (!err) {
3774 	    int i, v;
3775 
3776 	    for (i=0; i<k && !err; i++) {
3777 		v = (var != NULL)? gretl_VAR_get_variable_number(var, i) :
3778 		    sys->lists[i][1];
3779 		if (v < 0 || v >= dataset->v) {
3780 		    err = E_DATA;
3781 		} else {
3782 		    heads[i] = dataset->varname[v];
3783 		}
3784 	    }
3785 	}
3786 
3787 	if (!err) {
3788 	    title = (code == SYS_DATA_RESIDS)? titles[0] : titles[1];
3789 	    wtitle = g_strdup_printf("gretl: %s", _(title));
3790 	    gretl_matrix_print_with_col_heads(M, _(title), heads,
3791 					      dataset, prn);
3792 	}
3793 
3794 	free(heads);
3795     }
3796 
3797     if (err) {
3798 	gui_errmsg(err);
3799 	gretl_print_destroy(prn);
3800     } else {
3801 	/* FIXME: add matrix as saveable data */
3802 	view_buffer(prn, 80, 400, wtitle, PRINT, NULL);
3803     }
3804 
3805     g_free(wtitle);
3806 }
3807 
add_x12_output_menu_item(windata_t * vwin)3808 static void add_x12_output_menu_item (windata_t *vwin)
3809 {
3810     const gchar *mpath = "/menubar/Analysis";
3811     GtkActionEntry entry;
3812 
3813     vwin_menu_add_separator(vwin, mpath);
3814 
3815     action_entry_init(&entry);
3816     entry.name = "x12aout";
3817     entry.label = _("View X-12-ARIMA output");
3818     entry.callback = G_CALLBACK(x12_output_callback);
3819     vwin_menu_add_item(vwin, mpath, &entry);
3820 }
3821 
3822 #include "up_down.h" /* arrows for buttons below */
3823 
up_down_button(int up)3824 static GtkWidget *up_down_button (int up)
3825 {
3826     GtkWidget *img, *w = gtk_button_new();
3827     GdkPixbuf *pbuf;
3828 
3829     if (up) {
3830 	pbuf = gdk_pixbuf_new_from_inline(-1, up_pixbuf, FALSE, NULL);
3831     } else {
3832 	pbuf = gdk_pixbuf_new_from_inline(-1, down_pixbuf, FALSE, NULL);
3833     }
3834 
3835     img = gtk_image_new_from_pixbuf(pbuf);
3836     gtk_container_add(GTK_CONTAINER(w), img);
3837     g_object_unref(pbuf);
3838 
3839     return w;
3840 }
3841 
set_order_vec(GtkWidget * view)3842 static void set_order_vec (GtkWidget *view)
3843 {
3844     GtkTreeModel *model;
3845     GtkTreeIter iter;
3846     gretl_matrix *m;
3847     int v, i = 0;
3848 
3849     m = g_object_get_data(G_OBJECT(view), "ordvec");
3850     model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
3851 
3852     gtk_tree_model_get_iter_first(model, &iter);
3853     gtk_tree_model_get(model, &iter, 1, &v, -1);
3854     m->val[0] = v;
3855 
3856     while (gtk_tree_model_iter_next(model, &iter)) {
3857 	gtk_tree_model_get(model, &iter, 1, &v, -1);
3858 	m->val[++i] = v;
3859     }
3860 }
3861 
sensitize_up_down(GtkTreeSelection * selection,GtkWidget * view)3862 static void sensitize_up_down (GtkTreeSelection *selection,
3863 			       GtkWidget *view)
3864 {
3865     gretl_matrix *v;
3866     GtkTreeModel *model;
3867     GtkTreeIter iter;
3868     GtkTreePath *path;
3869     GtkWidget *up, *down;
3870     gboolean s;
3871 
3872     model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
3873     v = g_object_get_data(G_OBJECT(view), "ordvec");
3874     up = g_object_get_data(G_OBJECT(view), "up-button");
3875     down = g_object_get_data(G_OBJECT(view), "down-button");
3876 
3877     gtk_tree_model_get_iter_first(model, &iter);
3878     s = gtk_tree_selection_iter_is_selected(selection, &iter);
3879     gtk_widget_set_sensitive(up, !s);
3880 
3881     path = gtk_tree_path_new_from_indices(gretl_vector_get_length(v) - 1,
3882 					  -1);
3883     s = gtk_tree_selection_path_is_selected(selection, path);
3884     gtk_widget_set_sensitive(down, !s);
3885     gtk_tree_path_free(path);
3886 }
3887 
shift_var_up(GtkButton * b,GtkWidget * view)3888 static void shift_var_up (GtkButton *b, GtkWidget *view)
3889 {
3890     GtkTreeSelection *selection;
3891     GtkTreeModel *model;
3892     GtkTreeIter seliter, previter;
3893     GtkTreePath *path;
3894 
3895     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3896     gtk_tree_selection_get_selected(selection, &model, &seliter);
3897     path = gtk_tree_model_get_path(model, &seliter);
3898     if (gtk_tree_path_prev(path)) {
3899 	gtk_tree_model_get_iter(model, &previter, path);
3900 	gtk_list_store_swap(GTK_LIST_STORE(model), &seliter, &previter);
3901 	set_order_vec(view);
3902 	sensitize_up_down(selection, view);
3903     }
3904     gtk_tree_path_free(path);
3905 }
3906 
shift_var_down(GtkButton * b,GtkWidget * view)3907 static void shift_var_down (GtkButton *b, GtkWidget *view)
3908 {
3909     GtkTreeSelection *selection;
3910     GtkTreeModel *model;
3911     GtkTreeIter seliter, nextiter;
3912 
3913     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3914     gtk_tree_selection_get_selected(selection, &model, &seliter);
3915     nextiter = seliter;
3916     if (gtk_tree_model_iter_next(model, &nextiter)) {
3917 	gtk_list_store_swap(GTK_LIST_STORE(model), &seliter, &nextiter);
3918 	set_order_vec(view);
3919 	sensitize_up_down(selection, view);
3920     }
3921 }
3922 
dialog_add_order_selector(GtkWidget * dlg,GRETL_VAR * var,gretl_matrix * ordvec)3923 static void dialog_add_order_selector (GtkWidget *dlg, GRETL_VAR *var,
3924 				       gretl_matrix *ordvec)
3925 {
3926     GtkWidget *b1, *b2;
3927     GtkWidget *vbox, *hbox;
3928     GtkWidget *bbox, *scroller;
3929     GtkTreeViewColumn *column;
3930     GtkCellRenderer *renderer;
3931     GtkTreeSelection *select;
3932     GtkListStore *store;
3933     GtkWidget *view, *lbl;
3934     GtkTreeIter iter;
3935     const char *vname;
3936     int i, j, v;
3937 
3938     vbox = gtk_dialog_get_content_area(GTK_DIALOG(dlg));
3939 
3940     hbox = gtk_hbox_new(FALSE, 5);
3941     lbl = gtk_label_new(_("Cholesky ordering:"));
3942     gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 5);
3943     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
3944 
3945     store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
3946     view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
3947     g_object_set_data(G_OBJECT(view), "ordvec", ordvec);
3948 
3949     renderer = gtk_cell_renderer_text_new();
3950     column = gtk_tree_view_column_new_with_attributes(NULL,
3951 						      renderer,
3952 						      "text", 0,
3953 						      NULL);
3954     gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
3955 
3956     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
3957     gtk_tree_view_set_reorderable(GTK_TREE_VIEW(view), FALSE);
3958 
3959     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
3960 
3961     for (i=0; i<var->neqns; i++) {
3962 	j = gretl_vector_get(ordvec, i);
3963 	v = var->ylist[j+1];
3964 	vname = dataset->varname[v];
3965 	gtk_list_store_append(store, &iter);
3966 	gtk_list_store_set(store, &iter, 0, vname,
3967 			   1, j, -1);
3968     }
3969 
3970     select = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
3971     gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
3972     gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
3973     gtk_tree_selection_select_iter(select, &iter);
3974 
3975     gtk_widget_set_size_request(view, 140 * gui_scale, -1);
3976 
3977     scroller = gtk_scrolled_window_new(NULL, NULL);
3978     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scroller),
3979 				   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3980     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scroller),
3981 					GTK_SHADOW_IN);
3982     gtk_container_add(GTK_CONTAINER(scroller), view);
3983 
3984 #if GTK_MAJOR_VERSION >= 3
3985     gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(scroller),
3986 					      140 * gui_scale);
3987 #endif
3988 
3989     bbox = gtk_vbox_new(FALSE, 5);
3990     b1 = up_down_button(1);
3991     b2 = up_down_button(0);
3992     gtk_box_pack_start(GTK_BOX(bbox), b1, FALSE, FALSE, 5);
3993     gtk_box_pack_start(GTK_BOX(bbox), b2, FALSE, FALSE, 5);
3994     g_signal_connect(G_OBJECT(b1), "clicked",
3995 		     G_CALLBACK(shift_var_up), view);
3996     g_signal_connect(G_OBJECT(b2), "clicked",
3997 		     G_CALLBACK(shift_var_down), view);
3998 
3999     /* FIXME this is ignored in GTK3 ? */
4000     gtk_widget_set_sensitive(b1, FALSE);
4001     g_object_set_data(G_OBJECT(view), "up-button", b1);
4002     g_object_set_data(G_OBJECT(view), "down-button", b2);
4003     g_signal_connect(G_OBJECT(select), "changed",
4004 		     G_CALLBACK(sensitize_up_down), view);
4005 
4006     hbox = gtk_hbox_new(FALSE, 5);
4007     gtk_box_pack_start(GTK_BOX(hbox), scroller, FALSE, FALSE, 5);
4008     gtk_box_pack_start(GTK_BOX(hbox), bbox, FALSE, FALSE, 5);
4009     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
4010 
4011     g_object_unref(store);
4012 }
4013 
4014 static int
impulse_response_setup(GRETL_VAR * var,gretl_matrix * ordvec,int * horizon,int * bootstrap,double * alpha,int * piters,gretlopt * gopt,GtkWidget * parent)4015 impulse_response_setup (GRETL_VAR *var, gretl_matrix *ordvec, int *horizon,
4016 			int *bootstrap, double *alpha, int *piters,
4017 			gretlopt *gopt, GtkWidget *parent)
4018 {
4019     gchar *title;
4020     int h = default_VAR_horizon(dataset);
4021     const char *impulse_opts[] = {
4022 	N_("include bootstrap confidence interval")
4023     };
4024     static int active[] = {0};
4025     GtkWidget *dlg;
4026     double conf = 1 - *alpha;
4027     int iters = *piters;
4028     int resp = -1;
4029 
4030     title = g_strdup_printf("gretl: %s", _("impulse responses"));
4031     dlg = build_checks_dialog(title, NULL,
4032 			      impulse_opts, 1, active, 0, 0, /* check */
4033 			      0, NULL, /* no radios */
4034 			      &h, _("forecast horizon (periods):"),
4035 			      2, dataset->n / 2, IRF_BOOT,
4036 			      parent, &resp);
4037     g_free(title);
4038 
4039     if (dlg == NULL) {
4040 	return -1;
4041     }
4042 
4043     dialog_add_confidence_selector(dlg, &conf, gopt);
4044 
4045     if (iters == 0) {
4046 	iters = libset_get_int(BOOT_ITERS);
4047     }
4048     dialog_add_iters_spinner(dlg, &iters);
4049 
4050     if (ordvec != NULL) {
4051 	dialog_add_order_selector(dlg, var, ordvec);
4052     }
4053     gtk_widget_show_all(dlg);
4054 
4055     if (resp < 0) {
4056 	/* canceled */
4057 	*horizon = 0;
4058     } else {
4059 	*horizon = h;
4060 	*bootstrap = (active[0] > 0);
4061 	if (*bootstrap) {
4062 	    *alpha = 1 - conf;
4063 	    *piters = iters;
4064 	}
4065     }
4066 
4067     return resp;
4068 }
4069 
FEVD_setup(GRETL_VAR * var,gretl_matrix * ordvec,int * horizon,gretlopt * opt,GtkWidget * parent)4070 static int FEVD_setup (GRETL_VAR *var, gretl_matrix *ordvec,
4071 		       int *horizon, gretlopt *opt,
4072 		       GtkWidget *parent)
4073 {
4074     const char *opts[] = {
4075 	N_("stacked bar graph"),
4076 	N_("line graph"),
4077     };
4078     gchar *title;
4079     int h = default_VAR_horizon(dataset);
4080     GtkWidget *dlg;
4081     int lines = 0;
4082     int resp = -1;
4083 
4084     title = g_strdup_printf("gretl: %s", _("Forecast variance decomposition"));
4085 
4086     dlg = build_checks_dialog(title, NULL, opts,
4087 			      0, NULL, 0, 0, /* no checks */
4088 			      2, &lines, /* two radio buttons */
4089 			      &h, _("forecast horizon (periods):"),
4090 			      2, dataset->n / 2, 0,
4091 			      parent, &resp);
4092 
4093     g_free(title);
4094 
4095     if (dlg == NULL) {
4096 	return -1;
4097     }
4098 
4099     if (ordvec != NULL) {
4100 	dialog_add_order_selector(dlg, var, ordvec);
4101     }
4102 
4103     gtk_widget_show_all(dlg);
4104 
4105     if (resp < 0) {
4106 	/* cancelled */
4107 	*horizon = 0;
4108     } else {
4109 	*horizon = h;
4110 	if (!lines) {
4111 	    *opt = OPT_H;
4112 	}
4113     }
4114 
4115     return resp;
4116 }
4117 
impulse_params_from_action(GtkAction * action,int * targ,int * shock)4118 static void impulse_params_from_action (GtkAction *action,
4119 					int *targ,
4120 					int *shock)
4121 {
4122     const gchar *s = gtk_action_get_name(action);
4123 
4124     sscanf(s, "Imp:%d:%d", targ, shock);
4125 }
4126 
FEVD_param_from_action(GtkAction * action,int * targ)4127 static void FEVD_param_from_action (GtkAction *action,
4128 				    int *targ)
4129 {
4130     const gchar *s = gtk_action_get_name(action);
4131 
4132     sscanf(s, "FEVD:%d", targ);
4133 }
4134 
ordvec_default(gretl_matrix * v)4135 static int ordvec_default (gretl_matrix *v)
4136 {
4137     int i, n = gretl_vector_get_length(v);
4138 
4139     for (i=0; i<n; i++) {
4140 	if (v->val[i] != i) {
4141 	    return 0;
4142 	}
4143     }
4144 
4145     return 1;
4146 }
4147 
cholesky_order_vector(GRETL_VAR * var)4148 static gretl_matrix *cholesky_order_vector (GRETL_VAR *var)
4149 {
4150     gretl_matrix *v = NULL;
4151 
4152     if (var->ord != NULL) {
4153 	v = gretl_matrix_copy(var->ord);
4154     } else if (var->neqns > 1) {
4155 	int i;
4156 
4157 	v = gretl_vector_alloc(var->neqns);
4158 	if (v != NULL) {
4159 	    for (i=0; i<var->neqns; i++) {
4160 		v->val[i] = i;
4161 	    }
4162 	}
4163     }
4164 
4165     return v;
4166 }
4167 
FEVD_plot_call(GtkAction * action,gpointer p)4168 static void FEVD_plot_call (GtkAction *action, gpointer p)
4169 {
4170     windata_t *vwin = (windata_t *) p;
4171     GRETL_VAR *var = (GRETL_VAR *) vwin->data;
4172     int targ, horizon;
4173     gretl_matrix *ordvec = NULL;
4174     gretlopt opt = OPT_NONE;
4175     int resp, err;
4176 
4177     FEVD_param_from_action(action, &targ);
4178     ordvec = cholesky_order_vector(var);
4179 
4180     resp = FEVD_setup(var, ordvec, &horizon, &opt, vwin->main);
4181 
4182     if (resp < 0) {
4183 	/* canceled */
4184 	gretl_matrix_free(ordvec);
4185 	return;
4186     }
4187 
4188     if (ordvec != NULL) {
4189 	if (ordvec_default(ordvec)) {
4190 	    gretl_matrix_free(ordvec);
4191 	    gretl_VAR_set_ordering(var, NULL);
4192 	} else {
4193 	    gretl_VAR_set_ordering(var, ordvec);
4194 	}
4195     }
4196 
4197     err = gretl_VAR_plot_FEVD(var, targ, horizon, dataset, opt);
4198     gui_graph_handler(err);
4199 }
4200 
impulse_plot_call(GtkAction * action,gpointer p)4201 static void impulse_plot_call (GtkAction *action, gpointer p)
4202 {
4203     windata_t *vwin = (windata_t *) p;
4204     GRETL_VAR *var = (GRETL_VAR *) vwin->data;
4205     int horizon, bootstrap;
4206     gint shock, targ;
4207     static double alpha = 0.10;
4208     static gretlopt gopt = OPT_NONE;
4209     static int iters = 0;
4210     gretl_matrix *ordvec = NULL;
4211     double this_alpha = 0;
4212     int save_iters;
4213     int resp, err;
4214 
4215     impulse_params_from_action(action, &targ, &shock);
4216     ordvec = cholesky_order_vector(var);
4217     save_iters = libset_get_int(BOOT_ITERS);
4218 
4219     resp = impulse_response_setup(var, ordvec, &horizon, &bootstrap,
4220 				  &alpha, &iters, &gopt, vwin->main);
4221 
4222     if (resp < 0) {
4223 	/* canceled */
4224 	gretl_matrix_free(ordvec);
4225 	return;
4226     }
4227 
4228     if (bootstrap) {
4229 	this_alpha = alpha;
4230     }
4231 
4232     if (ordvec != NULL) {
4233 	if (ordvec_default(ordvec)) {
4234 	    gretl_matrix_free(ordvec);
4235 	    gretl_VAR_set_ordering(var, NULL);
4236 	} else {
4237 	    gretl_VAR_set_ordering(var, ordvec);
4238 	}
4239     }
4240 
4241     if (iters != save_iters) {
4242 	libset_set_int(BOOT_ITERS, iters);
4243     }
4244     err = gretl_VAR_plot_impulse_response(var, targ, shock,
4245 					  horizon, this_alpha,
4246 					  dataset, gopt);
4247     if (iters != save_iters) {
4248 	libset_set_int(BOOT_ITERS, save_iters);
4249     }
4250 
4251     gui_graph_handler(err);
4252 }
4253 
multiple_irf_plot_call(GtkAction * action,gpointer p)4254 static void multiple_irf_plot_call (GtkAction *action, gpointer p)
4255 {
4256     windata_t *vwin = (windata_t *) p;
4257     GRETL_VAR *var = (GRETL_VAR *) vwin->data;
4258     int horizon, bootstrap;
4259     static double alpha = 0.10;
4260     static gretlopt gopt = OPT_NONE;
4261     static int iters = 0;
4262     gretl_matrix *ordvec = NULL;
4263     double this_alpha = 0;
4264     int save_iters;
4265     int resp, err;
4266 
4267     ordvec = cholesky_order_vector(var);
4268     save_iters = libset_get_int(BOOT_ITERS);
4269 
4270     resp = impulse_response_setup(var, ordvec, &horizon, &bootstrap,
4271 				  &alpha, &iters, &gopt, vwin->main);
4272 
4273     if (resp < 0) {
4274 	/* canceled */
4275 	gretl_matrix_free(ordvec);
4276 	return;
4277     }
4278 
4279     if (bootstrap) {
4280 	this_alpha = alpha;
4281     }
4282 
4283     if (ordvec != NULL) {
4284 	if (ordvec_default(ordvec)) {
4285 	    gretl_matrix_free(ordvec);
4286 	    gretl_VAR_set_ordering(var, NULL);
4287 	} else {
4288 	    gretl_VAR_set_ordering(var, ordvec);
4289 	}
4290     }
4291 
4292     if (iters != save_iters) {
4293 	libset_set_int(BOOT_ITERS, iters);
4294     }
4295     err = gretl_VAR_plot_multiple_irf(var, horizon, this_alpha,
4296 				      dataset, gopt);
4297     if (iters != save_iters) {
4298 	libset_set_int(BOOT_ITERS, save_iters);
4299     }
4300 
4301     gui_graph_handler(err);
4302 }
4303 
VAR_model_data_code(GtkAction * action)4304 static int VAR_model_data_code (GtkAction *action)
4305 {
4306     const gchar *s = gtk_action_get_name(action);
4307 
4308     if (!strcmp(s, "VarIrf")) {
4309 	return VAR_IRF;
4310     } else if (!strcmp(s, "VarDecomp")) {
4311 	return VAR_DECOMP;
4312     } else {
4313 	return VAR_IRF;
4314     }
4315 }
4316 
VAR_model_data_callback(GtkAction * action,gpointer p)4317 static void VAR_model_data_callback (GtkAction *action, gpointer p)
4318 {
4319     windata_t *vwin = (windata_t *) p;
4320     GRETL_VAR *var = vwin->data;
4321     gretl_matrix *ordvec;
4322     GtkWidget *dlg;
4323     gchar *title;
4324     PRN *prn = NULL;
4325     int code, h = 0;
4326     int resp = -1;
4327     int err;
4328 
4329     if (var == NULL) {
4330 	return;
4331     }
4332 
4333     code = VAR_model_data_code(action);
4334     h = default_VAR_horizon(dataset);
4335     ordvec = cholesky_order_vector(var);
4336 
4337     title = g_strdup_printf("gretl: %s",
4338 			    (code == VAR_IRF)? _("impulse responses") :
4339 			    _("variance decompositions"));
4340 
4341     dlg = build_checks_dialog(title, NULL,
4342 			      NULL, 0, NULL, 0, 0, /* no check-buttons */
4343 			      0, NULL,             /* no radios */
4344 			      &h, _("forecast horizon (periods):"),
4345 			      2, dataset->n / 2,
4346 			      0, vwin->main, &resp);
4347 
4348     if (dlg == NULL) {
4349 	goto bailout;
4350     }
4351 
4352     if (ordvec != NULL) {
4353 	dialog_add_order_selector(dlg, var, ordvec);
4354     }
4355 
4356     /* blocks till response is selected */
4357     gtk_widget_show_all(dlg);
4358 
4359     if (resp < 0 || bufopen(&prn)) {
4360 	/* cancel or fail */
4361 	goto bailout;
4362     }
4363 
4364     if (ordvec != NULL) {
4365 	if (ordvec_default(ordvec)) {
4366 	    gretl_matrix_free(ordvec);
4367 	    ordvec = NULL;
4368 	}
4369 	gretl_VAR_set_ordering(var, ordvec);
4370 	ordvec = NULL;
4371     }
4372 
4373     if (code == VAR_IRF) {
4374 	err = gretl_VAR_print_all_impulse_responses(var, dataset, h, prn);
4375     } else if (code == VAR_DECOMP) {
4376 	err = gretl_VAR_print_all_fcast_decomps(var, dataset, h, prn);
4377     } else {
4378 	err = 1;
4379     }
4380 
4381     if (err) {
4382 	gui_errmsg(err);
4383 	gretl_print_destroy(prn);
4384     } else {
4385 	windata_t *viewer;
4386 
4387 	viewer = view_buffer_with_parent(vwin, prn, 80, 400, title,
4388 					 code, NULL);
4389 	/* for use when printing in other formats */
4390 	viewer->active_var = h;
4391     }
4392 
4393  bailout:
4394 
4395     g_free(title);
4396     gretl_matrix_free(ordvec);
4397 }
4398 
system_forecast_callback(GtkAction * action,gpointer p)4399 static void system_forecast_callback (GtkAction *action, gpointer p)
4400 {
4401     static gretlopt gopt = OPT_P;
4402     windata_t *vwin = (windata_t *) p;
4403     int ci = vwin->role;
4404     GRETL_VAR *var = NULL;
4405     equation_system *sys = NULL;
4406     FITRESID *fr;
4407     int t1, t2, t2est, yno, resp;
4408     int premax, pre_n, dyn_ok;
4409     int static_model = 0;
4410     gretlopt opt = OPT_NONE;
4411     double conf = 0.95;
4412     int i, err = 0;
4413 
4414     varnum_from_action(action, &i);
4415 
4416     if (ci == VAR || ci == VECM) {
4417 	var = (GRETL_VAR *) vwin->data;
4418 	t2est = gretl_VAR_get_t2(var);
4419 	yno = var->ylist[i+1];
4420     } else if (ci == SYSTEM) {
4421 	sys = (equation_system *) vwin->data;
4422 	t2est = sys->t2;
4423 	yno = sys->ylist[i+1];
4424 	static_model = (sys->order == 0);
4425     } else {
4426 	return;
4427     }
4428 
4429     t2 = dataset->n - 1;
4430 
4431     /* if no out-of-sample obs are available, alert the user */
4432     if (t2 == t2est) {
4433 	err = out_of_sample_info(1, &t2);
4434 	if (err) {
4435 	    return;
4436 	}
4437 	t2 = dataset->n - 1;
4438     }
4439 
4440     /* max number of pre-forecast obs in "best case" */
4441     premax = dataset->n - 1;
4442 
4443     /* if there are spare obs available, default to an
4444        out-of-sample forecast */
4445     if (t2 > t2est) {
4446 	t1 = t2est + 1;
4447 	pre_n = t2est / 2;
4448 	if (pre_n > 100) {
4449 	    pre_n = 100;
4450 	}
4451 	dyn_ok = !static_model;
4452     } else {
4453 	if (var != NULL) {
4454 	    t1 = effective_order(var);
4455 	} else {
4456 	    t1 = sys->order;
4457 	}
4458 	pre_n = 0;
4459 	dyn_ok = 0;
4460     }
4461 
4462     resp = forecast_dialog(t1, t1, &t1,
4463 			   t1, t2, &t2, NULL,
4464 			   0, premax, &pre_n,
4465 			   dyn_ok, &gopt, &conf,
4466 			   NULL, vwin->main);
4467     if (resp < 0) {
4468 	return;
4469     }
4470 
4471     if (resp == 1) {
4472 	opt = OPT_D;
4473     } else if (resp == 2) {
4474 	opt = OPT_S;
4475     }
4476 
4477     fr = get_system_forecast(vwin->data, ci, i, t1, t2, pre_n,
4478 			     dataset, opt, &err);
4479 
4480     if (err) {
4481 	gui_errmsg(err);
4482     } else {
4483 	char obs1[OBSLEN];
4484 	char obs2[OBSLEN];
4485 	PRN *prn;
4486 
4487 	ntolabel(obs1, t1, dataset);
4488 	ntolabel(obs2, t2, dataset);
4489 	lib_command_sprintf("fcast %s %s %s%s", obs1, obs2, dataset->varname[yno],
4490 			    print_flags(opt, FCAST));
4491 	record_command_verbatim();
4492 
4493 	if (bufopen(&prn)) {
4494 	    return;
4495 	}
4496 
4497 	fr->alpha = 1 - conf;
4498 	err = text_print_forecast(fr, dataset, gopt, prn);
4499 	gui_graph_handler(err);
4500 
4501 	view_buffer(prn, (fr->sderr == NULL)? 50 : 78, 400,
4502 		    _("gretl: forecasts"), FCAST, fr);
4503     }
4504 }
4505 
4506 enum {
4507     SYS_AUTOCORR_TEST,
4508     SYS_ARCH_TEST,
4509     SYS_NORMALITY_TEST,
4510     SYS_RESTRICT
4511 };
4512 
sys_test_code(GtkAction * action)4513 static int sys_test_code (GtkAction *action)
4514 {
4515     const gchar *s = gtk_action_get_name(action);
4516 
4517     if (!strcmp(s, "autocorr")) {
4518 	return SYS_AUTOCORR_TEST;
4519     } else if (!strcmp(s, "ARCH")) {
4520 	return SYS_ARCH_TEST;
4521     } else if (!strcmp(s, "normtest")) {
4522 	return SYS_NORMALITY_TEST;
4523     } else if (!strcmp(s, "restrict")) {
4524 	return SYS_RESTRICT;
4525     } else {
4526 	return SYS_NORMALITY_TEST;
4527     }
4528 }
4529 
system_test_call(GtkAction * action,gpointer p)4530 static void system_test_call (GtkAction *action, gpointer p)
4531 {
4532     windata_t *vwin = (windata_t *) p;
4533     GRETL_VAR *var = NULL;
4534     equation_system *sys = NULL;
4535     gchar *title = NULL;
4536     gchar *cstr = NULL;
4537     PRN *prn;
4538     int code, order = 0;
4539     int err = 0;
4540 
4541     if (bufopen(&prn)) {
4542 	return;
4543     }
4544 
4545     code = sys_test_code(action);
4546 
4547     if (vwin->role == SYSTEM) {
4548 	sys = (equation_system *) vwin->data;
4549     } else {
4550 	var = (GRETL_VAR *) vwin->data;
4551     }
4552 
4553     if (code == SYS_AUTOCORR_TEST || code == SYS_ARCH_TEST) {
4554 	int resp;
4555 
4556 	order = default_lag_order(dataset);
4557 	resp = spin_dialog((code == SYS_AUTOCORR_TEST)?
4558 			   _("gretl: autocorrelation") :
4559 			   _("gretl: ARCH test"), NULL,
4560 			   &order, _("Lag order for test:"),
4561 			   1, dataset->n / 2, 0, vwin->main);
4562 	if (canceled(resp)) {
4563 	    gretl_print_destroy(prn);
4564 	    return;
4565 	}
4566     }
4567 
4568     if (code == SYS_AUTOCORR_TEST) {
4569 	title = g_strdup(_("gretl: autocorrelation"));
4570 	cstr = g_strdup_printf("modtest %d --autocorr", order);
4571 	if (var != NULL) {
4572 	    err = gretl_VAR_autocorrelation_test(var, order,
4573 						 dataset,
4574 						 OPT_NONE,
4575 						 prn);
4576 	} else {
4577 	    err = system_autocorrelation_test(sys, order, OPT_NONE, prn);
4578 	}
4579     } else if (code == SYS_ARCH_TEST) {
4580 	title = g_strdup(_("gretl: ARCH test"));
4581 	cstr = g_strdup_printf("modtest %d --arch", order);
4582 	if (var != NULL) {
4583 	    err = gretl_VAR_arch_test(var, order, dataset, OPT_NONE, prn);
4584 	} else {
4585 	    err = system_arch_test(sys, order, OPT_NONE, prn);
4586 	}
4587     } else if (code == SYS_NORMALITY_TEST) {
4588 	title = g_strdup_printf("gretl: %s", _("Test for normality of residual"));
4589 	cstr = g_strdup("modtest --normality");
4590 	if (var != NULL) {
4591 	    err = gretl_VAR_normality_test(var, OPT_NONE, prn);
4592 	} else {
4593 	    err = system_normality_test(sys, OPT_NONE, prn);
4594 	}
4595     } else {
4596 	err = 1;
4597     }
4598 
4599     if (err) {
4600 	gui_errmsg(err);
4601 	gretl_print_destroy(prn);
4602     } else {
4603 	add_command_to_stack(cstr, 0);
4604 	view_buffer(prn, 78, 400, title, PRINT, NULL);
4605     }
4606 
4607     g_free(title);
4608     g_free(cstr);
4609 }
4610 
VAR_roots_plot_call(GtkAction * action,gpointer p)4611 static void VAR_roots_plot_call (GtkAction *action, gpointer p)
4612 {
4613     windata_t *vwin = (windata_t *) p;
4614     GRETL_VAR *var = (GRETL_VAR *) vwin->data;
4615     int err;
4616 
4617     err = gretl_VAR_roots_plot(var);
4618     gui_graph_handler(err);
4619 }
4620 
combined_EC_plot_call(GtkAction * action,gpointer p)4621 static void combined_EC_plot_call (GtkAction *action, gpointer p)
4622 {
4623     windata_t *vwin = (windata_t *) p;
4624     GRETL_VAR *var = (GRETL_VAR *) vwin->data;
4625     int err;
4626 
4627     err = gretl_VECM_combined_EC_plot(var, dataset);
4628     gui_graph_handler(err);
4629 }
4630 
sys_ci_from_action(GtkAction * action,int * eqn)4631 static int sys_ci_from_action (GtkAction *action, int *eqn)
4632 {
4633     const gchar *s = gtk_action_get_name(action);
4634     char cmdword[9];
4635 
4636     if (eqn != NULL) {
4637 	sscanf(s, "residplot_%d", eqn);
4638     }
4639     sscanf(s, "%*s %8s", cmdword);
4640     return gretl_command_number(cmdword);
4641 }
4642 
system_resid_plot_call(GtkAction * action,gpointer p)4643 static void system_resid_plot_call (GtkAction *action, gpointer p)
4644 {
4645     windata_t *vwin = (windata_t *) p;
4646     int ci, eqn = 0;
4647     int err;
4648 
4649     ci = sys_ci_from_action(action, &eqn);
4650     err = gretl_system_residual_plot(vwin->data, ci, eqn, dataset);
4651     gui_graph_handler(err);
4652 }
4653 
system_resid_mplot_call(GtkAction * action,gpointer p)4654 static void system_resid_mplot_call (GtkAction *action, gpointer p)
4655 {
4656     windata_t *vwin = (windata_t *) p;
4657     int ci = sys_ci_from_action(action, NULL);
4658     int err;
4659 
4660     err = gretl_system_residual_mplot(vwin->data, ci, dataset);
4661     gui_graph_handler(err);
4662 }
4663 
VECM_matrix_name(int idx)4664 static const char *VECM_matrix_name (int idx)
4665 {
4666     if (idx == M_JALPHA) {
4667 	return "alpha";
4668     } else if (idx == M_JBETA) {
4669 	return "beta";
4670     } else if (idx == M_JVBETA) {
4671 	return "var(beta)";
4672     } else {
4673 	/* not registered! */
4674 	return NULL;
4675     }
4676 }
4677 
get_VECM_matrix_idx(GtkAction * action)4678 static int get_VECM_matrix_idx (GtkAction *action)
4679 {
4680     const gchar *aname = gtk_action_get_name(action);
4681     int idx;
4682 
4683     sscanf(aname, "matrix %d", &idx);
4684     return idx;
4685 }
4686 
VECM_add_matrix(GtkAction * action,gpointer p)4687 static void VECM_add_matrix (GtkAction *action, gpointer p)
4688 {
4689     windata_t *vwin = (windata_t *) p;
4690     GRETL_VAR *var = (GRETL_VAR *) vwin->data;
4691     gretl_matrix *m = NULL;
4692     char vname[VNAMELEN];
4693     const char *mname;
4694     gchar *blurb = NULL;
4695     int vecid = gretl_VECM_id(var);
4696     int idx, resp, show = 1;
4697     int err = 0;
4698 
4699     idx = get_VECM_matrix_idx(action);
4700     mname = VECM_matrix_name(idx);
4701     if (mname == NULL) {
4702 	/* internal error! */
4703 	gui_errmsg(E_DATA);
4704 	return;
4705     }
4706 
4707     if (!strcmp(mname, "var(beta)")) {
4708 	sprintf(vname, "jvbeta_%d", vecid);
4709     } else {
4710 	sprintf(vname, "j%s_%d", mname, vecid);
4711     }
4712     blurb = g_strdup_printf("%s (%s) from VECM %d\n"
4713 			    "Name (max. %d characters):",
4714 			    mname, gretl_type_get_name(GRETL_TYPE_MATRIX),
4715 			    vecid, VNAMELEN - 1);
4716     resp = object_name_entry_dialog(vname, GRETL_TYPE_MATRIX, blurb,
4717 				    &show, vwin->main);
4718     g_free(blurb);
4719     if (resp < 0) {
4720 	/* canceled */
4721 	return;
4722     }
4723 
4724     m = gretl_VAR_get_matrix(var, idx, &err);
4725     if (!err) {
4726 	err = user_var_add_or_replace(vname, GRETL_TYPE_MATRIX, m);
4727     }
4728     if (err) {
4729 	gui_errmsg(err);
4730     } else if (show) {
4731 	view_session();
4732     }
4733 }
4734 
add_system_menu_items(windata_t * vwin,int ci)4735 static void add_system_menu_items (windata_t *vwin, int ci)
4736 {
4737     GtkActionEntry item;
4738     const gchar *top = "/menubar";
4739     const gchar *tests = "/menubar/Tests";
4740     const gchar *save = "/menubar/Save";
4741     const gchar *graphs = "/menubar/Graphs";
4742     const gchar *analysis = "/menubar/Analysis";
4743     GRETL_VAR *var = NULL;
4744     equation_system *sys = NULL;
4745     int neqns, nfc, vtarg, vshock;
4746     char tmp[VNAMELEN2], istr[VNAMELEN];
4747     char maj[128], min[64];
4748     const char *cmdword;
4749     int i, j;
4750 
4751     if (ci == SYSTEM) {
4752 	sys = (equation_system *) vwin->data;
4753 	neqns = sys->neqns;
4754 	nfc = sys->neqns + sys->nidents;
4755     } else {
4756 	var = (GRETL_VAR *) vwin->data;
4757 	nfc = neqns = gretl_VAR_get_n_equations(var);
4758     }
4759 
4760     cmdword = gretl_command_word(ci);
4761     action_entry_init(&item);
4762 
4763     /* FIXME: the following two tests should really be multivariate */
4764 
4765     if (dataset_is_time_series(dataset)) {
4766 	/* univariate autocorrelation tests */
4767 	item.name = "autocorr";
4768 	item.label = N_("_Autocorrelation");
4769 	item.callback = G_CALLBACK(system_test_call);
4770 	vwin_menu_add_item(vwin, tests, &item);
4771 
4772 	/* univariate ARCH tests */
4773 	item.name = "ARCH";
4774 	item.label = N_("A_RCH");
4775 	vwin_menu_add_item(vwin, tests, &item);
4776     }
4777 
4778     /* multivariate normality test */
4779     item.name = "normtest";
4780     item.label = N_("_Normality of residuals");
4781     item.callback = G_CALLBACK(system_test_call);
4782     vwin_menu_add_item(vwin, tests, &item);
4783 
4784     if (ci == VECM || ci == SYSTEM) {
4785 	/* linear restrictions */
4786 	item.name = "restrict";
4787 	item.label = N_("Linear restrictions");
4788 	item.callback = G_CALLBACK(gretl_callback);
4789 	vwin_menu_add_item(vwin, tests, &item);
4790     } else if (ci == VAR) {
4791 	/* regular VAR: omit exogenous variables test */
4792 	if (gretl_VAR_get_exo_list(var) != NULL) {
4793 	    item.name = "VarOmit";
4794 	    item.label = N_("Omit exogenous variables...");
4795 	    item.callback = G_CALLBACK(selector_callback);
4796 	    vwin_menu_add_item(vwin, tests, &item);
4797 	}
4798 	if (var->detflags & DET_TREND) {
4799 	    item.name = "VarOmitTrend";
4800 	    item.label = N_("Omit time trend");
4801 	    item.callback = G_CALLBACK(VAR_omit_auto);
4802 	    vwin_menu_add_item(vwin, tests, &item);
4803 	}
4804 	if (var->detflags & DET_SEAS) {
4805 	    item.name = "VarOmitSeas";
4806 	    item.label = N_("Omit seasonal dummies");
4807 	    item.callback = G_CALLBACK(VAR_omit_auto);
4808 	    vwin_menu_add_item(vwin, tests, &item);
4809 	}
4810     }
4811 
4812     /* Save residuals */
4813     for (i=0; i<neqns; i++) {
4814 	sprintf(istr, "resid %d", i);
4815 	sprintf(maj, "%s %d", _("Residuals from equation"), i + 1);
4816 	item.name = istr;
4817 	item.label = maj;
4818 	item.callback = G_CALLBACK(add_system_resid);
4819 	vwin_menu_add_item(vwin, save, &item);
4820     }
4821 
4822     /* Display residual matrix */
4823     item.name = "uhat";
4824     item.label = N_("Display residuals, all equations");
4825     item.callback = G_CALLBACK(system_data_callback);
4826     vwin_menu_add_item(vwin, analysis, &item);
4827 
4828     if (ci == SYSTEM) {
4829 	/* Display fitted values matrix */
4830 	item.name = "yhat";
4831 	item.label = N_("Display fitted values, all equations");
4832 	vwin_menu_add_item(vwin, analysis, &item);
4833     }
4834 
4835     if (neqns > 1) {
4836 	/* Display VCV matrix */
4837 	item.name = "sigma";
4838 	item.label = N_("Cross-equation covariance matrix");
4839 	vwin_menu_add_item(vwin, analysis, &item);
4840     }
4841 
4842     if (ci == VAR || ci == VECM) {
4843 	/* impulse response printout */
4844 	item.name = "VarIrf";
4845 	item.label = N_("Impulse responses");
4846 	item.callback = G_CALLBACK(VAR_model_data_callback);
4847 	vwin_menu_add_item(vwin, analysis, &item);
4848 
4849 	/* variance decomp printout */
4850 	item.name = "VarDecomp";
4851 	item.label = N_("Forecast variance decomposition");
4852 	vwin_menu_add_item(vwin, analysis, &item);
4853     }
4854 
4855     /* Residual plots */
4856 
4857     action_entry_init(&item);
4858     item.name = "ResidsMenu";
4859     item.label = _("Residuals");
4860     vwin_menu_add_menu(vwin, graphs, &item);
4861 
4862     if (neqns > 1) {
4863 	/* combined residual plot */
4864 	sprintf(min, "comboresid %s", cmdword);
4865 	item.name = min;
4866 	item.label = N_("Combined plot");
4867 	item.callback = G_CALLBACK(system_resid_plot_call);
4868 	vwin_menu_add_item(vwin, "/menubar/Graphs/ResidsMenu", &item);
4869     }
4870 
4871     if (neqns > 1 && neqns <= 6) {
4872 	/* multiple residual plots in one frame */
4873 	sprintf(min, "multiresid %s", cmdword);
4874 	item.name = min;
4875 	item.label = N_("Multiple plots");
4876 	item.callback = G_CALLBACK(system_resid_mplot_call);
4877 	vwin_menu_add_item(vwin, "/menubar/Graphs/ResidsMenu", &item);
4878     }
4879 
4880     item.callback = G_CALLBACK(system_resid_plot_call);
4881 
4882     for (i=0; i<neqns; i++) {
4883 	sprintf(min, "residplot_%d %s", i+1, cmdword);
4884 	sprintf(maj, N_("Equation %d"), i+1);
4885 	item.name = min;
4886 	item.label = maj;
4887 	vwin_menu_add_item(vwin, "/menubar/Graphs/ResidsMenu", &item);
4888     }
4889 
4890     /* end residual plots */
4891 
4892     if (ci == VECM) {
4893 	int r = gretl_VECM_rank(var);
4894 
4895 	if (r == 1) {
4896 	    item.name = "ecplot";
4897 	    item.label = N_("EC plot");
4898 	    item.callback = G_CALLBACK(combined_EC_plot_call);
4899 	    vwin_menu_add_item(vwin, graphs, &item);
4900 	} else {
4901 	    item.name = "ecplot";
4902 	    item.label = N_("Combined EC plot");
4903 	    item.callback = G_CALLBACK(combined_EC_plot_call);
4904 	    vwin_menu_add_item(vwin, graphs, &item);
4905 	}
4906     }
4907 
4908     if (ci != SYSTEM) {
4909 	/* VAR inverse roots */
4910 	item.name = "VarRoots";
4911 	item.label = N_("VAR inverse roots");
4912 	item.callback = G_CALLBACK(VAR_roots_plot_call);
4913 	vwin_menu_add_item(vwin, graphs, &item);
4914     }
4915 
4916     if (ci != SYSTEM && neqns > 1 && neqns <= 4) {
4917 	/* Multiple IRFs */
4918 	item.name = "MultiIrf";
4919 	item.label = N_("Impulse responses (combined)");
4920 	item.callback = G_CALLBACK(multiple_irf_plot_call);
4921 	vwin_menu_add_item(vwin, graphs, &item);
4922     }
4923 
4924     for (i=0; i<nfc; i++) {
4925 	char newpath[64];
4926 	int dv;
4927 
4928 	/* forecast items */
4929 	if (var != NULL) {
4930 	    dv = gretl_VAR_get_variable_number(var, i);
4931 	} else {
4932 	    dv = sys->ylist[i+1];
4933 	}
4934 	double_underscores(tmp, dataset->varname[dv]);
4935 	sprintf(istr, "fcast %d", i);
4936 	item.name = istr;
4937 	item.label = tmp;
4938 	item.callback = G_CALLBACK(system_forecast_callback);
4939 	vwin_menu_add_item(vwin, "/menubar/Analysis/Forecasts", &item);
4940 
4941 	if (var == NULL) {
4942 	    continue;
4943 	}
4944 
4945 	/* impulse response plots: make menu for target */
4946 	vtarg = gretl_VAR_get_variable_number(var, i);
4947 	double_underscores(tmp, dataset->varname[vtarg]);
4948 	sprintf(istr, "targ_%d", i);
4949 	sprintf(maj, _("Response of %s"), tmp);
4950 	item.name = istr;
4951 	item.label = maj;
4952 	item.callback = NULL;
4953 	vwin_menu_add_menu(vwin, graphs, &item);
4954 
4955 	/* path under which to add shocks */
4956 	sprintf(newpath, "/menubar/Graphs/targ_%d", i);
4957 
4958 	for (j=0; j<neqns; j++) {
4959 	    /* impulse responses: subitems for shocks */
4960 	    vshock = gretl_VAR_get_variable_number(var, j);
4961 	    double_underscores(tmp, dataset->varname[vshock]);
4962 	    sprintf(istr, "Imp:%d:%d", i, j);
4963 	    sprintf(min, _("to %s"), tmp);
4964 	    item.name = istr;
4965 	    item.label = min;
4966 	    item.callback = G_CALLBACK(impulse_plot_call);
4967 	    vwin_menu_add_item(vwin, newpath, &item);
4968 	}
4969     }
4970 
4971     if (var != NULL) {
4972 	item.name = "FEVD";
4973 	item.label = _("Forecast variance decomposition");
4974 	item.callback = NULL;
4975 	vwin_menu_add_menu(vwin, graphs, &item);
4976 	for (j=0; j<neqns; j++) {
4977 	    /* FEVD graphs per equation */
4978 	    vtarg = gretl_VAR_get_variable_number(var, j);
4979 	    double_underscores(tmp, dataset->varname[vtarg]);
4980 	    sprintf(istr, "FEVD:%d", j);
4981 	    item.name = istr;
4982 	    item.label = tmp;
4983 	    item.callback = G_CALLBACK(FEVD_plot_call);
4984 	    vwin_menu_add_item(vwin, "/menubar/Graphs/FEVD", &item);
4985 	}
4986     }
4987 
4988     if (ci == VECM) {
4989 	/* saving things specific to VECMs */
4990 	int mtypes[] = {M_JALPHA, M_JBETA, M_JVBETA};
4991 
4992 	/* save error correction terms as series */
4993 	for (i=0; i<jrank(var); i++) {
4994 	    sprintf(istr, "EC %d", i);
4995 	    sprintf(maj, "%s %d", _("EC term"), i+1);
4996 	    item.name = istr;
4997 	    item.label = maj;
4998 	    item.callback = G_CALLBACK(VECM_add_EC_data);
4999 	    vwin_menu_add_item(vwin, save, &item);
5000 	}
5001 	/* save relevant matrices */
5002 	for (i=0; i<G_N_ELEMENTS(mtypes); i++) {
5003 	    sprintf(istr, "matrix %d", mtypes[i]);
5004 	    item.name = istr;
5005 	    item.label = VECM_matrix_name(mtypes[i]);
5006 	    item.callback = G_CALLBACK(VECM_add_matrix);
5007 	    vwin_menu_add_item(vwin, save, &item);
5008 	}
5009     }
5010 
5011     maybe_add_packages_to_model_menus(vwin);
5012 
5013     if (latex_is_ok()) {
5014 	int n = G_N_ELEMENTS(sys_tex_items);
5015 
5016 	vwin_menu_add_menu(vwin, top, &sys_tex_items[0]);
5017 	vwin_menu_add_items(vwin, "/menubar/LaTeX",
5018 			    sys_tex_items + 1, n - 1);
5019     }
5020 }
5021 
vector_suitable_for_series(const gretl_matrix * m)5022 static int vector_suitable_for_series (const gretl_matrix *m)
5023 {
5024     if (m->cols == 1 && gretl_matrix_is_dated(m)) {
5025 	int t2 = gretl_matrix_get_t2(m);
5026 
5027 	/* the column vector can be "cast" to series
5028 	   without data loss */
5029 	return t2 < dataset->n;
5030     } else {
5031 	return 0;
5032     }
5033 }
5034 
save_bundled_item_call(GtkAction * action,gpointer p)5035 static void save_bundled_item_call (GtkAction *action, gpointer p)
5036 {
5037     windata_t *vwin = (windata_t *) p;
5038     gretl_bundle *bundle = vwin->data;
5039     const gchar *key = gtk_action_get_name(action);
5040     const char *note;
5041     GretlType type;
5042     void *val;
5043     int size = 0;
5044     int err = 0;
5045 
5046     val = gretl_bundle_get_data(bundle, key, &type, &size, &err);
5047     if (err) {
5048 	gui_errmsg(err);
5049 	return;
5050     }
5051 
5052     note = gretl_bundle_get_note(bundle, key);
5053 
5054     if (type == GRETL_TYPE_SERIES && size <= dataset->n) {
5055 	const double *x = (double *) val;
5056 
5057 	save_bundled_series(x, 0, size - 1, key, note, vwin);
5058     } else if (type == GRETL_TYPE_MATRIX &&
5059 	       vector_suitable_for_series((gretl_matrix *) val)) {
5060 	const gretl_matrix *m = val;
5061 	int t1 = gretl_matrix_get_t1(m);
5062 	int t2 = gretl_matrix_get_t2(m);
5063 
5064 	save_bundled_series(m->val, t1, t2, key, note, vwin);
5065     } else {
5066 	char vname[VNAMELEN];
5067 	gchar *blurb;
5068 	int resp, show = 1;
5069 
5070 	*vname = '\0';
5071 	strncat(vname, key, VNAMELEN - 1);
5072 
5073 	blurb = g_strdup_printf("%s (%s) from bundle\n"
5074 				"Name (max. %d characters):",
5075 				key, gretl_type_get_name(type),
5076 				VNAMELEN - 1);
5077 	resp = object_name_entry_dialog(vname, type, blurb,
5078 					&show, vwin->main);
5079 	g_free(blurb);
5080 
5081 	if (resp < 0) {
5082 	    /* canceled */
5083 	    return;
5084 	}
5085 
5086 	if (gretl_is_scalar_type(type)) {
5087 	    double *xp = malloc(sizeof *xp);
5088 
5089 	    if (type == GRETL_TYPE_INT || type == GRETL_TYPE_BOOL) {
5090 		*xp = *(int *) val;
5091 	    } else if (type == GRETL_TYPE_UNSIGNED) {
5092 		*xp = *(unsigned *) val;
5093 	    } else {
5094 		*xp = *(double *) val;
5095 	    }
5096 	    err = user_var_add_or_replace(vname, GRETL_TYPE_DOUBLE, xp);
5097 	} else if (type == GRETL_TYPE_MATRIX) {
5098 	    gretl_matrix *orig = (gretl_matrix *) val;
5099 	    gretl_matrix *m = gretl_matrix_copy(orig);
5100 
5101 	    if (m == NULL) {
5102 		err = E_ALLOC;
5103 	    } else {
5104 		err = user_var_add_or_replace(vname, GRETL_TYPE_MATRIX, m);
5105 	    }
5106 	} else if (type == GRETL_TYPE_SERIES) {
5107 	    double *x = (double *) val;
5108 	    gretl_matrix *m;
5109 
5110 	    m = gretl_vector_from_array(x, size, GRETL_MOD_NONE);
5111 	    err = user_var_add_or_replace(vname, GRETL_TYPE_MATRIX, m);
5112 	} else if (type == GRETL_TYPE_STRING) {
5113 	    char *s = gretl_strdup((char *) val);
5114 
5115 	    err = user_var_add_or_replace(vname, GRETL_TYPE_STRING, s);
5116 	} else if (type == GRETL_TYPE_BUNDLE) {
5117 	    gretl_bundle *orig = (gretl_bundle *) val;
5118 	    gretl_bundle *b = gretl_bundle_copy(orig, &err);
5119 
5120 	    if (!err) {
5121 		err = user_var_add_or_replace(vname, GRETL_TYPE_BUNDLE, b);
5122 	    }
5123 	} else if (type == GRETL_TYPE_ARRAY) {
5124 	    gretl_array *orig = (gretl_array *) val;
5125 	    gretl_array *a = gretl_array_copy(orig, &err);
5126 
5127 	    if (!err) {
5128 		err = user_var_add_or_replace(vname, gretl_array_get_type(a), a);
5129 	    }
5130 	}
5131 
5132 	if (show && !err) {
5133 	    if (gretl_is_scalar_type(type)) {
5134 		edit_scalars();
5135 	    } else {
5136 		view_session();
5137 	    }
5138 	}
5139     }
5140 
5141     if (err) {
5142 	gui_errmsg(err);
5143     }
5144 }
5145 
bundle_plot_call(GtkAction * action,gpointer p)5146 static void bundle_plot_call (GtkAction *action, gpointer p)
5147 {
5148     windata_t *vwin = (windata_t *) p;
5149     gretl_bundle *bundle = vwin->data;
5150     const gchar *aname = gtk_action_get_name(action);
5151 
5152     exec_bundle_special_function(bundle, BUNDLE_PLOT,
5153 				 aname, vwin->main);
5154 }
5155 
add_blist_item_to_menu(gpointer listitem,gpointer p)5156 static void add_blist_item_to_menu (gpointer listitem,
5157 				    gpointer p)
5158 {
5159     bundled_item *bi = listitem;
5160     gpointer data;
5161     const char *key;
5162     GtkAction *action;
5163     GtkWidget *item;
5164     GtkWidget *menu = p;
5165     gchar *keystr, *label = NULL;
5166     const char *typestr = "?";
5167     const char *note;
5168     GretlType type;
5169     int scalar = 0;
5170     int r = 0, c = 0;
5171     int size = 0;
5172 
5173     key = bundled_item_get_key(bi);
5174     data = bundled_item_get_data(bi, &type, &size);
5175 
5176     if (data == NULL || type == GRETL_TYPE_STRING) {
5177 	return;
5178     }
5179 
5180     if (type == GRETL_TYPE_MATRIX) {
5181 	gretl_matrix *m = data;
5182 
5183 	if (gretl_is_null_matrix(m)) {
5184 	    return;
5185 	} else if (vector_suitable_for_series(m)) {
5186 	    type = GRETL_TYPE_SERIES;
5187 	} else {
5188 	    r = m->rows;
5189 	    c = m->cols;
5190 	}
5191     } else if (type == GRETL_TYPE_SERIES && size > dataset->n) {
5192 	type = GRETL_TYPE_MATRIX;
5193 	r = size;
5194 	c = 1;
5195     } else if (gretl_is_scalar_type(type)) {
5196 	scalar = 1;
5197     }
5198 
5199     typestr = gretl_type_get_name(type);
5200     note = bundled_item_get_note(bi);
5201     keystr = double_underscores_new((gchar *) key);
5202 
5203     if (r > 0 && c > 0) {
5204 	if (note != NULL) {
5205 	    label = g_strdup_printf("%s (%s: %s, %d x %d)", keystr,
5206 				    typestr, note, r, c);
5207 	} else {
5208 	    label = g_strdup_printf("%s (%s, %d x %d)", keystr,
5209 				    typestr, r, c);
5210 	}
5211     } else if (scalar) {
5212 	if (type == GRETL_TYPE_DOUBLE) {
5213 	    label = g_strdup_printf("%s (scalar: %g)", keystr,
5214 				    *(double *) data);
5215 	} else if (type == GRETL_TYPE_INT || type == GRETL_TYPE_BOOL) {
5216 	    label = g_strdup_printf("%s (scalar: %d)", keystr,
5217 				    *(int *) data);
5218 	} else if (type == GRETL_TYPE_UNSIGNED) {
5219 	    label = g_strdup_printf("%s (scalar: %d)", keystr,
5220 				    *(unsigned int *) data);
5221 	}
5222     } else if (note != NULL) {
5223 	label = g_strdup_printf("%s (%s: %s)", keystr, typestr, note);
5224     } else {
5225 	label = g_strdup_printf("%s (%s)", keystr, typestr);
5226     }
5227 
5228     g_free(keystr);
5229 
5230     action = gtk_action_new(key, label, NULL, NULL);
5231     g_signal_connect(G_OBJECT(action), "activate",
5232 		     G_CALLBACK(save_bundled_item_call),
5233 		     g_object_get_data(G_OBJECT(menu), "vwin"));
5234 
5235     item = gtk_action_create_menu_item(action);
5236     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
5237 
5238     g_free(label);
5239 }
5240 
add_kalman_items_to_menu(GtkWidget * menu,kalman * K)5241 static void add_kalman_items_to_menu (GtkWidget *menu,
5242 				      kalman *K)
5243 {
5244     GtkAction *action;
5245     GtkWidget *item;
5246     gchar *label;
5247     char **S;
5248     int i, ns = 0;
5249 
5250     S = kalman_bundle_get_matrix_names(K, &ns);
5251 
5252     for (i=0; i<ns; i++) {
5253 	label = g_strdup_printf("%s (matrix)", S[i]);
5254 	action = gtk_action_new(S[i], label, NULL, NULL);
5255 	g_signal_connect(G_OBJECT(action), "activate",
5256 			 G_CALLBACK(save_bundled_item_call),
5257 			 g_object_get_data(G_OBJECT(menu), "vwin"));
5258 	item = gtk_action_create_menu_item(action);
5259 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
5260 	g_free(label);
5261     }
5262 
5263     strings_array_free(S, ns);
5264     ns = 0;
5265 
5266     S = kalman_bundle_get_scalar_names(K, &ns);
5267 
5268     for (i=0; i<ns; i++) {
5269 	label = g_strdup_printf("%s (scalar)", S[i]);
5270 	action = gtk_action_new(S[i], label, NULL, NULL);
5271 	g_signal_connect(G_OBJECT(action), "activate",
5272 			 G_CALLBACK(save_bundled_item_call),
5273 			 g_object_get_data(G_OBJECT(menu), "vwin"));
5274 	item = gtk_action_create_menu_item(action);
5275 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
5276 	g_free(label);
5277     }
5278 
5279     strings_array_free(S, ns);
5280 }
5281 
check_for_saveable(gpointer key,gpointer value,gpointer data)5282 static void check_for_saveable (gpointer key,
5283 				gpointer value,
5284 				gpointer data)
5285 {
5286     int *pn = (int *) data;
5287     GretlType type;
5288     void *val;
5289 
5290     val = bundled_item_get_data((bundled_item *) value, &type, NULL);
5291     if (val == NULL) {
5292 	/* "can't happen" */
5293 	return;
5294     }
5295     if (type == GRETL_TYPE_STRING) {
5296 	/* not useful in GUI? */
5297 	return;
5298     }
5299     if (type == GRETL_TYPE_MATRIX) {
5300 	gretl_matrix *m = val;
5301 
5302 	if (gretl_is_null_matrix(m)) {
5303 	    /* no use to man nor beast? */
5304 	    return;
5305 	}
5306     }
5307 
5308     *pn += 1;
5309 }
5310 
any_saveable_content(gretl_bundle * b)5311 static int any_saveable_content (gretl_bundle *b)
5312 {
5313     int n = gretl_bundle_get_n_keys(b);
5314 
5315     if (n > 0) {
5316 	GHashTable *ht = (GHashTable *) gretl_bundle_get_content(b);
5317 
5318 	n = 0;
5319 	g_hash_table_foreach(ht, check_for_saveable, &n);
5320     }
5321 
5322     return n;
5323 }
5324 
make_bundle_content_menu(windata_t * vwin)5325 GtkWidget *make_bundle_content_menu (windata_t *vwin)
5326 {
5327     gretl_bundle *bundle = vwin->data;
5328     GtkWidget *menu = NULL;
5329 
5330     if (gretl_bundle_get_type(bundle) == BUNDLE_KALMAN) {
5331 	kalman *K = gretl_bundle_get_private_data(bundle);
5332 
5333 	if (K != NULL) {
5334 	    menu = gtk_menu_new();
5335 	    g_object_set_data(G_OBJECT(menu), "vwin", vwin);
5336 	    add_kalman_items_to_menu(menu, K);
5337 	}
5338     }
5339 
5340     if (any_saveable_content(bundle)) {
5341 	GList *blist = gretl_bundle_get_sorted_items(bundle);
5342 
5343 	if (menu == NULL) {
5344 	    menu = gtk_menu_new();
5345 	    g_object_set_data(G_OBJECT(menu), "vwin", vwin);
5346 	}
5347 	g_list_foreach(blist, add_blist_item_to_menu, menu);
5348 	g_list_free(blist);
5349     }
5350 
5351     return menu;
5352 }
5353 
make_bundle_plot_menu(windata_t * vwin)5354 GtkWidget *make_bundle_plot_menu (windata_t *vwin)
5355 {
5356     gretl_bundle *bundle = vwin->data;
5357     gchar *plotfunc;
5358     GtkWidget *menu = NULL;
5359 
5360     plotfunc = get_bundle_special_function(bundle, BUNDLE_PLOT);
5361 
5362     if (plotfunc != NULL) {
5363 	ufunc *fun = NULL;
5364 	const char **S = NULL;
5365 	int ng = 0;
5366 
5367 	if (strcmp(plotfunc, "builtin")) {
5368 	    fun = get_user_function_by_name(plotfunc);
5369 	}
5370 
5371 	if (fun != NULL) {
5372 	    S = fn_param_value_labels(fun, 1, &ng);
5373 	}
5374 
5375 	if (S != NULL) {
5376 	    /* the plotfunc has some options available */
5377 	    GtkAction *action;
5378 	    GtkWidget *item;
5379 	    gchar *aname;
5380 	    int i;
5381 
5382 	    menu = gtk_menu_new();
5383 
5384 	    for (i=0; i<ng; i++) {
5385 		aname = g_strdup_printf("%s:%d", plotfunc, i);
5386 		action = gtk_action_new(aname, S[i], NULL, NULL);
5387 		g_signal_connect(G_OBJECT(action), "activate",
5388 				 G_CALLBACK(bundle_plot_call),
5389 				 vwin);
5390 		item = gtk_action_create_menu_item(action);
5391 		gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
5392 		g_free(aname);
5393 	    }
5394 	}
5395 	g_free(plotfunc);
5396     }
5397 
5398     return menu;
5399 }
5400 
make_bundle_save_menu(windata_t * vwin)5401 GtkWidget *make_bundle_save_menu (windata_t *vwin)
5402 {
5403     gretl_bundle *bundle = vwin->data;
5404     GtkWidget *menu = gtk_menu_new();
5405     GtkAction *action;
5406     GtkWidget *item;
5407 
5408     action = gtk_action_new("SaveAs", _("_Save text..."),
5409 			    NULL, NULL);
5410     g_signal_connect(G_OBJECT(action), "activate",
5411 		     G_CALLBACK(model_output_save), vwin);
5412     item = gtk_action_create_menu_item(action);
5413     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
5414 
5415     action = gtk_action_new("SaveAsIcon", _("Save bundle to session as _icon"),
5416 			    NULL, NULL);
5417     g_signal_connect(G_OBJECT(action), "activate",
5418 		     G_CALLBACK(bundle_add_as_icon), vwin);
5419     item = gtk_action_create_menu_item(action);
5420     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
5421     vwin_record_action(vwin, action);
5422 
5423     if (get_user_var_by_data(bundle)) {
5424 	gtk_action_set_sensitive(action, FALSE);
5425     }
5426 
5427     return menu;
5428 }
5429 
set_sample_from_model(void * ptr,int role)5430 static int set_sample_from_model (void *ptr, int role)
5431 {
5432     MODEL *pmod = NULL;
5433     int range_set = 0;
5434     int err = 0;
5435 
5436     if (role == VIEW_MODEL) {
5437 	/* called from single-eqn model window */
5438 	pmod = ptr;
5439     }
5440 
5441     /* first restore the full dataset */
5442     err = restore_full_sample(dataset, NULL);
5443 
5444     /* then, if the model was subsampled, restore the subsample */
5445     if (!err) {
5446 	if (pmod != NULL && pmod->submask != NULL) {
5447 	    err = restrict_sample_from_mask(pmod->submask, dataset,
5448 					    OPT_NONE);
5449 	    range_set = 1;
5450 	} else {
5451 	    /* VAR, VECM or something */
5452 	    int t1 = 0, t2 = 0;
5453 
5454 	    model_get_t1_t2(ptr, role, &t1, &t2);
5455 	    if (t1 == 0 && t2 == 0) {
5456 		err = E_DATA;
5457 	    } else if (t1 != dataset->t1 || t2 != dataset->t2) {
5458 		dataset->t1 = t1;
5459 		dataset->t2 = t2;
5460 		range_set = 1;
5461 	    }
5462 	}
5463     }
5464 
5465     if (err) {
5466 	gui_errmsg(err);
5467     } else {
5468 	if (range_set) {
5469 	    char comment[64];
5470 
5471 	    restore_sample_state(TRUE);
5472 	    if (pmod != NULL) {
5473 		sprintf(comment, "# restored sample from model %d\n", pmod->ID);
5474 	    } else {
5475 		strcpy(comment, "# restored sample from model\n");
5476 	    }
5477 	    add_command_to_stack(comment, 0);
5478 	} else {
5479 	    restore_sample_state(FALSE);
5480 	    lib_command_strcpy("smpl --full");
5481 	    record_command_verbatim();
5482 	}
5483 
5484 	mark_session_changed();
5485 	set_sample_label(dataset);
5486     }
5487 
5488     return err;
5489 }
5490 
5491 /* maybe_set_sample_from_model: return TRUE if the problem situation
5492    (sample mismatch) is successfully handled, else FALSE.
5493 */
5494 
maybe_set_sample_from_model(windata_t * vwin)5495 static gboolean maybe_set_sample_from_model (windata_t *vwin)
5496 {
5497     const char *msg = N_("The model sample differs from the dataset sample,\n"
5498 			 "so some menu options will be disabled.\n\n"
5499 			 "Do you want to restore the sample on which\n"
5500 			 "this model was estimated?");
5501     int resp, err = 0;
5502 
5503     resp = yes_no_dialog(NULL, _(msg), vwin_toplevel(vwin));
5504 
5505     if (resp == GRETL_NO) {
5506 	return FALSE;
5507     }
5508 
5509     err = set_sample_from_model(vwin->data, vwin->role);
5510 
5511     return (err == 0);
5512 }
5513 
check_model_menu(GtkWidget * w,GdkEventButton * eb,gpointer data)5514 static gint check_model_menu (GtkWidget *w, GdkEventButton *eb,
5515 			      gpointer data)
5516 {
5517     windata_t *vwin = (windata_t *) data;
5518     MODEL *pmod = vwin->data;
5519     GtkAction *action;
5520     int resampled = 0;
5521     int between = 0;
5522     gboolean s, ok = TRUE;
5523 
5524     if (RQ_SPECIAL_MODEL(pmod)) {
5525 	return FALSE;
5526     }
5527 
5528     if (dataset == NULL || dataset->Z == NULL) {
5529 	flip(vwin->ui, "/menubar/File/SaveAsIcon", FALSE);
5530 	flip(vwin->ui, "/menubar/File/SaveAndClose", FALSE);
5531 	flip(vwin->ui, "/menubar/Edit/Copy", FALSE);
5532 	flip(vwin->ui, "/menubar/Tests", FALSE);
5533 	flip(vwin->ui, "/menubar/Graphs", FALSE);
5534 	flip(vwin->ui, "/menubar/Analysis", FALSE);
5535 	return FALSE;
5536     }
5537 
5538     if (pmod->ci == MLE || pmod->ci == GMM ||
5539 	pmod->ci == MPOLS || pmod->ci == BIPROBIT) {
5540 	return FALSE;
5541     }
5542 
5543     if (model_sample_problem(pmod, dataset)) {
5544 	resampled = (pmod->submask == RESAMPLED);
5545 	between = gretl_is_between_model(pmod);
5546 	ok = FALSE;
5547     }
5548 
5549     /* check current menu state */
5550     action = gtk_ui_manager_get_action(vwin->ui, "/menubar/Save/uhat");
5551     s = gtk_action_is_sensitive(action);
5552 
5553     if (s == ok) {
5554 	/* no need to flip state */
5555 	return FALSE;
5556     }
5557 
5558     if (s && !ok) {
5559 	if (resampled) {
5560 	    infobox(_("The model sample differs from the dataset sample,\n"
5561 		      "so some menu options will be disabled."));
5562 	} else if (!between) {
5563 	    /* give option to restore model sample */
5564 	    ok = maybe_set_sample_from_model(vwin);
5565 	    if (ok) {
5566 		return FALSE;
5567 	    }
5568 	}
5569     }
5570 
5571     flip(vwin->ui, "/menubar/Analysis/Forecasts", ok);
5572     flip(vwin->ui, "/menubar/Save/yhat", ok);
5573     flip(vwin->ui, "/menubar/Save/uhat", ok);
5574     flip(vwin->ui, "/menubar/Save/uhat2", ok);
5575     flip(vwin->ui, "/menubar/Save/NewVar", ok);
5576 
5577     if (resampled) {
5578 	flip(vwin->ui, "/menubar/Tests", FALSE);
5579 	flip(vwin->ui, "/menubar/Analysis/DisplayAFR", FALSE);
5580 	flip(vwin->ui, "/menubar/Analysis/Bootstrap", FALSE);
5581 	flip(vwin->ui, "/menubar/Graphs", FALSE);
5582     }
5583 
5584     if (between) {
5585 	flip(vwin->ui, "/menubar/Edit/Revise", FALSE);
5586     }
5587 
5588     return FALSE;
5589 }
5590 
check_VAR_menu(GtkWidget * w,GdkEventButton * eb,gpointer data)5591 static gint check_VAR_menu (GtkWidget *w, GdkEventButton *eb,
5592 			    gpointer data)
5593 {
5594     windata_t *vwin = (windata_t *) data;
5595     GtkAction *action;
5596     gboolean s, ok = TRUE;
5597 
5598     if (complex_subsampled()) {
5599 	ok = FALSE;
5600     }
5601 
5602     action = gtk_ui_manager_get_action(vwin->ui, "/menubar/Tests");
5603     s = gtk_action_is_sensitive(action);
5604 
5605     if (s == ok) {
5606 	/* no need to flip state */
5607 	return FALSE;
5608     }
5609 
5610     flip(vwin->ui, "/menubar/Edit/Revise", ok);
5611     flip(vwin->ui, "/menubar/Tests", ok);
5612     flip(vwin->ui, "/menubar/Save", ok);
5613     flip(vwin->ui, "/menubar/Graphs", ok);
5614     flip(vwin->ui, "/menubar/Analysis/Forecasts", ok);
5615     flip(vwin->ui, "/menubar/Analysis/VarIrf", ok);
5616     flip(vwin->ui, "/menubar/Analysis/VarDecomp", ok);
5617 
5618     if (!ok) {
5619 	warnbox(_("dataset is subsampled"));
5620     }
5621 
5622     return FALSE;
5623 }
5624 
exists_string(const char * name,GretlType t)5625 static gchar *exists_string (const char *name, GretlType t)
5626 {
5627     gchar *s = NULL;
5628 
5629     if (t == GRETL_TYPE_SERIES) {
5630 	s = g_strdup_printf(_("A series named %s already exists"), name);
5631     } else if (t == GRETL_TYPE_MATRIX) {
5632 	s = g_strdup_printf(_("A matrix named %s already exists"), name);
5633     } else if (t == GRETL_TYPE_DOUBLE) {
5634 	s = g_strdup_printf(_("A scalar named %s already exists"), name);
5635     } else if (t == GRETL_TYPE_LIST) {
5636 	s = g_strdup_printf(_("A list named %s already exists"), name);
5637     } else if (t == GRETL_TYPE_STRING) {
5638 	s = g_strdup_printf(_("A string named %s already exists"), name);
5639     } else if (t == GRETL_TYPE_BUNDLE) {
5640 	s = g_strdup_printf(_("A bundle named %s already exists"), name);
5641     } else if (t == GRETL_TYPE_ARRAY) {
5642 	s = g_strdup_printf(_("An array named %s already exists"), name);
5643     }
5644 
5645     return s;
5646 }
5647 
object_overwrite_ok(const char * name,GretlType t,GtkWidget * parent)5648 static int object_overwrite_ok (const char *name, GretlType t,
5649 				GtkWidget *parent)
5650 {
5651     gchar *info = exists_string(name, t);
5652     gchar *msg = g_strdup_printf("%s\n%s", info, _("OK to overwrite it?"));
5653     int resp;
5654 
5655     resp = yes_no_dialog("gretl", msg, parent);
5656     g_free(info);
5657     g_free(msg);
5658 
5659     return (resp == GRETL_YES);
5660 }
5661 
5662 /* note: returns non-zero if the varname is not acceptable */
5663 
real_gui_validate_varname(const char * name,GretlType t,int allow_overwrite,GtkWidget * parent)5664 static int real_gui_validate_varname (const char *name,
5665 				      GretlType t,
5666 				      int allow_overwrite,
5667 				      GtkWidget *parent)
5668 {
5669     int i, n = strlen(name);
5670     char namebit[VNAMELEN];
5671     unsigned char c;
5672     int err = 0;
5673 
5674     *namebit = '\0';
5675 
5676     if (n > VNAMELEN - 1) {
5677 	strncat(namebit, name, VNAMELEN - 1);
5678 	errbox_printf(_("Variable name %s... is too long\n"
5679 			"(the max is %d characters)"), namebit,
5680 		      VNAMELEN - 1);
5681 	err = 1;
5682     } else if (!(isalpha(*name))) {
5683 	errbox_printf(_("First char of name ('%c') is bad\n"
5684 			"(first must be alphabetical)"), *name);
5685 	err = 1;
5686     } else {
5687 	for (i=1; i<n && !err; i++) {
5688 	    c = (unsigned char) name[i];
5689 
5690 	    if ((!(isalpha(c)) && !(isdigit(c)) && c != '_') || c > 127) {
5691 		errbox_printf(_("Name contains an illegal char (in place %d)\n"
5692 				"Use only unaccented letters, digits and underscore"),
5693 			      i + 1);
5694 		err = 1;
5695 	    }
5696 	}
5697     }
5698 
5699     if (!err && t != GRETL_TYPE_NONE) {
5700 	/* check for variable type collisions */
5701 	GretlType t0 = gretl_type_from_name(name, dataset);
5702 
5703 	if (t0 != GRETL_TYPE_NONE) {
5704 	    /* there's already a variable of this name */
5705 	    if (t == t0 && allow_overwrite) {
5706 		/* the types agree: overwrite? */
5707 		err = !object_overwrite_ok(name, t, parent);
5708 	    } else {
5709 		/* the types disgree: won't work */
5710 		gchar *msg = exists_string(name, t0);
5711 
5712 		errbox(msg);
5713 		g_free(msg);
5714 		err = 1;
5715 	    }
5716 	}
5717     }
5718 
5719     return err;
5720 }
5721 
5722 /* The "gui_validate_varname" family: both functions below check the
5723    putative @name for legality as a gretl variable name and return
5724    non-zero if it's not legal. In addition, both return non-zero if
5725    the name is valid but belongs to an existing variable of a type
5726    other than @type.
5727 
5728    They diverge in this respect:
5729 
5730    gui_validate_varname_strict: unconditionally returns non-zero
5731    if there's an existing variable of the same name, even if it's
5732    of type @type.
5733 
5734    gui_validate_varname: checks with the user whether overwriting is
5735    OK in the case where a variable of type @type already exists; if
5736    so, it's assumed that the distinction between redefining a variable
5737    and adding a new variable is handled by the caller.
5738 */
5739 
gui_validate_varname_strict(const char * name,GretlType type,GtkWidget * parent)5740 int gui_validate_varname_strict (const char *name, GretlType type,
5741 				 GtkWidget *parent)
5742 {
5743     return real_gui_validate_varname(name, type, 0, parent);
5744 }
5745 
gui_validate_varname(const char * name,GretlType type,GtkWidget * parent)5746 int gui_validate_varname (const char *name, GretlType type,
5747 			  GtkWidget *parent)
5748 {
5749     return real_gui_validate_varname(name, type, 1, parent);
5750 }
5751 
popup_menu_handler(GtkWidget * widget,GdkEventButton * event,gpointer data)5752 gint popup_menu_handler (GtkWidget *widget, GdkEventButton *event,
5753 			 gpointer data)
5754 {
5755     if (right_click(event)) {
5756 	gtk_menu_popup(GTK_MENU(data), NULL, NULL, NULL, NULL,
5757 		       event->button, event->time);
5758 	return TRUE;
5759     }
5760 
5761     return FALSE;
5762 }
5763 
add_popup_item(const gchar * label,GtkWidget * menu,GCallback callback,gpointer data)5764 void add_popup_item (const gchar *label, GtkWidget *menu,
5765 		     GCallback callback,
5766 		     gpointer data)
5767 {
5768     GtkWidget *item;
5769 
5770     item = gtk_menu_item_new_with_label(label);
5771     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
5772     g_signal_connect(G_OBJECT(item), "activate",
5773 		     G_CALLBACK(callback), data);
5774     gtk_widget_show(item);
5775 }
5776 
gui_get_plugin_function(const char * funcname)5777 void *gui_get_plugin_function (const char *funcname)
5778 {
5779     void *func;
5780 
5781     func = get_plugin_function(funcname);
5782     if (func == NULL) {
5783 	errbox(gretl_errmsg_get());
5784     }
5785 
5786     return func;
5787 }
5788 
double_underscores(char * targ,const char * src)5789 char *double_underscores (char *targ, const char *src)
5790 {
5791     char *p = targ;
5792 
5793     while (*src) {
5794 	if (*src == '_') {
5795 	    *p++ = '_';
5796 	    *p++ = '_';
5797 	} else {
5798 	    *p++ = *src;
5799 	}
5800 	src++;
5801     }
5802     *p = '\0';
5803 
5804     return targ;
5805 }
5806 
double_underscores_new(const char * src)5807 gchar *double_underscores_new (const char *src)
5808 {
5809     const char *s = src;
5810     gchar *ret;
5811     int n = 0;
5812 
5813     while (*s && (s = strchr(s, '_')) != NULL) {
5814 	n++;
5815 	s++;
5816     }
5817 
5818     ret = g_malloc(strlen(src) + n + 1);
5819 
5820     return double_underscores(ret, src);
5821 }
5822 
adjust_fontspec_string(char * targ,const char * src,int mod)5823 char *adjust_fontspec_string (char *targ, const char *src,
5824 			      int mod)
5825 {
5826     char *p, c0, c1;
5827 
5828     strcpy(targ, src);
5829 
5830     if (mod == ADD_COMMA) {
5831 	c0 = ' ';
5832 	c1 = ',';
5833     } else {
5834 	c0 = ',';
5835 	c1 = ' ';
5836     }
5837 
5838     p = strrchr(targ, c0);
5839     if (p != NULL && isdigit(p[1])) {
5840 	*p = c1;
5841     }
5842 
5843     return targ;
5844 }
5845 
got_printable_output(PRN * prn)5846 static int got_printable_output (PRN *prn)
5847 {
5848     int ret = 0;
5849 
5850     if (prn == NULL) {
5851 	warnbox(_("No output was produced"));
5852     } else {
5853 	const char *buf = gretl_print_get_buffer(prn);
5854 
5855 	if (string_is_blank(buf)) {
5856 	    warnbox(_("No output was produced"));
5857 	    gretl_print_destroy(prn);
5858 	} else {
5859 	    ret = 1;
5860 	}
5861     }
5862 
5863     return ret;
5864 }
5865 
5866 #ifdef G_OS_WIN32
5867 
5868 /* MS Windows variants of functions to exec some third-party
5869    programs */
5870 
win32_run_R_sync(const char * buf,gretlopt opt)5871 static void win32_run_R_sync (const char *buf, gretlopt opt)
5872 {
5873     PRN *prn = NULL;
5874     int err;
5875 
5876     if (bufopen(&prn)) {
5877 	return;
5878     }
5879 
5880     err = execute_R_buffer(buf, dataset, opt, prn);
5881 
5882     if (err) {
5883 	gui_errmsg(err);
5884     } else {
5885 	view_buffer(prn, 78, 350, _("gretl: script output"),
5886 		    PRINT, NULL);
5887     }
5888 }
5889 
5890 /* win32 version */
5891 
run_foreign_script(gchar * buf,int lang,gretlopt opt)5892 void run_foreign_script (gchar *buf, int lang, gretlopt opt)
5893 {
5894     const char *fname = NULL;
5895     int err;
5896 
5897     opt |= OPT_G;
5898 
5899     /* note: as things stand, the @fname we obtain here
5900        (composed in gretl_foreign.c) will be in the locale
5901        encoding, ready to pass on the Windows command line
5902        as in "foreign.exe fname"; this composite string is
5903        given to gretl_win32_grab_output() or gretl_spawn()
5904        below.
5905     */
5906 
5907     err = write_gretl_foreign_script(buf, lang, opt, dataset, &fname);
5908 
5909     if (err) {
5910 	gui_errmsg(err);
5911     } else {
5912 	PRN *prn = NULL;
5913 	gchar *cmd = NULL;
5914 
5915 	if (bufopen(&prn)) {
5916 	    return;
5917 	}
5918 
5919 	if (lang == LANG_OX) {
5920 	    cmd = g_strdup_printf("\"%s\" \"%s\"", gretl_oxl_path(), fname);
5921 	} else if (lang == LANG_PYTHON) {
5922 	    cmd = g_strdup_printf("\"%s\" \"%s\"", gretl_python_path(), fname);
5923 	} else if (lang == LANG_JULIA) {
5924 	    cmd = g_strdup_printf("\"%s\" \"%s\"", gretl_julia_path(), fname);
5925 	} else if (lang == LANG_STATA) {
5926 	    cmd = g_strdup_printf("\"%s\" /e do \"%s\"", gretl_stata_path(), fname);
5927 	} else if (lang == LANG_OCTAVE) {
5928 	    cmd = g_strdup_printf("\"%s\" -q \"%s\"", gretl_octave_path(), fname);
5929 	}
5930 
5931 	if (lang == LANG_STATA) {
5932 	    gchar *buf = NULL;
5933 
5934 	    gretl_chdir(gretl_workdir());
5935 	    remove("gretltmp.log");
5936 	    err = gretl_spawn(cmd);
5937 
5938 	    if (g_file_get_contents("gretltmp.log", &buf, NULL, NULL)) {
5939 		pputs(prn, buf);
5940 		g_free(buf);
5941 		pputc(prn, '\n');
5942 	    }
5943 	} else {
5944 	    err = gretl_win32_pipe_output(cmd, gretl_dotdir(), OPT_NONE, prn);
5945 	}
5946 
5947 	if (got_printable_output(prn)) {
5948 	    /* note: this check destroys @prn on failure */
5949 	    view_buffer(prn, 78, 350, _("gretl: script output"), PRINT, NULL);
5950 	} else if (err) {
5951 	    gui_errmsg(err);
5952 	}
5953 
5954 	g_free(cmd);
5955     }
5956 }
5957 
5958 #else /* some non-Windows functions follow */
5959 
browser_open(const char * url)5960 int browser_open (const char *url)
5961 {
5962 # if defined(OS_OSX)
5963     return osx_open_url(url);
5964 # else
5965     return gretl_fork("Browser", url, NULL);
5966 # endif
5967 }
5968 
5969 /* Start an R session in asynchronous (interactive) mode.
5970    Note that there's a separate win32 function for this
5971    in gretlwin32.c.
5972 */
5973 
start_R_async(void)5974 static void start_R_async (void)
5975 {
5976     char *s0 = NULL, *s1 = NULL, *s2 = NULL;
5977     int n = -1;
5978 
5979     s0 = mymalloc(64);
5980     s1 = mymalloc(32);
5981     s2 = mymalloc(32);
5982 
5983     if (s0 != NULL && s1 != NULL && s2 != NULL) {
5984 	*s0 = *s1 = *s2 = '\0';
5985 	/* probably "xterm -e R" or similar */
5986 	n = sscanf(Rcommand, "%63s %31s %31s", s0, s1, s2);
5987     }
5988 
5989     if (n == 0) {
5990 	errbox(_("No command was supplied to start R"));
5991     } else if (n > 0) {
5992 	char *supp1 = "--no-init-file";
5993 	char *supp2 = "--no-restore-data";
5994 	gchar *argv[6];
5995 	GError *error = NULL;
5996 	gboolean ok;
5997 	int i = 0;
5998 
5999 	argv[i++] = s0;
6000 	if (n > 1) {
6001 	    argv[i++] = s1;
6002 	}
6003 	if (n > 2) {
6004 	    argv[i++] = s2;
6005 	}
6006 	argv[i++] = supp1;
6007 	argv[i++] = supp2;
6008 	argv[i++] = NULL;
6009 
6010 	ok = g_spawn_async(NULL,
6011 			   argv,
6012 			   NULL,
6013 			   G_SPAWN_SEARCH_PATH,
6014 			   NULL,
6015 			   NULL,
6016 			   NULL,
6017 			   &error);
6018 
6019 	if (error != NULL) {
6020 	    errbox(error->message);
6021 	    g_error_free(error);
6022 	} else if (!ok) {
6023 	    gui_errmsg(E_EXTERNAL);
6024 	    g_error_free(error);
6025 	}
6026     }
6027 
6028     free(s0);
6029     free(s1);
6030     free(s2);
6031 }
6032 
6033 /* run R, Ox, etc., in synchronous (batch) mode and display the
6034    results in a gretl window: non-Windows variant
6035 */
6036 
run_prog_sync(char ** argv,int lang)6037 static void run_prog_sync (char **argv, int lang)
6038 {
6039     gchar *sout = NULL;
6040     gchar *errout = NULL;
6041     gint status = 0;
6042     GError *gerr = NULL;
6043     PRN *prn = NULL;
6044 
6045     if (lang == LANG_STATA) {
6046 	/* control location of Stata log file */
6047 	gretl_chdir(gretl_workdir());
6048 	remove("gretltmp.log");
6049     }
6050 
6051     g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
6052 		 NULL, NULL, &sout, &errout,
6053 		 &status, &gerr);
6054 
6055     if (gerr != NULL) {
6056 	errbox(gerr->message);
6057 	g_error_free(gerr);
6058     } else if (status != 0) {
6059 	if (errout != NULL && *errout != '\0') {
6060 	    if (strlen(errout) < MAXLEN) {
6061 		errbox(errout);
6062 	    } else {
6063 		bufopen(&prn);
6064 		pputs(prn, errout);
6065 	    }
6066 	} else if (sout != NULL && *sout != '\0') {
6067 	    if (strlen(sout) < MAXLEN) {
6068 		errbox(sout);
6069 	    } else {
6070 		bufopen(&prn);
6071 		pputs(prn, sout);
6072 	    }
6073 	} else {
6074 	    errbox_printf("%s exited with status %d", argv[0], status);
6075 	}
6076     } else if (lang == LANG_STATA) {
6077 	/* read log file */
6078 	gchar *buf = NULL;
6079 
6080 	if (g_file_get_contents("gretltmp.log", &buf, NULL, NULL)) {
6081 	    bufopen(&prn);
6082 	    pputs(prn, buf);
6083 	    g_free(buf);
6084 	    pputc(prn, '\n');
6085 	}
6086     } else {
6087 	/* read good old stdout */
6088 	if (!string_is_blank(sout)) {
6089 	    bufopen(&prn);
6090 	    pputs(prn, sout);
6091 	}
6092     }
6093 
6094     if (got_printable_output(prn)) {
6095 	view_buffer(prn, 78, 350, _("gretl: script output"), PRINT, NULL);
6096     }
6097 
6098     g_free(sout);
6099     g_free(errout);
6100 }
6101 
run_R_sync(void)6102 static void run_R_sync (void)
6103 {
6104     gchar *argv[] = {
6105 	"R",
6106 	"--no-save",
6107 	"--no-init-file",
6108 	"--no-restore-data",
6109 	"--slave",
6110 	NULL
6111     };
6112 
6113     run_prog_sync(argv, LANG_R);
6114 }
6115 
run_foreign_script(gchar * buf,int lang,gretlopt opt)6116 void run_foreign_script (gchar *buf, int lang, gretlopt opt)
6117 {
6118     const char *fname = NULL;
6119     int err;
6120 
6121     opt |= OPT_G;
6122 
6123     err = write_gretl_foreign_script(buf, lang, opt, dataset, &fname);
6124 
6125     if (err) {
6126 	gui_errmsg(err);
6127     } else {
6128 	gchar *argv[6];
6129 
6130 	if (lang == LANG_OCTAVE && (opt & OPT_Y)) {
6131 	    gretl_chdir(gretl_workdir());
6132 	}
6133 
6134 	if (lang == LANG_OX) {
6135 	    argv[0] = (gchar *) gretl_oxl_path();
6136 	    argv[1] = (gchar *) fname;
6137 	    argv[2] = NULL;
6138 	} else if (lang == LANG_PYTHON) {
6139 	    argv[0] = (gchar *) gretl_python_path();
6140 	    argv[1] = (gchar *) fname;
6141 	    argv[2] = NULL;
6142 	} else if (lang == LANG_JULIA) {
6143 	    argv[0] = (gchar *) gretl_julia_path();
6144 	    argv[1] = (gchar *) fname;
6145 	    argv[2] = NULL;
6146 	} else if (lang == LANG_STATA) {
6147 	    argv[0] = (gchar *) gretl_stata_path();
6148 	    argv[1] = (gchar *) "-q";
6149 	    argv[2] = (gchar *) "-b";
6150 	    argv[3] = (gchar *) "do";
6151 	    argv[4] = (gchar *) fname;
6152 	    argv[5] = NULL;
6153 	} else if (lang == LANG_OCTAVE) {
6154 	    argv[0] = (gchar *) gretl_octave_path();
6155 	    argv[1] = (gchar *) "-q";
6156 	    argv[2] = (gchar *) fname;
6157 	    argv[3] = NULL;
6158 	}
6159 
6160 	run_prog_sync(argv, lang);
6161     }
6162 }
6163 
6164 #endif /* !G_OS_WIN32 */
6165 
6166 /* driver for starting R, either interactive or in batch mode */
6167 
start_R(const char * buf,int send_data,int interactive)6168 void start_R (const char *buf, int send_data, int interactive)
6169 {
6170     gretlopt Ropt = OPT_G;
6171     int err = 0;
6172 
6173     if (send_data && !data_status) {
6174 	warnbox(_("Please open a data file first"));
6175 	return;
6176     }
6177 
6178     if (interactive) {
6179 	Ropt |= OPT_I;
6180     }
6181 
6182     if (send_data) {
6183 	Ropt |= OPT_D;
6184 	if (annual_data(dataset) || quarterly_or_monthly(dataset)) {
6185 	    const char *opts[] = {
6186 		N_("multiple time series object"),
6187 		N_("data frame")
6188 	    };
6189 	    int resp;
6190 
6191 	    resp = radio_dialog(NULL, _("Send data as"), opts, 2, 0, 0, NULL);
6192 	    if (resp < 0) {
6193 		return;
6194 	    } else if (resp == 1) {
6195 		Ropt |= OPT_F;
6196 	    }
6197 	}
6198     }
6199 
6200     /* On Windows in non-interactive mode, don't write
6201        these files here; that will be handled later
6202     */
6203 #ifdef G_OS_WIN32
6204     if (interactive) {
6205 	err = write_gretl_R_files(buf, dataset, Ropt);
6206     }
6207 #else
6208     err = write_gretl_R_files(buf, dataset, Ropt);
6209 #endif
6210 
6211     if (err) {
6212 	gui_errmsg(err);
6213 	delete_gretl_R_files();
6214     } else if (interactive) {
6215 #ifdef G_OS_WIN32
6216 	win32_start_R_async();
6217 #else
6218 	start_R_async();
6219 #endif
6220     } else {
6221 	/* non-interactive */
6222 #ifdef G_OS_WIN32
6223 	win32_run_R_sync(buf, Ropt);
6224 #else
6225 	run_R_sync();
6226 #endif
6227     }
6228 }
6229 
verbose_gerror_report(GError * gerr,const char * src)6230 void verbose_gerror_report (GError *gerr, const char *src)
6231 {
6232     fprintf(stderr, "GError details from %s\n"
6233 	    " message: '%s'\n domain = %d, code = %d\n",
6234 	    src, gerr->message, gerr->domain, gerr->code);
6235 }
6236 
6237 /* Note: simplified 2020-12-08 on the assumption that filenames
6238    within gretl will be in UTF-8 on all platforms.
6239 */
6240 
gretl_file_get_contents(const gchar * fname,gchar ** contents,gsize * size)6241 int gretl_file_get_contents (const gchar *fname, gchar **contents,
6242 			     gsize *size)
6243 {
6244     GError *gerr = NULL;
6245     gboolean ok = 0;
6246 
6247     ok = g_file_get_contents(fname, contents, size, &gerr);
6248 
6249     if (gerr != NULL) {
6250 	verbose_gerror_report(gerr, "g_file_get_contents");
6251 	errbox(gerr->message);
6252 	g_error_free(gerr);
6253     }
6254 
6255     return ok ? 0 : E_FOPEN;
6256 }
6257 
print_today(void)6258 const char *print_today (void)
6259 {
6260     static char timestr[16];
6261     struct tm *local;
6262     time_t t;
6263 
6264     t = time(NULL);
6265     local = localtime(&t);
6266     strftime(timestr, 15, "%Y-%m-%d", local);
6267 
6268     return timestr;
6269 }
6270