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 /* menustate.c: status of menus etc. */
21 
22 #include "gretl.h"
23 #include "console.h"
24 #include "guiprint.h"
25 #include "ssheet.h"
26 #include "selector.h"
27 #include "varinfo.h"
28 #include "uservar.h"
29 #include "treeutils.h"
30 #include "session.h"
31 #include "gretl_ipc.h"
32 #include "gretl_www.h"
33 #include "fncall.h"
34 #include "menustate.h"
35 
refresh_data(void)36 void refresh_data (void)
37 {
38     if (data_status) {
39         populate_varlist();
40         set_sample_label(dataset);
41     }
42 }
43 
flip(GtkUIManager * ui,const char * path,gboolean s)44 void flip (GtkUIManager *ui, const char *path, gboolean s)
45 {
46     if (ui != NULL) {
47         GtkAction *a = gtk_ui_manager_get_action(ui, path);
48 
49         if (a != NULL) {
50             gtk_action_set_sensitive(a, s);
51         } else {
52             fprintf(stderr, "Failed to flip state of \"%s\"\n", path);
53         }
54     }
55 }
56 
57 /* by using gretl_set_window_modal() we make the main
58    window visibly insensitive */
59 
60 static int modcount;
61 
increment_modal_count(GtkWidget * w)62 static void increment_modal_count (GtkWidget *w)
63 {
64     if (modcount == 0) {
65         gtk_widget_set_sensitive(mdata->main, FALSE);
66     }
67 
68     modcount++;
69 }
70 
decrement_modal_count(GtkWidget * w,gpointer p)71 static void decrement_modal_count (GtkWidget *w, gpointer p)
72 {
73     if (modcount > 0) {
74         modcount--;
75     }
76 
77     if (modcount == 0) {
78         gtk_widget_set_sensitive(mdata->main, TRUE);
79     }
80 }
81 
gretl_set_window_modal(GtkWidget * w)82 void gretl_set_window_modal (GtkWidget *w)
83 {
84     gtk_window_set_modal(GTK_WINDOW(w), TRUE);
85     increment_modal_count(w);
86     g_signal_connect(G_OBJECT(w), "destroy",
87                      G_CALLBACK(decrement_modal_count),
88                      NULL);
89 }
90 
gretl_set_window_quasi_modal(GtkWidget * w)91 void gretl_set_window_quasi_modal (GtkWidget *w)
92 {
93     increment_modal_count(w);
94     g_signal_connect(G_OBJECT(w), "destroy",
95                      G_CALLBACK(decrement_modal_count),
96                      NULL);
97 }
98 
variable_menu_state(gboolean s)99 void variable_menu_state (gboolean s)
100 {
101     if (mdata == NULL || mdata->ui == NULL) return;
102 
103     flip(mdata->ui, "/menubar/Variable", s);
104     flip(mdata->ui, "/menubar/View/xcorrgm",
105          dataset_is_time_series(dataset));
106 }
107 
view_items_state(gboolean s)108 static void view_items_state (gboolean s)
109 {
110     const char *viewpaths[] = {
111         "GraphVars",
112         "MultiPlots",
113         "summary",
114         "corr",
115         "xtab",
116         "pca",
117         "mahal",
118         NULL
119     };
120     char fullpath[32];
121     int i;
122 
123     for (i=0; viewpaths[i] != NULL; i++) {
124         sprintf(fullpath, "/menubar/View/%s", viewpaths[i]);
125         flip(mdata->ui, fullpath, s);
126     }
127 
128     flip(mdata->ui, "/menubar/View/IconView", have_session_objects());
129 
130     flip(mdata->ui, "/menubar/View/xcorrgm",
131          data_status && dataset_is_time_series(dataset));
132 }
133 
gfn_menuitems_state(void)134 static void gfn_menuitems_state (void)
135 {
136     GtkActionGroup *ag;
137     GList *aglist;
138     DataReq dreq;
139     int err;
140 
141     aglist = gtk_ui_manager_get_action_groups(mdata->ui);
142 
143     while (aglist != NULL) {
144         ag = aglist->data;
145         if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(ag), "datareq"))) {
146             dreq = pkg_get_data_requirement(ag);
147             err = check_function_needs(dataset, dreq, 0);
148             gtk_action_group_set_sensitive(ag, !err);
149         }
150         aglist = aglist->next;
151     }
152 }
153 
dataset_menubar_state(gboolean s)154 void dataset_menubar_state (gboolean s)
155 {
156     static int mail_ok = -1;
157 
158     if (mdata == NULL || mdata->ui == NULL) return;
159 
160     if (mail_ok < 0) {
161         mail_ok = curl_does_smtp();
162     }
163 
164     flip(mdata->ui, "/menubar/File/AppendData", s);
165     flip(mdata->ui, "/menubar/File/ClearData", s);
166     flip(mdata->ui, "/menubar/File/SaveData", s);
167     flip(mdata->ui, "/menubar/File/SaveDataAs", s);
168     flip(mdata->ui, "/menubar/File/ExportData", s);
169     flip(mdata->ui, "/menubar/File/MailData", mail_ok && s);
170     flip(mdata->ui, "/menubar/Data", s);
171     flip(mdata->ui, "/menubar/Add", s);
172     flip(mdata->ui, "/menubar/Sample", s);
173     flip(mdata->ui, "/menubar/Variable", s);
174     flip(mdata->ui, "/menubar/Model", s);
175 
176     view_items_state(s);
177     gfn_menuitems_state();
178 
179     if (s || !have_session_objects()) {
180         /* Either we're enabling dataset items, in which
181            case we should also enable the /View menu, or
182            we're disabling the dataset items and there are
183            no session objects, in which case /View should
184            be disabled.
185         */
186         flip(mdata->ui, "/menubar/View", s);
187     }
188 
189     flip(mdata->ui, "/menubar/File/NewData", !s);
190 
191     set_main_colheads_clickable(s);
192 }
193 
iconview_menubar_state(gboolean s)194 void iconview_menubar_state (gboolean s)
195 {
196     if (s) {
197         GtkAction *a = gtk_ui_manager_get_action(mdata->ui, "/menubar/View");
198 
199         if (a != NULL && !gtk_action_get_sensitive(a)) {
200             gtk_action_set_sensitive(a, TRUE);
201         }
202     }
203 
204     flip(mdata->ui, "/menubar/View/IconView", s);
205 }
206 
207 #define OK_MIDAS_PD(p) (p == 1 || p == 4 || p == 12)
208 
209 #define COMPACTABLE(d) (d->structure == TIME_SERIES && \
210                         (d->pd == 4 || d->pd == 12 || \
211                          d->pd == 5 || d->pd == 6 || \
212                          d->pd == 7 || d->pd == 24))
213 
214 #define EXPANSIBLE(d) (d->structure == TIME_SERIES && (d->pd == 1 || d->pd == 4))
215 
216 #define extended_ts(d) ((d)->structure == TIME_SERIES || \
217                         (d)->structure == SPECIAL_TIME_SERIES || \
218                         (d)->structure == STACKED_TIME_SERIES)
219 
time_series_menu_state(gboolean s)220 void time_series_menu_state (gboolean s)
221 {
222     gboolean sx = extended_ts(dataset);
223     gboolean panel = dataset_is_panel(dataset);
224     gboolean realpan = multi_unit_panel_sample(dataset);
225     gboolean have_map = dataset_get_mapfile(dataset) != NULL;
226     gboolean ur;
227 
228     if (mdata->ui == NULL) {
229         return;
230     }
231 
232     /* enable/disable function packages that have menu
233        attachments */
234     gfn_menuitems_state();
235 
236     /* unit-root tests: require time-series or panel data,
237        and a time series length greater than 5
238     */
239     if (panel) {
240         ur = dataset->pd > 5;
241     } else {
242         ur = s && sample_size(dataset) > 5;
243     }
244 
245     /* Plots */
246     flip(mdata->ui, "/menubar/View/GraphVars/TSPlot", sx);
247     flip(mdata->ui, "/menubar/View/MultiPlots/MultiTS", sx);
248     flip(mdata->ui, "/menubar/Variable/VarTSPlot", sx && !realpan);
249     flip(mdata->ui, "/menubar/Variable/PanPlot", realpan);
250     flip(mdata->ui, "/menubar/View/GraphVars/MapPlot", have_map);
251 
252     /* Variable menu */
253     flip(mdata->ui, "/menubar/Variable/URTests", ur);
254     if (ur && !s) {
255         /* time-series only "ur" option */
256         flip(mdata->ui, "/menubar/Variable/URTests/fractint", s);
257     }
258     flip(mdata->ui, "/menubar/Variable/URTests/levinlin", ur && panel);
259     flip(mdata->ui, "/menubar/Variable/corrgm", s);
260     flip(mdata->ui, "/menubar/Variable/pergm", s);
261     flip(mdata->ui, "/menubar/Variable/Filter", s);
262 #ifdef HAVE_X12A
263     flip(mdata->ui, "/menubar/Variable/X12A", get_x12a_ok());
264 #endif
265 #ifdef HAVE_TRAMO
266     flip(mdata->ui, "/menubar/Variable/Tramo", get_tramo_ok());
267 #endif
268     flip(mdata->ui, "/menubar/Variable/Hurst", s);
269     flip(mdata->ui, "/menubar/Variable/BDS", s);
270     flip(mdata->ui, "/menubar/Variable/tdisagg", s &&
271          quarterly_or_monthly(dataset));
272 
273     /* Model menu */
274     flip(mdata->ui, "/menubar/Model/TSModels", s);
275     flip(mdata->ui, "/menubar/Model/TSMulti", s);
276     flip(mdata->ui, "/menubar/Model/TSModels/midasreg",
277          s && OK_MIDAS_PD(dataset->pd));
278 
279     /* Sample menu */
280     flip(mdata->ui, "/menubar/Data/DataCompact",
281          s && (COMPACTABLE(dataset) || dated_weekly_data(dataset)));
282     flip(mdata->ui, "/menubar/Data/DataExpand", s && EXPANSIBLE(dataset));
283 }
284 
panel_menu_state(gboolean s)285 void panel_menu_state (gboolean s)
286 {
287     if (mdata->ui != NULL) {
288         flip(mdata->ui, "/menubar/Add/AddUnit", s);
289         flip(mdata->ui, "/menubar/Add/UnitDums", s);
290         flip(mdata->ui, "/menubar/Add/TimeDums", s);
291         flip(mdata->ui, "/menubar/Add/RangeDum", !s);
292         flip(mdata->ui, "/menubar/Model/PanelModels", s);
293         flip(mdata->ui, "/menubar/Model/LimdepModels/probit/reprobit", s);
294         if (s && dataset->pd <= 2) {
295             flip(mdata->ui, "/menubar/Model/PanelModels/dpanel", 0);
296         }
297         gfn_menuitems_state();
298     }
299 }
300 
ts_or_panel_menu_state(gboolean s)301 void ts_or_panel_menu_state (gboolean s)
302 {
303     if (mdata->ui == NULL) return;
304 
305     flip(mdata->ui, "/menubar/Data/DataSort", !s);
306 
307     flip(mdata->ui, "/menubar/Add/AddTime", s);
308     flip(mdata->ui, "/menubar/Add/lags", s);
309     flip(mdata->ui, "/menubar/Add/diff", s);
310     flip(mdata->ui, "/menubar/Add/ldiff", s);
311     flip(mdata->ui, "/menubar/Add/pcdiff", s);
312     flip(mdata->ui, "/menubar/Add/idxvals",
313          s && !dataset_is_panel(dataset));
314 
315     s = dataset_is_seasonal(dataset);
316     if (!s && dataset_is_seasonal_panel(dataset)) {
317         s = dataset->panel_pd == 4 ||
318             dataset->panel_pd == 12 ||
319             dataset->panel_pd == 24;
320     }
321 
322     flip(mdata->ui, "/menubar/Add/sdiff", s);
323     flip(mdata->ui, "/menubar/Add/PeriodDums", s);
324 }
325 
session_menu_state(gboolean s)326 void session_menu_state (gboolean s)
327 {
328     if (mdata->ui != NULL) {
329         flip(mdata->ui, "/menubar/View/IconView", s);
330         if (!s || session_is_modified()) {
331             flip(mdata->ui, "/menubar/File/SessionFiles/SaveSession", s);
332         }
333         if (!s || session_is_open()) {
334             flip(mdata->ui, "/menubar/File/SessionFiles/SaveSessionAs", s);
335         }
336     }
337 
338     if (!s && mdata->main != NULL) {
339         set_main_window_title(NULL, FALSE);
340     }
341 }
342 
restore_sample_state(gboolean s)343 void restore_sample_state (gboolean s)
344 {
345     if (mdata->ui != NULL) {
346         flip(mdata->ui, "/menubar/Sample/FullRange", s);
347     }
348 }
349 
drop_obs_state(gboolean s)350 void drop_obs_state (gboolean s)
351 {
352     if (mdata->ui != NULL) {
353         flip(mdata->ui, "/menubar/Data/RemoveObs", s);
354     }
355 }
356 
compact_data_state(gboolean s)357 void compact_data_state (gboolean s)
358 {
359     if (mdata->ui != NULL) {
360         flip(mdata->ui, "/menubar/Data/DataCompact", s);
361     }
362 }
363 
main_menus_enable(gboolean s)364 void main_menus_enable (gboolean s)
365 {
366     if (mdata->ui != NULL) {
367         flip(mdata->ui, "/menubar/File", s);
368         flip(mdata->ui, "/menubar/Tools", s);
369         flip(mdata->ui, "/menubar/Data", s);
370         flip(mdata->ui, "/menubar/View", s);
371         flip(mdata->ui, "/menubar/Add", s);
372         flip(mdata->ui, "/menubar/Sample", s);
373         flip(mdata->ui, "/menubar/Variable", s);
374         flip(mdata->ui, "/menubar/Model", s);
375     }
376 }
377 
check_var_labels_state(GtkMenuItem * item,gpointer p)378 void check_var_labels_state (GtkMenuItem *item, gpointer p)
379 {
380     gboolean s = FALSE;
381 
382     if (dataset != NULL && dataset->v > 0) {
383         if (dataset->v > 2 || strcmp(dataset->varname[1], "index")) {
384             s = TRUE;
385         }
386     }
387 
388     flip(mdata->ui, "/menubar/Data/VarLabels", s);
389 }
390 
missvals_in_selection(const int * list)391 static int missvals_in_selection (const int *list)
392 {
393     int i, vi, t;
394     int ret = 0;
395 
396     for (i=1; i<=list[0] && !ret; i++) {
397         vi = list[i];
398         for (t=dataset->t1; t<=dataset->t2; t++) {
399             if (na(dataset->Z[vi][t])) {
400                 ret = 1;
401                 break;
402             }
403         }
404     }
405 
406     return ret;
407 }
408 
uniform_corr_option(const gchar * title,gretlopt * popt)409 static int uniform_corr_option (const gchar *title, gretlopt *popt)
410 {
411     const char *opts[] = {
412         N_("Ensure uniform sample size"),
413         NULL
414     };
415     int uniform = 0;
416     int resp;
417 
418     resp = checks_only_dialog(title, NULL, opts, 1,
419                               &uniform, CORR, NULL);
420 
421     if (!canceled(resp) && uniform) {
422         *popt = OPT_N;
423     }
424 
425     return resp;
426 }
427 
right_click_corr(void)428 static void right_click_corr (void)
429 {
430     int *list = main_window_selection_as_list();
431     gretlopt opt = OPT_NONE;
432     char *buf;
433 
434     if (list != NULL && list[0] > 2 && missvals_in_selection(list)) {
435         gchar *title;
436         int resp;
437 
438         title = g_strdup_printf("gretl: %s", _("correlation matrix"));
439         resp = uniform_corr_option(title, &opt);
440         g_free(title);
441 
442         if (canceled(resp)) {
443             return;
444         }
445     }
446 
447     free(list);
448     buf = main_window_selection_as_string();
449 
450     if (buf != NULL) {
451         do_menu_op(CORR, buf, opt, NULL);
452         free(buf);
453     }
454 }
455 
is_integer_valued(int v)456 static int is_integer_valued (int v)
457 {
458     const double *x = dataset->Z[v];
459     double x0 = NADBL;
460     int nonconst = 0;
461     int t, n = 0;
462 
463     for (t=dataset->t1; t<=dataset->t2; t++) {
464         if (na(x[t])) {
465             continue;
466         }
467         if (!ok_int(x[t])) {
468             /* out of integer bounds */
469             return 0;
470         }
471         if (x[t] != floor(x[t])) {
472             /* non-integral */
473             return 0;
474         }
475         if (na(x0)) {
476             x0 = x[t];
477         } else if (x[t] != x0) {
478             nonconst = 1;
479         }
480         n++;
481     }
482 
483     return n > 2 && nonconst;
484 }
485 
series_is_dummifiable(int v)486 int series_is_dummifiable (int v)
487 {
488     if (series_is_discrete(dataset, v)) {
489         /* must be OK */
490         return 1;
491     } else if (gretl_isdummy(0, dataset->n-1, dataset->Z[v])) {
492         /* already a 0/1 dummy */
493         return 0;
494     } else {
495         /* could be OK? */
496         return is_integer_valued(v);
497     }
498 }
499 
dataset_could_be_midas(const DATASET * dset)500 static int dataset_could_be_midas (const DATASET *dset)
501 {
502     if (dataset_is_time_series(dset) &&
503         (dset->pd == 1 || dset->pd == 4 || dset->pd == 12)) {
504         return 1;
505     } else {
506         return 0;
507     }
508 }
509 
510 enum MenuIdx_ {
511     MNU_MPLOT,
512     MNU_MSAVE,
513     MNU_DISP,
514     MNU_EDIT,
515     MNU_STATS,
516     MNU_TPLOT,
517     MNU_PPLOT,
518     MNU_FDIST,
519     MNU_BPLOT,
520     MNU_CGRAM,
521     MNU_PGRAM,
522     MNU_ATTRS,
523     MNU_CORR,
524     MNU_COND,
525     MNU_XCORR,
526     MNU_SCATR,
527     MNU_CLIPB,
528     MNU_DELET,
529     MNU_SEPAR,
530     MNU_LOGS,
531     MNU_DIFF,
532     MNU_PCDIF,
533     MNU_IDXV,
534     MNU_DUMIF,
535     MNU_GENR,
536     MNU_LIST,
537     MNU_TDIS
538 };
539 
540 enum MDSIdx_ {
541     MDS_DISP,
542     MDS_TPLOT,
543     MDS_LOGS,
544     MDS_DIFF,
545     MDS_SEPAR,
546     MDS_CDISP,
547     MDS_CPLOT,
548     MDS_CEDIT,
549     MDS_CDEL,
550     MDS_GENR,
551     MDS_LIST
552 };
553 
554 enum MenuTarg_ {
555     T_SINGLE,
556     T_MULTI,
557     T_BOTH,
558 };
559 
560 typedef enum MenuIdx_ MenuIdx;
561 typedef enum MDSIdx_ MDSIdx;
562 typedef enum MenuTarg_ MenuTarg;
563 
564 struct popup_entries {
565     MenuIdx idx;       /* one of the MenuIdxvalues above */
566     const char *str;   /* translatable string */
567     MenuTarg target;   /* one of the MenuTarget values above */
568 };
569 
570 struct mpopup_entries {
571     MDSIdx idx;        /* one of the MDSIdx values above */
572     const char *str;   /* translatable string */
573 };
574 
575 struct popup_entries main_pop_entries[] = {
576     { MNU_MPLOT, N_("Display map..."), T_BOTH },
577     { MNU_MSAVE, N_("Write map as GeoJSON..."), T_BOTH },
578     { MNU_SEPAR, NULL, T_BOTH },
579     { MNU_DISP,  N_("Display values"), T_BOTH },
580     { MNU_EDIT,  N_("Edit values"), T_BOTH },
581     { MNU_STATS, N_("Summary statistics"), T_BOTH },
582     { MNU_TPLOT, N_("Time series plot"), T_BOTH },
583     { MNU_PPLOT, N_("Panel plot..."), T_SINGLE },
584     { MNU_FDIST, N_("Frequency distribution"), T_SINGLE },
585     { MNU_BPLOT, N_("Boxplot"), T_SINGLE },
586     { MNU_CGRAM, N_("Correlogram"), T_SINGLE, },
587     { MNU_PGRAM, N_("Periodogram"), T_SINGLE, },
588     { MNU_ATTRS, N_("Edit attributes"), T_SINGLE },
589     { MNU_CORR,  N_("Correlation matrix"), T_MULTI },
590     { MNU_COND,  N_("Collinearity"), T_MULTI },
591     { MNU_XCORR, N_("Cross-correlogram"), T_MULTI },
592     { MNU_SCATR, N_("XY scatterplot"), T_MULTI },
593     { MNU_CLIPB, N_("Copy to clipboard"), T_BOTH },
594     { MNU_DELET, N_("Delete"), T_BOTH },
595     { MNU_SEPAR, NULL, T_BOTH },
596     { MNU_LOGS,  N_("Add log"), T_SINGLE },
597     { MNU_DIFF,  N_("Add difference"), T_SINGLE },
598     { MNU_PCDIF, N_("Add percent change..."), T_SINGLE },
599     { MNU_IDXV,  N_("Add index values..."), T_SINGLE },
600     { MNU_DUMIF, N_("Dummify..."), T_SINGLE },
601     { MNU_LOGS,  N_("Add logs"), T_MULTI },
602     { MNU_DIFF,  N_("Add differences"), T_MULTI },
603     { MNU_PCDIF, N_("Add percent changes..."), T_MULTI },
604     { MNU_IDXV,  N_("Add index values..."), T_MULTI },
605     { MNU_TDIS,  N_("Disaggregate..."), T_SINGLE },
606     { MNU_SEPAR, NULL, T_BOTH },
607     { MNU_GENR,  N_("Define new variable..."), T_BOTH },
608     { MNU_LIST,  N_("Define list"), T_MULTI }
609 };
610 
611 struct mpopup_entries midas_pop_entries[] = {
612     { MDS_DISP,  N_("Display values") },
613     { MDS_TPLOT, N_("Time series plot") },
614     { MDS_LOGS,  N_("Add logs...") },
615     { MDS_DIFF,  N_("Add differences...") },
616     { MDS_SEPAR, NULL },
617     { MDS_CDISP, N_("Display components") },
618     { MDS_CPLOT, N_("Plot components") },
619     { MDS_CEDIT, N_("Edit components") },
620     { MDS_CDEL,  N_("Delete components") },
621     { MDS_SEPAR, NULL },
622     { MDS_GENR,  N_("Define new variable...") },
623     { MDS_LIST,  N_("Define list") }
624 };
625 
var_popup_click(GtkWidget * w,gpointer p)626 static gint var_popup_click (GtkWidget *w, gpointer p)
627 {
628     MenuIdx i = GPOINTER_TO_INT(p);
629     int v = mdata_active_var();
630 
631     switch (i) {
632     case MNU_DISP:
633         display_var();
634         break;
635     case MNU_STATS:
636         do_menu_op(VAR_SUMMARY, NULL, OPT_NONE, NULL);
637         break;
638     case MNU_TPLOT:
639     case MNU_PPLOT:
640         do_graph_var(v);
641         break;
642     case MNU_MPLOT:
643         map_plot_callback(v);
644         break;
645     case MNU_MSAVE:
646         map_save_callback();
647         break;
648     case MNU_FDIST:
649         do_freq_dist();
650         break;
651     case MNU_BPLOT:
652         menu_boxplot_callback(v);
653         break;
654     case MNU_CGRAM:
655         do_corrgm();
656         break;
657     case MNU_PGRAM:
658         do_pergm(NULL);
659         break;
660     case MNU_ATTRS:
661         varinfo_dialog(v);
662         break;
663     case MNU_EDIT:
664         show_spreadsheet(SHEET_EDIT_VARLIST);
665         break;
666     case MNU_CLIPB:
667         csv_selected_to_clipboard();
668         break;
669     case MNU_DELET:
670         delete_single_var(v);
671         break;
672     case MNU_LOGS:
673     case MNU_DIFF:
674         add_logs_etc(i == MNU_LOGS ? LOGS : DIFF, v, 0);
675         break;
676     case MNU_PCDIF:
677         single_percent_change_dialog(v, 0);
678         break;
679     case MNU_IDXV:
680         single_percent_change_dialog(v, 1);
681         break;
682     case MNU_DUMIF:
683         add_discrete_dummies(v);
684         break;
685     case MNU_TDIS:
686 	tdisagg_dialog(v);
687 	break;
688     case MNU_GENR:
689         genr_callback();
690         break;
691     default:
692         break;
693     }
694 
695     gtk_widget_destroy(mdata->popup);
696 
697     return FALSE;
698 }
699 
build_var_popup(int selvar)700 GtkWidget *build_var_popup (int selvar)
701 {
702     GtkWidget *menu, *item;
703     int i, j, n = G_N_ELEMENTS(main_pop_entries);
704     int real_panel = multi_unit_panel_sample(dataset);
705     int have_map = dataset_get_mapfile(dataset) != NULL;
706     int nullbak = 0;
707 
708     menu = gtk_menu_new();
709 
710     for (j=0; j<n; j++) {
711         if (main_pop_entries[j].target == T_MULTI) {
712             /* not applicable */
713             continue;
714         }
715         i = main_pop_entries[j].idx;
716         if (i == MNU_SEPAR) {
717             if (!nullbak) {
718                 /* don't insert two consecutive separators */
719                 item = gtk_separator_menu_item_new();
720                 gtk_widget_show(item);
721                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
722                 nullbak = 1;
723             }
724             continue;
725         }
726         if (real_panel && (i == MNU_TPLOT || i == MNU_BPLOT)) {
727             /* don't offer regular ts or boxplot */
728             continue;
729         }
730         if (!real_panel && i == MNU_PPLOT) {
731             /* don't offer panel plot */
732             continue;
733         }
734         if (!have_map && (i == MNU_MPLOT || i == MNU_MSAVE)) {
735             /* don't offer map plot or save */
736             continue;
737         }
738         if ((i == MNU_CGRAM || i == MNU_PGRAM || i == MNU_IDXV) &&
739             !dataset_is_time_series(dataset)) {
740             /* correlogram, periodogram, index values */
741             continue;
742         }
743         if ((i == MNU_TPLOT || i == MNU_DIFF || i == MNU_PCDIF) &&
744             !extended_ts(dataset)) {
745             /* time-series plot, difference, percent change */
746             continue;
747         }
748         if (i == MNU_BPLOT && dataset_is_time_series(dataset)) {
749             /* skip boxplot option */
750             continue;
751         }
752         if (i == MNU_DUMIF && !series_is_dummifiable(selvar)) {
753             /* skip dummify option */
754             continue;
755         }
756         if (i == MNU_STATS && is_string_valued(dataset, selvar)) {
757             /* skip (numerical) summary stats option */
758             continue;
759         }
760         if (i == MNU_TDIS && series_get_orig_pd(dataset, selvar) == 0) {
761             /* skip temporal disaggregation option */
762             continue;
763         }
764         item = gtk_menu_item_new_with_label(_(main_pop_entries[j].str));
765         g_signal_connect(G_OBJECT(item), "activate",
766                          G_CALLBACK(var_popup_click),
767                          GINT_TO_POINTER(i));
768         gtk_widget_show(item);
769         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
770 
771         nullbak = 0;
772     }
773 
774     return menu;
775 }
776 
selection_popup_click(GtkWidget * w,gpointer p)777 static gint selection_popup_click (GtkWidget *w, gpointer p)
778 {
779     MenuIdx i = GPOINTER_TO_INT(p);
780     int ci = 0;
781 
782     if (i == MNU_STATS) {
783         ci = SUMMARY;
784     } else if (i == MNU_CORR) {
785         ci = CORR;
786     }
787 
788     if (ci == CORR) {
789         right_click_corr();
790     } else if (ci != 0) {
791         char *buf = main_window_selection_as_string();
792 
793         if (buf != NULL) {
794             do_menu_op(ci, buf, OPT_NONE, NULL);
795             free(buf);
796         }
797     } else if (i == MNU_DISP) {
798         display_selected();
799     } else if (i == MNU_COND) {
800         cond_number_callback();
801     } else if (i == MNU_XCORR)  {
802         xcorrgm_callback();
803     } else if (i == MNU_TPLOT) {
804         plot_from_selection(GR_PLOT);
805     } else if (i == MNU_SCATR)  {
806         plot_from_selection(GR_XY);
807     } else if (i == MNU_MPLOT) {
808         map_plot_callback(0);
809     } else if (i == MNU_MSAVE) {
810 	map_save_callback();
811     } else if (i == MNU_EDIT)  {
812         show_spreadsheet(SHEET_EDIT_VARLIST);
813     } else if (i == MNU_CLIPB) {
814         csv_selected_to_clipboard();
815     } else if (i == MNU_DELET)  {
816         delete_selected_vars();
817     } else if (i == MNU_LOGS || i == MNU_DIFF)  {
818         add_logs_etc(i == MNU_LOGS ? LOGS : DIFF, 0, 0);
819     } else if (i == MNU_PCDIF) {
820         multi_percent_change_dialog(0);
821     } else if (i == MNU_IDXV) {
822         multi_percent_change_dialog(1);
823     } else if (i == MNU_LIST) {
824         make_list_from_main();
825     } else if (i == MNU_GENR) {
826         genr_callback();
827     }
828 
829     gtk_widget_destroy(mdata->popup);
830 
831     return FALSE;
832 }
833 
build_regular_selection_popup(void)834 static GtkWidget *build_regular_selection_popup (void)
835 {
836     GtkWidget *menu, *item;
837     int i, j, n = G_N_ELEMENTS(main_pop_entries);
838     int nullbak = 0;
839 
840     menu = gtk_menu_new();
841 
842     for (j=0; j<n; j++) {
843         if (main_pop_entries[j].target == T_SINGLE) {
844             /* for single selection only */
845             continue;
846         }
847         i = main_pop_entries[j].idx;
848         if (i == MNU_SEPAR) {
849             if (!nullbak) {
850                 /* don't insert two consecutive separators */
851                 item = gtk_separator_menu_item_new();
852                 gtk_widget_show(item);
853                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
854                 nullbak = 1;
855             }
856             continue;
857         }
858         if ((i == MNU_TPLOT || i == MNU_XCORR) &&
859             !dataset_is_time_series(dataset)) {
860             continue;
861         }
862         if (i == MNU_TPLOT && !extended_ts(dataset)) {
863             continue;
864         }
865         if ((i == MNU_MPLOT || i == MNU_MSAVE) && dataset->mapfile == NULL) {
866             continue;
867         }
868         item = gtk_menu_item_new_with_label(_(main_pop_entries[j].str));
869         g_signal_connect(G_OBJECT(item), "activate",
870                          G_CALLBACK(selection_popup_click),
871                          GINT_TO_POINTER(i));
872         gtk_widget_show(item);
873         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
874         nullbak = 0;
875     }
876 
877     return menu;
878 }
879 
midas_popup_click(GtkWidget * w,gpointer p)880 static gint midas_popup_click (GtkWidget *w, gpointer p)
881 {
882     MDSIdx i = GPOINTER_TO_INT(p);
883 
884     if (i == MDS_DISP || i == MDS_TPLOT) {
885         int *list = main_window_selection_as_list();
886 
887         midas_list_callback(list, NULL, i == MDS_DISP ? PRINT : PLOT);
888         free(list);
889     } else if (i == MDS_LOGS || i == MDS_DIFF)  {
890         add_logs_etc(i == MDS_LOGS ? LOGS : DIFF, 0, 1);
891     } else if (i == MDS_CDISP) {
892         display_selected();
893     } else if (i == MDS_CPLOT) {
894         plot_from_selection(GR_PLOT);
895     } else if (i == MDS_CEDIT) {
896         show_spreadsheet(SHEET_EDIT_VARLIST);
897     } else if (i == MDS_CDEL) {
898         delete_selected_vars();
899     } else if (i == MDS_LIST) {
900         make_list_from_main();
901     } else if (i == MDS_GENR) {
902         genr_callback();
903     }
904 
905     gtk_widget_destroy(mdata->popup);
906 
907     return FALSE;
908 }
909 
build_midas_popup(void)910 static GtkWidget *build_midas_popup (void)
911 {
912     GtkWidget *menu, *item;
913     int n = G_N_ELEMENTS(midas_pop_entries);
914     int i, j;
915 
916     menu = gtk_menu_new();
917 
918     for (j=0; j<n; j++) {
919         i = midas_pop_entries[j].idx;
920         if (i == MDS_SEPAR) {
921             item = gtk_separator_menu_item_new();
922             gtk_widget_show(item);
923             gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
924             continue;
925         }
926         item = gtk_menu_item_new_with_label(_(midas_pop_entries[j].str));
927         g_signal_connect(G_OBJECT(item), "activate",
928                          G_CALLBACK(midas_popup_click),
929                          GINT_TO_POINTER(i));
930         gtk_widget_show(item);
931         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
932     }
933 
934     return menu;
935 }
936 
build_selection_popup(void)937 GtkWidget *build_selection_popup (void)
938 {
939     int midas_list = 0;
940 
941     if (dataset_could_be_midas(dataset)) {
942         int *list = main_window_selection_as_list();
943 
944         if (gretl_is_midas_list(list, dataset)) {
945             midas_list = 1;
946         }
947         free(list);
948     }
949 
950     if (midas_list) {
951         return build_midas_popup();
952     } else {
953         return build_regular_selection_popup();
954     }
955 }
956 
clear_sample_label(void)957 void clear_sample_label (void)
958 {
959     GtkWidget *dlabel = g_object_get_data(G_OBJECT(mdata->main), "dlabel");
960 
961     gtk_label_set_text(GTK_LABEL(mdata->status), "");
962     gtk_label_set_text(GTK_LABEL(dlabel), _(" No datafile loaded "));
963 }
964 
965 /* Note: if @name is not NULL here it will be the name of
966    a gretl session file */
967 
set_main_window_title(const char * name,gboolean modified)968 void set_main_window_title (const char *name, gboolean modified)
969 {
970 #ifdef GRETL_PID_FILE
971     int seqno = gretl_sequence_number();
972 #else
973     int seqno = 0;
974 #endif
975     gchar *title = NULL;
976 
977     if (seqno <= 1 && name == NULL) {
978         gtk_window_set_title(GTK_WINDOW(mdata->main), "gretl");
979     } else if (name == NULL) {
980         title = g_strdup_printf("gretl (%d)", seqno);
981     } else {
982         /* show session name */
983         const char *mod = modified ? " *" : "";
984         gchar *prog;
985 
986         if (seqno > 1) {
987             prog = g_strdup_printf("gretl (%d)", seqno);
988         } else {
989             prog = g_strdup("gretl");
990         }
991         title = g_strdup_printf("%s: session %s%s", prog, name, mod);
992         g_free(prog);
993     }
994 
995     if (title != NULL) {
996         gtk_window_set_title(GTK_WINDOW(mdata->main), title);
997         g_free(title);
998     }
999 }
1000 
get_pd_string(DATASET * dset)1001 static const char *get_pd_string (DATASET *dset)
1002 {
1003     char *pdstr;
1004 
1005     if (custom_time_series(dset)) {
1006         pdstr = N_("Time series");
1007     } else if (dataset_is_time_series(dset)) {
1008         switch (dset->pd) {
1009         case 1:
1010             pdstr = N_("Annual"); break;
1011         case 4:
1012             pdstr = N_("Quarterly"); break;
1013         case 12:
1014             pdstr = N_("Monthly"); break;
1015         case 24:
1016             pdstr = N_("Hourly"); break;
1017         case 52:
1018             pdstr = N_("Weekly"); break;
1019         case 5:
1020             pdstr = N_("Daily (5 days)"); break;
1021         case 6:
1022             pdstr = N_("Daily (6 days)"); break;
1023         case 7:
1024             pdstr = N_("Daily (7 days)"); break;
1025         case 10:
1026             pdstr = N_("Decennial"); break;
1027         default:
1028             pdstr = N_("Unknown"); break;
1029         }
1030     } else if (dataset_is_panel(dset)) {
1031         pdstr = N_("Panel");
1032     } else {
1033         pdstr = N_("Undated");
1034     }
1035 
1036     return pdstr;
1037 }
1038 
set_sample_label(DATASET * dset)1039 void set_sample_label (DATASET *dset)
1040 {
1041     GtkWidget *dlabel;
1042     gchar *tmp = NULL;
1043     int tsubset;
1044 
1045     if (mdata == NULL) {
1046         return;
1047     }
1048 
1049     /* set the sensitivity of various menu items */
1050 
1051     time_series_menu_state(dataset_is_time_series(dset));
1052     panel_menu_state(dataset_is_panel(dset));
1053     ts_or_panel_menu_state(dataset_is_time_series(dset) ||
1054                            dataset_is_panel(dset));
1055     flip(mdata->ui, "/menubar/Data/DataTranspose", !dataset_is_panel(dset));
1056     flip(mdata->ui, "/menubar/Sample/PermaSample",
1057          dataset->submask != NULL && dataset->submask != RESAMPLED);
1058 
1059     tsubset = dset->t1 > 0 || dset->t2 < dset->n - 1;
1060 
1061     /* construct label showing summary of dataset/sample info
1062        (this goes at the foot of the window)
1063     */
1064 
1065     if (complex_subsampled() && !tsubset && dataset_is_cross_section(dset)) {
1066         tmp = g_strdup_printf(_("Undated: Full range n = %d; current sample"
1067                                 " n = %d"), get_full_length_n(), dataset->n);
1068         gtk_label_set_text(GTK_LABEL(mdata->status), tmp);
1069     } else if (complex_subsampled() && dataset_is_panel(dset)) {
1070         char t1str[OBSLEN], t2str[OBSLEN];
1071         const char *pdstr = get_pd_string(dset);
1072 
1073         ntolabel(t1str, dset->t1, dset);
1074         ntolabel(t2str, dset->t2, dset);
1075         tmp = g_strdup_printf(_("%s; sample %s - %s"), _(pdstr), t1str, t2str);
1076         gtk_label_set_text(GTK_LABEL(mdata->status), tmp);
1077     } else {
1078         char t1str[OBSLEN], t2str[OBSLEN];
1079         const char *pdstr = get_pd_string(dset);
1080 
1081         if (calendar_data(dset) && tsubset) {
1082             /* it's too verbose to print both full range and sample */
1083             ntolabel(t1str, dset->t1, dset);
1084             ntolabel(t2str, dset->t2, dset);
1085             tmp = g_strdup_printf(_("%s; sample %s - %s"), _(pdstr), t1str, t2str);
1086             gtk_label_set_text(GTK_LABEL(mdata->status), tmp);
1087         } else if (calendar_data(dset) && complex_subsampled()) {
1088             /* ditto, too verbose */
1089             tmp = g_strdup_printf(_("%s; sample %s - %s"), _(pdstr), dset->stobs,
1090                                   dset->endobs);
1091             gtk_label_set_text(GTK_LABEL(mdata->status), tmp);
1092         } else {
1093             int done = 0;
1094 
1095             ntolabel(t1str, 0, dset);
1096             ntolabel(t2str, dset->n - 1, dset);
1097             tmp = g_strdup_printf(_("%s: Full range %s - %s"), _(pdstr),
1098                                   t1str, t2str);
1099             if (dataset_is_panel(dset) && !tsubset) {
1100                 GString *full = g_string_new(tmp);
1101 
1102                 g_string_append(full, " ");
1103                 g_string_append(full, _("(unit:period)"));
1104                 gtk_label_set_text(GTK_LABEL(mdata->status), full->str);
1105                 g_string_free(full, TRUE);
1106                 done = 1;
1107             }
1108             if (tsubset) {
1109                 gchar *full;
1110 
1111                 ntolabel(t1str, dset->t1, dset);
1112                 ntolabel(t2str, dset->t2, dset);
1113                 full = g_strdup_printf(_("%s; sample %s - %s"), tmp, t1str, t2str);
1114                 gtk_label_set_text(GTK_LABEL(mdata->status), full);
1115                 g_free(full);
1116             } else if (!done) {
1117                 gtk_label_set_text(GTK_LABEL(mdata->status), tmp);
1118             }
1119         }
1120     }
1121 
1122     g_free(tmp);
1123 
1124     /* construct label with datafile name (this goes above the
1125        data series window) */
1126 
1127     dlabel = g_object_get_data(G_OBJECT(mdata->main), "dlabel");
1128 
1129     if (dlabel != NULL) {
1130         GString *dl = NULL;
1131 
1132         if (strlen(datafile) > 2) {
1133             /* data file open already */
1134             gchar *basename = g_path_get_basename(datafile);
1135 
1136             dl = g_string_new(" ");
1137             if (data_status & SESSION_DATA) {
1138                 g_string_append_printf(dl, _("Imported %s"), basename);
1139             } else if (data_status & MODIFIED_DATA) {
1140                 g_string_append_printf(dl, "%s *", basename);
1141             } else {
1142                 g_string_append(dl, basename);
1143             }
1144             gtk_label_set_text(GTK_LABEL(dlabel), dl->str);
1145             g_free(basename);
1146         } else if (data_status & MODIFIED_DATA) {
1147             dl = g_string_new(_(" Unsaved data "));
1148             gtk_label_set_text(GTK_LABEL(dlabel), dl->str);
1149         }
1150         g_string_free(dl, TRUE);
1151     }
1152 
1153     if (complex_subsampled() || dset->t1 > 0 || dset->t2 < dset->n - 1) {
1154         restore_sample_state(TRUE);
1155     } else {
1156         restore_sample_state(FALSE);
1157     }
1158 
1159     console_record_sample(dataset);
1160 }
1161 
set_workdir_label(void)1162 void set_workdir_label (void)
1163 {
1164     GtkWidget *wlabel;
1165 
1166     wlabel = g_object_get_data(G_OBJECT(mdata->main), "wlabel");
1167 
1168     if (wlabel != NULL) {
1169         const char fmt[] = "<span color=\"blue\">%s</span>";
1170         gchar *wdir, *buf;
1171         int len;
1172 
1173         wdir = g_strdup(gretl_workdir());
1174         trim_slash(wdir);
1175         len = g_utf8_strlen(wdir, -1);
1176         if (len > 56) {
1177             gretl_utf8_truncate(wdir, 53);
1178             strcat(wdir, "...");
1179         }
1180         buf = g_markup_printf_escaped(fmt, wdir);
1181         gtk_label_set_markup(GTK_LABEL(wlabel), buf);
1182         g_free(buf);
1183         g_free(wdir);
1184     }
1185 }
1186 
action_entry_init(GtkActionEntry * entry)1187 void action_entry_init (GtkActionEntry *entry)
1188 {
1189     entry->stock_id = NULL;
1190     entry->accelerator = NULL;
1191     entry->tooltip = NULL;
1192     entry->callback = NULL;
1193 }
1194 
vwin_add_ui(windata_t * vwin,GtkActionEntry * entries,gint n_entries,const gchar * ui_info)1195 int vwin_add_ui (windata_t *vwin, GtkActionEntry *entries,
1196                  gint n_entries, const gchar *ui_info)
1197 {
1198     GtkActionGroup *actions;
1199     GError *err = NULL;
1200 
1201     actions = gtk_action_group_new("MyActions");
1202     gtk_action_group_set_translation_domain(actions, "gretl");
1203 
1204     gtk_action_group_add_actions(actions, entries, n_entries, vwin);
1205 
1206     vwin->ui = gtk_ui_manager_new();
1207     gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
1208     g_object_unref(actions);
1209 
1210     gtk_window_add_accel_group(GTK_WINDOW(vwin->main),
1211                                gtk_ui_manager_get_accel_group(vwin->ui));
1212 
1213     gtk_ui_manager_add_ui_from_string(vwin->ui, ui_info, -1, &err);
1214     if (err != NULL) {
1215         g_message("building menus failed: %s", err->message);
1216         g_error_free(err);
1217     }
1218 
1219     vwin->mbar = gtk_ui_manager_get_widget(vwin->ui, "/menubar");
1220 
1221     return 0;
1222 }
1223 
get_named_group(GtkUIManager * uim,const char * name,int * newgroup)1224 static GtkActionGroup *get_named_group (GtkUIManager *uim,
1225                                         const char *name,
1226                                         int *newgroup)
1227 {
1228     GList *list = gtk_ui_manager_get_action_groups(uim);
1229     GtkActionGroup *actions = NULL;
1230 
1231     while (list != NULL) {
1232         GtkActionGroup *group = list->data;
1233 
1234         if (!strcmp(gtk_action_group_get_name(group), name)) {
1235             actions = group;
1236             break;
1237         }
1238         list = list->next;
1239     }
1240 
1241     if (actions == NULL) {
1242         actions = gtk_action_group_new(name);
1243         gtk_action_group_set_translation_domain(actions, "gretl");
1244         *newgroup = 1;
1245     } else {
1246         *newgroup = 0;
1247     }
1248 
1249     return actions;
1250 }
1251 
vwin_menu_add_item_unique(windata_t * vwin,const gchar * aname,const gchar * path,GtkActionEntry * entry)1252 int vwin_menu_add_item_unique (windata_t *vwin,
1253                                const gchar *aname,
1254                                const gchar *path,
1255                                GtkActionEntry *entry)
1256 {
1257     GList *list = gtk_ui_manager_get_action_groups(vwin->ui);
1258     GtkActionGroup *actions;
1259     guint id;
1260 
1261     while (list != NULL) {
1262         GtkActionGroup *group = list->data;
1263 
1264         if (!strcmp(aname, gtk_action_group_get_name(group))) {
1265             gtk_ui_manager_remove_action_group(vwin->ui, group);
1266             break;
1267         }
1268         list = list->next;
1269     }
1270 
1271     id = gtk_ui_manager_new_merge_id(vwin->ui);
1272     actions = gtk_action_group_new(aname);
1273     gtk_action_group_set_translation_domain(actions, "gretl");
1274 
1275     gtk_action_group_add_actions(actions, entry, 1, vwin);
1276     gtk_ui_manager_add_ui(vwin->ui, id, path, entry->name, entry->name,
1277                           GTK_UI_MANAGER_MENUITEM, FALSE);
1278 
1279     gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
1280     g_object_unref(actions);
1281 
1282     return id;
1283 }
1284 
1285 /* Retrieve existing "AdHoc" action group from @uim, or add a
1286    new group of this name to the UIManager and return it.
1287 */
1288 
get_ad_hoc_group(GtkUIManager * uim,int * newgroup)1289 GtkActionGroup *get_ad_hoc_group (GtkUIManager *uim,
1290                                   int *newgroup)
1291 {
1292     return get_named_group(uim, "AdHoc", newgroup);
1293 }
1294 
1295 /* Adds the specified @entry to vwin->ui at @path; returns
1296    the "merge_id", which can be used to remove the item
1297 */
1298 
vwin_menu_add_item(windata_t * vwin,const gchar * path,GtkActionEntry * entry)1299 int vwin_menu_add_item (windata_t *vwin, const gchar *path,
1300                         GtkActionEntry *entry)
1301 {
1302     GtkActionGroup *actions;
1303     int newgroup = 1;
1304     guint id;
1305 
1306     actions = get_ad_hoc_group(vwin->ui, &newgroup);
1307     gtk_action_group_add_actions(actions, entry, 1, vwin);
1308     id = gtk_ui_manager_new_merge_id(vwin->ui);
1309 
1310     gtk_ui_manager_add_ui(vwin->ui, id, path, entry->name, entry->name,
1311                           GTK_UI_MANAGER_MENUITEM, FALSE);
1312 
1313     if (newgroup) {
1314         gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
1315         g_object_unref(actions);
1316     }
1317 
1318     return id;
1319 }
1320 
1321 /* Adds the specified @entries to vwin->ui at @path; returns
1322    the "merge_id", which can be used to remove the items
1323 */
1324 
vwin_menu_add_items(windata_t * vwin,const gchar * path,GtkActionEntry * entries,int n)1325 int vwin_menu_add_items (windata_t *vwin, const gchar *path,
1326                          GtkActionEntry *entries, int n)
1327 {
1328     GtkActionGroup *actions;
1329     int newgroup = 1;
1330     guint id;
1331     int i;
1332 
1333     actions = get_ad_hoc_group(vwin->ui, &newgroup);
1334     gtk_action_group_add_actions(actions, entries, n, vwin);
1335     id = gtk_ui_manager_new_merge_id(vwin->ui);
1336 
1337     for (i=0; i<n; i++) {
1338         gtk_ui_manager_add_ui(vwin->ui, id, path,
1339                               entries[i].name, entries[i].name,
1340                               GTK_UI_MANAGER_MENUITEM, FALSE);
1341     }
1342 
1343     if (newgroup) {
1344         gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
1345         g_object_unref(actions);
1346     }
1347 
1348     return id;
1349 }
1350 
vwin_menu_add_radios(windata_t * vwin,const gchar * path,GtkRadioActionEntry * entries,int n,int deflt,GCallback callback)1351 int vwin_menu_add_radios (windata_t *vwin, const gchar *path,
1352                           GtkRadioActionEntry *entries, int n,
1353                           int deflt, GCallback callback)
1354 {
1355     guint id = gtk_ui_manager_new_merge_id(vwin->ui);
1356     GtkActionGroup *actions;
1357     int i;
1358 
1359     actions = gtk_action_group_new("Radios");
1360     gtk_action_group_set_translation_domain(actions, "gretl");
1361 
1362     gtk_action_group_add_radio_actions(actions, entries, n,
1363                                        deflt, callback,
1364                                        vwin);
1365     for (i=0; i<n; i++) {
1366         gtk_ui_manager_add_ui(vwin->ui, id, path,
1367                               entries[i].name, entries[i].name,
1368                               GTK_UI_MANAGER_MENUITEM, FALSE);
1369     }
1370     gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
1371     g_object_unref(actions);
1372 
1373     return id;
1374 }
1375 
vwin_menu_add_menu(windata_t * vwin,const gchar * path,GtkActionEntry * entry)1376 int vwin_menu_add_menu (windata_t *vwin, const gchar *path,
1377                         GtkActionEntry *entry)
1378 {
1379     guint id = gtk_ui_manager_new_merge_id(vwin->ui);
1380     GtkActionGroup *actions;
1381     gchar *grpname;
1382     static int seq;
1383 
1384     grpname = g_strdup_printf("NewMenu%d", seq);
1385     actions = gtk_action_group_new(grpname);
1386     gtk_action_group_set_translation_domain(actions, "gretl");
1387     g_free(grpname);
1388     seq++;
1389 
1390     gtk_action_group_add_actions(actions, entry, 1, vwin);
1391     gtk_ui_manager_add_ui(vwin->ui, id, path, entry->name, entry->name,
1392                           GTK_UI_MANAGER_MENU, FALSE);
1393     gtk_ui_manager_insert_action_group(vwin->ui, actions, 0);
1394     g_object_unref(actions);
1395 
1396     return id;
1397 }
1398 
vwin_menu_add_separator(windata_t * vwin,const gchar * path)1399 void vwin_menu_add_separator (windata_t *vwin, const gchar *path)
1400 {
1401     guint id = gtk_ui_manager_new_merge_id(vwin->ui);
1402 
1403     gtk_ui_manager_add_ui(vwin->ui, id, path, NULL, NULL,
1404                           GTK_UI_MANAGER_SEPARATOR, FALSE);
1405 }
1406