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