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 /* session.c for gretl */
21
22 #include "gretl.h"
23 #include "session.h"
24 #include "selector.h"
25 #include "ssheet.h"
26 #include "plotspec.h"
27 #include "gpt_control.h"
28 #include "guiprint.h"
29 #include "gui_recode.h"
30 #include "model_table.h"
31 #include "graph_page.h"
32 #include "textbuf.h"
33 #include "cmdstack.h"
34 #include "filelists.h"
35 #include "dlgutils.h"
36 #include "fileselect.h"
37 #include "menustate.h"
38 #include "toolbar.h"
39 #include "winstack.h"
40 #include "fncall.h"
41 #include "lib_private.h"
42
43 #include "var.h"
44 #include "varprint.h"
45 #include "objstack.h"
46 #include "system.h"
47 #include "gretl_xml.h"
48 #include "gretl_func.h"
49 #include "matrix_extra.h"
50 #include "uservar.h"
51 #include "gretl_zip.h"
52 #include "dbread.h"
53
54 #include <sys/stat.h>
55 #include <unistd.h>
56 #include <dirent.h>
57 #include <errno.h>
58
59 #ifdef _WIN32
60 # include <windows.h>
61 # include "gretlwin32.h"
62 #endif
63
64 #include "../pixmaps/model.xpm"
65 #include "../pixmaps/boxplot.xpm"
66 #include "../pixmaps/gnuplot.xpm"
67 #include "../pixmaps/xfm_sc.xpm"
68 #include "../pixmaps/xfm_info.xpm"
69 #include "../pixmaps/xfm_text.xpm"
70 #include "../pixmaps/rhohat.xpm"
71 #include "../pixmaps/summary.xpm"
72 #include "../pixmaps/model_table.xpm"
73 #include "../pixmaps/graph_page.xpm"
74 #include "../pixmaps/matrix.xpm"
75 #include "../pixmaps/bundle.xpm"
76
77 #define SESSION_DEBUG 0
78
79 #define SHOWNAMELEN 15
80 #define ICONVIEW_MIN_COLS 4
81
82 #if GTK_MAJOR_VERSION < 3
83 # define REMEDY_LABELS
84 #endif
85
86 typedef struct SESSION_ SESSION;
87 typedef struct SESSION_TEXT_ SESSION_TEXT;
88 typedef struct SESSION_MODEL_ SESSION_MODEL;
89 typedef struct SESSION_GRAPH_ SESSION_GRAPH;
90 typedef struct gui_obj_ gui_obj;
91
92 enum {
93 SESSION_CHANGED = 1 << 0,
94 SESSION_SAVED = 1 << 1,
95 SESSION_OPEN = 1 << 2
96 };
97
98 struct SESSION_ {
99 char name[MAXLEN];
100 char dirname[MAXLEN];
101 int status;
102 int show_notes;
103 int nmodels;
104 int ngraphs;
105 int ntexts;
106 SESSION_GRAPH **graphs;
107 SESSION_MODEL **models;
108 SESSION_TEXT **texts;
109 char *notes;
110 };
111
112 struct SESSION_TEXT_ {
113 char name[MAXSAVENAME];
114 char *buf;
115 };
116
117 struct SESSION_MODEL_ {
118 char name[MAXSAVENAME];
119 void *ptr;
120 GretlObjType type;
121 };
122
123 struct SESSION_GRAPH_ {
124 char name[MAXSAVENAME];
125 char fname[MAXLEN];
126 GretlObjType type;
127 int has_datafile;
128 };
129
130 struct gui_obj_ {
131 gchar *name;
132 gint sort;
133 gpointer data;
134 GtkWidget *icon;
135 GtkWidget *label;
136 gint row, col;
137 };
138
139 struct sample_info {
140 char datafile[MAXLEN];
141 int t1;
142 int t2;
143 char *mask;
144 char *restriction;
145 unsigned int seed;
146 int resample_n;
147 };
148
149 enum {
150 ICON_ADD_BATCH,
151 ICON_ADD_SINGLE
152 } icon_add_modes;
153
154 static char *global_items[] = {
155 N_("Save session"),
156 N_("Arrange icons"),
157 N_("Add matrix..."),
158 N_("Windows"),
159 N_("Close window")
160 };
161
162 static char *model_items[] = {
163 N_("Display"),
164 N_("Add to model table"),
165 N_("Rename"),
166 N_("Delete")
167 };
168 #define ADD_TO_MTAB_IDX 1 /* position of "Add to model table" */
169
170 static char *model_table_items[] = {
171 N_("Display"),
172 N_("Clear"),
173 N_("Help")
174 };
175
176 static char *graph_page_items[] = {
177 N_("Display"),
178 N_("Save as TeX..."),
179 N_("Clear"),
180 N_("Help")
181 };
182
183 static char *generic_items[] = {
184 N_("Display"),
185 N_("Rename"),
186 N_("Delete")
187 };
188
189 static char *graph_items[] = {
190 N_("Display"),
191 N_("Edit plot commands"),
192 N_("Add to graph page"),
193 N_("Rename"),
194 N_("Delete"),
195 N_("Copy")
196 };
197 #define ADD_TO_GPAGE_IDX 2 /* position of "Add to graph page" */
198 #define GRAPH_COPY_IDX 5 /* position of "Copy" */
199
200 static char *dataset_items[] = {
201 N_("Edit"),
202 N_("Export as CSV..."),
203 N_("Copy as CSV...")
204 };
205
206 static char *scalars_items[] = {
207 N_("Edit"),
208 N_("Copy as CSV...")
209 };
210
211 static char *info_items[] = {
212 N_("View")
213 };
214
215 static char *matrix_items[] = {
216 N_("View"),
217 N_("Edit"),
218 N_("Properties"),
219 N_("Copy as CSV..."),
220 N_("Rename"),
221 N_("Delete"),
222 N_("Copy")
223 };
224
225 static char *bundle_items[] = {
226 N_("View"),
227 N_("Rename"),
228 N_("Delete")
229 };
230
231 /* file-scope globals */
232
233 SESSION session; /* holds named models, graphs, etc. */
234
235 static char sessionfile[MAXLEN];
236
237 static GtkWidget *iconview;
238 static GtkWidget *icon_table;
239 static GtkWidget *global_popup;
240 static GtkWidget *model_popup;
241 static GtkWidget *model_table_popup;
242 static GtkWidget *generic_popup;
243 static GtkWidget *graph_popup;
244 static GtkWidget *graph_page_popup;
245 static GtkWidget *data_popup;
246 static GtkWidget *scalars_popup;
247 static GtkWidget *info_popup;
248 static GtkWidget *matrix_popup;
249 static GtkWidget *bundle_popup;
250 static GtkWidget *save_item;
251 static GtkWidget *mtab_add_item;
252 static GtkWidget *gpage_add_item;
253 static GtkWidget *graph_copy_item;
254
255 static GList *iconlist;
256 static gui_obj *active_object;
257 static gint iconview_width;
258 static gint iconview_cols;
259 static gint in_icon;
260
261 /* private functions */
262 static gui_obj *gui_object_new (gchar *name, int sort, gpointer data);
263 static gui_obj *session_add_icon (gpointer data, int sort, int mode);
264 static void session_build_popups (void);
265 static void global_popup_callback (GtkWidget *widget, gpointer data);
266 static void object_popup_callback (GtkWidget *widget, gpointer data);
267 static void data_popup_callback (GtkWidget *widget, gpointer data);
268 static void scalars_popup_callback (GtkWidget *widget, gpointer data);
269 static void info_popup_callback (GtkWidget *widget, gpointer data);
270 static void matrix_popup_callback (GtkWidget *widget, gpointer data);
271 static void bundle_popup_callback (GtkWidget *widget, gpointer data);
272 static void session_delete_icon (gui_obj *obj);
273 static void open_gui_graph (gui_obj *obj);
274 static gboolean session_view_click (GtkWidget *widget,
275 GdkEventButton *event,
276 gpointer data);
277 static int real_delete_model_from_session (SESSION_MODEL *model);
278 static void make_short_label_string (char *targ, const char *src);
279 static gui_obj *get_gui_obj_by_data (void *finddata);
280 static int gui_user_var_callback (const char *name, GretlType type,
281 int action);
282 static void auto_view_session (void);
283 static int display_session_model (SESSION_MODEL *sm);
284
285 static int session_graph_count;
286 static int session_bundle_count;
287 static int commands_recorded;
288
session_is_modified(void)289 int session_is_modified (void)
290 {
291 return session.status & SESSION_CHANGED;
292 }
293
session_is_open(void)294 int session_is_open (void)
295 {
296 return session.status & SESSION_OPEN;
297 }
298
mark_session_changed(void)299 void mark_session_changed (void)
300 {
301 iconview_menubar_state(TRUE);
302 session.status &= ~SESSION_SAVED;
303 session.status |= SESSION_CHANGED;
304 if (save_item != NULL) {
305 gtk_widget_set_sensitive(save_item, TRUE);
306 }
307 flip(mdata->ui, "/menubar/File/SessionFiles/SaveSession", TRUE);
308 flip(mdata->ui, "/menubar/File/SessionFiles/SaveSessionAs", TRUE);
309 if (*session.name != '\0') {
310 set_main_window_title(session.name, TRUE);
311 }
312 }
313
mark_session_saved(void)314 static void mark_session_saved (void)
315 {
316 session.status &= ~SESSION_CHANGED;
317 session.status |= SESSION_SAVED;
318 if (save_item != NULL) {
319 gtk_widget_set_sensitive(save_item, FALSE);
320 }
321 flip(mdata->ui, "/menubar/File/SessionFiles/SaveSession", FALSE);
322 flip(mdata->ui, "/menubar/File/SessionFiles/SaveSessionAs",
323 session.status & SESSION_OPEN);
324 set_main_window_title(session.name, FALSE);
325 }
326
set_commands_recorded(void)327 void set_commands_recorded (void)
328 {
329 commands_recorded = 1;
330 }
331
get_commands_recorded(void)332 int get_commands_recorded (void)
333 {
334 return commands_recorded;
335 }
336
widget_is_iconview(GtkWidget * w)337 int widget_is_iconview (GtkWidget *w)
338 {
339 return w == iconview;
340 }
341
342 /* constructors and destructors for session data-objects */
343
free_session_text(SESSION_TEXT * text)344 static void free_session_text (SESSION_TEXT *text)
345 {
346 free(text->buf);
347 free(text);
348 }
349
free_session_model(SESSION_MODEL * mod)350 static void free_session_model (SESSION_MODEL *mod)
351 {
352 #if SESSION_DEBUG
353 fprintf(stderr, "free_session_model: ptr at %p\n", (void *) mod->ptr);
354 #endif
355 gretl_object_remove_from_stack(mod->ptr, mod->type);
356 free(mod);
357 }
358
session_model_new(void * ptr,const char * name,GretlObjType type)359 static SESSION_MODEL *session_model_new (void *ptr, const char *name,
360 GretlObjType type)
361 {
362 SESSION_MODEL *mod = mymalloc(sizeof *mod);
363
364 if (mod != NULL) {
365 mod->ptr = ptr;
366 mod->type = type;
367 gretl_stack_object_as(ptr, type, name);
368 strcpy(mod->name, gretl_object_get_name(ptr, type));
369 /* note: we don't add a reference here: that's handled by the
370 mechanism in objstack.c
371 */
372 }
373
374 return mod;
375 }
376
session_append_text(const char * tname,char * buf)377 static int session_append_text (const char *tname, char *buf)
378 {
379 SESSION_TEXT *text;
380 SESSION_TEXT **texts;
381 int nt = session.ntexts;
382
383 text = mymalloc(sizeof *text);
384 if (text == NULL) {
385 return 1;
386 }
387
388 text->buf = buf;
389
390 *text->name = '\0';
391 if (tname != NULL) {
392 strncat(text->name, tname, MAXSAVENAME - 1);
393 }
394
395 texts = myrealloc(session.texts, (nt + 1) * sizeof *texts);
396
397 if (texts == NULL) {
398 free_session_text(text);
399 return 1;
400 }
401
402 session.texts = texts;
403 session.texts[nt] = text;
404 session.ntexts += 1;
405 mark_session_changed();
406
407 return 0;
408 }
409
session_append_model(SESSION_MODEL * mod)410 static int session_append_model (SESSION_MODEL *mod)
411 {
412 SESSION_MODEL **models;
413 int nm = session.nmodels;
414
415 models = myrealloc(session.models, (nm + 1) * sizeof *models);
416 if (models == NULL) {
417 free_session_model(mod);
418 return 1;
419 }
420
421 session.models = models;
422 session.models[nm] = mod;
423 session.nmodels += 1;
424
425 #if SESSION_DEBUG
426 fprintf(stderr, "session_append_model: nmodels now = %d\n",
427 session.nmodels);
428 #endif
429
430 return 0;
431 }
432
session_append_graph(const char * grname,const char * fname,GretlObjType type)433 static SESSION_GRAPH *session_append_graph (const char *grname,
434 const char *fname,
435 GretlObjType type)
436 {
437 SESSION_GRAPH *graph;
438 SESSION_GRAPH **graphs;
439 int ng = session.ngraphs;
440
441 graph = mymalloc(sizeof *graph);
442 if (graph == NULL) {
443 return NULL;
444 }
445
446 *graph->name = '\0';
447 if (grname != NULL) {
448 strncat(graph->name, grname, MAXSAVENAME - 1);
449 }
450
451 *graph->fname = '\0';
452 if (fname != NULL) {
453 strncat(graph->fname, fname, MAXLEN - 1);
454 }
455
456 graph->type = type;
457 graph->has_datafile = 0;
458
459 graphs = myrealloc(session.graphs, (ng + 1) * sizeof *graphs);
460
461 if (graphs == NULL) {
462 free(graph);
463 return NULL;
464 }
465
466 session.graphs = graphs;
467 session.graphs[ng] = graph;
468 session.ngraphs++; /* decremented if graph is deleted */
469 session_graph_count++; /* not decremented on deletion */
470
471 return graph;
472 }
473
last_session_graph_name(void)474 const char *last_session_graph_name (void)
475 {
476 int ng = session.ngraphs;
477
478 if (ng > 0) {
479 SESSION_GRAPH *graph = session.graphs[ng - 1];
480
481 return graph->fname;
482 } else {
483 return NULL;
484 }
485 }
486
session_switch_log_location(int code)487 static void session_switch_log_location (int code)
488 {
489 gchar *dirpath;
490
491 dirpath = gretl_make_dotpath(session.dirname);
492 set_session_log(dirpath, code);
493 g_free(dirpath);
494 }
495
session_graph_make_path(char * path,const char * fname)496 char *session_graph_make_path (char *path, const char *fname)
497 {
498 if (strstr(fname, session.dirname) != NULL) {
499 /* should be OK */
500 strcpy(path, fname);
501 } else {
502 const char *p = path_last_slash_const(fname);
503
504 if (p != NULL) {
505 sprintf(path, "%s%s", session.dirname, p);
506 } else {
507 sprintf(path, "%s%c%s", session.dirname, SLASH, fname);
508 }
509 }
510
511 return path;
512 }
513
514 /* first arg should be a MAXLEN string */
515
session_file_make_path(char * path,const char * fname)516 static char *session_file_make_path (char *path, const char *fname)
517 {
518 #if SESSION_DEBUG
519 fprintf(stderr, "session_file_make_path: fname arg = '%s'\n", fname);
520 #endif
521
522 if (g_path_is_absolute(fname)) {
523 strcpy(path, fname);
524 } else {
525 #if 1 /* modified 2020-01-23: build absolute path */
526 gretl_build_path(path, gretl_dotdir(), session.dirname,
527 fname, NULL);
528 #else
529 sprintf(path, "%s%c%s", session.dirname, SLASH, fname);
530 #endif
531 }
532
533 #if SESSION_DEBUG
534 fprintf(stderr, "session_file_make_path: outgoing path = '%s'\n", path);
535 #endif
536
537 return path;
538 }
539
540 #include "session_xml.c"
541
edit_session_notes(void)542 static void edit_session_notes (void)
543 {
544 static GtkWidget *notes_window;
545
546 if (notes_window == NULL) {
547 windata_t *vwin;
548
549 vwin = edit_buffer(&session.notes, 80, 400,
550 _("gretl: session notes"),
551 EDIT_NOTES);
552 notes_window = vwin->main;
553 g_signal_connect(G_OBJECT(vwin->main), "destroy",
554 G_CALLBACK(gtk_widget_destroyed),
555 ¬es_window);
556 } else {
557 gtk_window_present(GTK_WINDOW(notes_window));
558 }
559 }
560
is_session_model(void * p)561 int is_session_model (void *p)
562 {
563 int i;
564
565 #if SESSION_DEBUG
566 fprintf(stderr, "is_session_model: testing %p (nmodels = %d)\n",
567 p, session.nmodels);
568 #endif
569
570 for (i=0; i<session.nmodels; i++) {
571 if (p == session.models[i]->ptr) {
572 return 1;
573 }
574 }
575 return 0;
576 }
577
get_session_model_by_name(const char * name)578 static SESSION_MODEL *get_session_model_by_name (const char *name)
579 {
580 int i;
581
582 for (i=0; i<session.nmodels; i++) {
583 if (!strcmp(name, session.models[i]->name)) {
584 return session.models[i];
585 }
586 }
587
588 return NULL;
589 }
590
get_session_graph_by_name(const char * name)591 static SESSION_GRAPH *get_session_graph_by_name (const char *name)
592 {
593 int i;
594
595 for (i=0; i<session.ngraphs; i++) {
596 if (!strcmp(name, session.graphs[i]->name)) {
597 return session.graphs[i];
598 }
599 }
600
601 return NULL;
602 }
603
get_session_text_by_name(const char * name)604 static SESSION_TEXT *get_session_text_by_name (const char *name)
605 {
606 int i;
607
608 for (i=0; i<session.ntexts; i++) {
609 if (!strcmp(name, session.texts[i]->name)) {
610 return session.texts[i];
611 }
612 }
613
614 return NULL;
615 }
616
real_add_text_to_session(PRN * prn,int pos,const char * tname)617 int real_add_text_to_session (PRN *prn, int pos, const char *tname)
618 {
619 SESSION_TEXT *text = get_session_text_by_name(tname);
620 char *buf = gretl_print_get_chunk_at(prn, pos);
621 int replace = 0;
622
623 if (buf == NULL || string_is_blank(buf)) {
624 warnbox_printf(_("%s: no text to save"), tname);
625 return ADD_OBJECT_FAIL;
626 }
627
628 if (text != NULL) {
629 free(text->buf);
630 text->buf = buf;
631 replace = 1;
632 } else {
633 if (session_append_text(tname, buf)) {
634 return ADD_OBJECT_FAIL;
635 }
636 }
637
638 mark_session_changed();
639
640 if (iconlist != NULL && !replace) {
641 session_add_icon(text, GRETL_OBJ_TEXT, ICON_ADD_SINGLE);
642 } else if (autoicon_on()) {
643 auto_view_session();
644 }
645
646 return (replace)? ADD_OBJECT_REPLACE : ADD_OBJECT_OK;
647 }
648
ends_with_number(const char * s,int * k)649 static int ends_with_number (const char *s, int *k)
650 {
651 int ret = 0;
652
653 s = strrchr(s, '(');
654
655 if (s != NULL) {
656 int n = strspn(s + 1, "0123456789");
657
658 if (n > 0 && *(s + n + 1) == ')' && *(s + n + 2) == '\0') {
659 sscanf(s + 1, "%d", k);
660 ret = 1;
661 }
662 }
663
664 return ret;
665 }
666
ensure_unique_text_name(char * tname)667 static void ensure_unique_text_name (char *tname)
668 {
669 char tmp[MAXSAVENAME];
670 const char *p, *oldname;
671 int i, n, id, idmax = 0;
672
673 for (i=0; i<session.ntexts; i++) {
674 id = 0;
675 oldname = session.texts[i]->name;
676 if (!strcmp(tname, oldname)) {
677 id = 1;
678 } else if (ends_with_number(oldname, &id)) {
679 p = strrchr(oldname, '(');
680 *tmp = '\0';
681 strncat(tmp, oldname, p - oldname);
682 if (strcmp(tmp, tname)) {
683 id = 0;
684 }
685 }
686 if (id > idmax) {
687 idmax = id;
688 }
689 }
690
691 if (idmax > 0) {
692 char num[16];
693
694 sprintf(num, "(%d)", ++idmax);
695 n = MAXSAVENAME - strlen(num) - 1;
696 *tmp = '\0';
697 strncat(tmp, tname, n);
698 strcat(tmp, num);
699 strcpy(tname, tmp);
700 }
701 }
702
save_output_as_text_icon(windata_t * vwin)703 void save_output_as_text_icon (windata_t *vwin)
704 {
705 const gchar *title = NULL;
706 char tname[MAXSAVENAME];
707 gchar *buf;
708 int err;
709
710 buf = textview_get_text(vwin->text);
711 if (buf == NULL) {
712 errbox("Couldn't retrieve buffer");
713 return;
714 }
715
716 if (vwin->main != NULL) {
717 title = gtk_window_get_title(GTK_WINDOW(vwin->main));
718 }
719
720 if (title != NULL && !strncmp(title, "gretl: ", 7)) {
721 *tname = '\0';
722 strncat(tname, title + 7, MAXSAVENAME - 1);
723 } else {
724 strcpy(tname, "text");
725 }
726
727 ensure_unique_text_name(tname);
728 err = session_append_text(tname, buf);
729
730 if (err) {
731 return;
732 } else if (iconlist != NULL) {
733 SESSION_TEXT * text = get_session_text_by_name(tname);
734
735 session_add_icon(text, GRETL_OBJ_TEXT, ICON_ADD_SINGLE);
736 } else if (autoicon_on()) {
737 auto_view_session();
738 }
739 }
740
add_model_to_session(void * ptr,const char * name,GretlObjType type,SESSION_MODEL ** psm)741 static int add_model_to_session (void *ptr, const char *name,
742 GretlObjType type,
743 SESSION_MODEL **psm)
744 {
745 SESSION_MODEL *model;
746 int err = 0;
747
748 #if SESSION_DEBUG
749 fprintf(stderr, "add_model_to_session: doing session_model_new\n"
750 " with ptr = %p\n", ptr);
751 #endif
752
753 model = session_model_new(ptr, name, type);
754
755 if (model == NULL || session_append_model(model)) {
756 err = E_ALLOC;
757 } else if (iconlist != NULL) {
758 session_add_icon(model, type, ICON_ADD_SINGLE);
759 } else if (autoicon_on()) {
760 auto_view_session();
761 }
762
763 if (!err && psm != NULL) {
764 *psm = model;
765 }
766
767 return err;
768 }
769
replace_session_graph(SESSION_GRAPH * graph,const char * fname,GretlObjType type)770 static int replace_session_graph (SESSION_GRAPH *graph,
771 const char *fname,
772 GretlObjType type)
773 {
774 if (fname != NULL && strcmp(graph->fname, fname)) {
775 gretl_remove(graph->fname);
776 strcpy(graph->fname, fname);
777 }
778
779 graph->type = type;
780 mark_session_changed();
781
782 return ADD_OBJECT_REPLACE;
783 }
784
real_add_graph_to_session(const char * fname,const char * grname,GretlObjType type,SESSION_GRAPH ** pgraph)785 static int real_add_graph_to_session (const char *fname,
786 const char *grname,
787 GretlObjType type,
788 SESSION_GRAPH **pgraph)
789 {
790 SESSION_GRAPH *graph = get_session_graph_by_name(grname);
791 int ret = ADD_OBJECT_OK;
792
793 if (graph != NULL) {
794 ret = replace_session_graph(graph, grname, type);
795 } else {
796 graph = session_append_graph(grname, fname, type);
797 if (graph == NULL) {
798 ret = ADD_OBJECT_FAIL;
799 }
800 }
801
802 if (ret != ADD_OBJECT_FAIL) {
803 if (pgraph != NULL) {
804 *pgraph = graph;
805 }
806 mark_session_changed();
807 if (iconlist != NULL) {
808 session_add_icon(graph, type, ICON_ADD_SINGLE);
809 if (autoicon_on()) {
810 gtk_window_present(GTK_WINDOW(iconview));
811 }
812 } else if (autoicon_on()) {
813 auto_view_session();
814 }
815 }
816
817 return ret;
818 }
819
get_session_dirname(void)820 const char *get_session_dirname (void)
821 {
822 return session.dirname;
823 }
824
session_dir_ok(void)825 static int session_dir_ok (void)
826 {
827 int ret = 1;
828
829 if (*session.dirname == '\0') {
830 pid_t p = getpid();
831
832 errno = 0;
833
834 sprintf(session.dirname, ".gretl-%d", (int) p);
835 if (gretl_chdir(gretl_dotdir())) {
836 perror("moving to user directory");
837 ret = 0;
838 } else if (gretl_mkdir(session.dirname)) {
839 ret = 0;
840 }
841 }
842
843 return ret;
844 }
845
make_graph_name(char * shortname,char * graphname)846 static void make_graph_name (char *shortname, char *graphname)
847 {
848 int i, n = session_graph_count + 1;
849
850 for ( ; ; n++) {
851 int unique = 1;
852
853 sprintf(shortname, "graph.%d", n);
854 sprintf(graphname, "%s %d", _("Graph"), n);
855
856 for (i=0; i<session.ngraphs; i++) {
857 if (!strcmp(shortname, session.graphs[i]->fname) ||
858 !strcmp(graphname, session.graphs[i]->name)) {
859 unique = 0;
860 break;
861 }
862 }
863
864 if (unique) {
865 break;
866 }
867 }
868 }
869
maybe_move_plot_datafile(const char * orig,const char * revised,int * has_datafile)870 static int maybe_move_plot_datafile (const char *orig,
871 const char *revised,
872 int *has_datafile)
873 {
874 gchar *tmp1 = g_strdup_printf("%s.dat", orig);
875 int err = 0;
876
877 if (gretl_test_fopen(tmp1, "r") == 0) {
878 gchar *tmp2 = g_strdup_printf("%s.dat", revised);
879
880 err = gretl_rename(tmp1, tmp2);
881 g_free(tmp2);
882 *has_datafile = 1;
883 }
884
885 g_free(tmp1);
886
887 return err;
888 }
889
890 /* Callback for "add to session as icon" on a graph displayed
891 as PNG -- see gpt_control.c. Note that there is code in
892 gpt_control designed to ensure that this option is not
893 available for a graph that has already been saved in
894 this way.
895 */
896
gui_add_graph_to_session(char * fname,char * fullname,int type)897 int gui_add_graph_to_session (char *fname, char *fullname, int type)
898 {
899 char shortname[MAXSAVENAME];
900 char graphname[MAXSAVENAME];
901 int has_datafile = 0;
902 int err = 0;
903
904 if (type != GRETL_OBJ_PLOT && (dataset == NULL || dataset->Z == NULL)) {
905 /* we may be called via the "stats calculator" when
906 there's no dataset yet */
907 err = open_nulldata(dataset, 0, 10, OPT_NONE, NULL);
908 if (err) {
909 gui_errmsg(err);
910 return 1;
911 }
912 register_data(NULLDATA_STARTED);
913 }
914
915 errno = 0;
916
917 if (!session_dir_ok()) {
918 errbox(_("Failed to copy graph file"));
919 return 1;
920 }
921
922 err = gretl_chdir(gretl_dotdir());
923 if (err) {
924 gui_errmsg(err);
925 } else {
926 make_graph_name(shortname, graphname);
927 session_file_make_path(fullname, shortname);
928
929 /* copy temporary plot file to session directory */
930 err = copyfile(fname, fullname);
931 if (!err) {
932 /* remove the original and transcribe the new
933 name to @fname */
934 maybe_move_plot_datafile(fname, fullname, &has_datafile);
935 gretl_remove(fname);
936 strcpy(fname, fullname);
937 }
938 }
939
940 if (!err) {
941 SESSION_GRAPH *grf = NULL;
942
943 err = real_add_graph_to_session(shortname, graphname, type, &grf);
944 if (err == ADD_OBJECT_FAIL) {
945 err = 1;
946 } else if (has_datafile) {
947 grf->has_datafile = 1;
948 }
949 }
950
951 return err;
952 }
953
make_graph_filename(char * shortname)954 static void make_graph_filename (char *shortname)
955 {
956 int i, n = session_graph_count + 1;
957
958 for ( ; ; n++) {
959 int unique = 1;
960
961 sprintf(shortname, "graph.%d", n);
962
963 for (i=0; i<session.ngraphs; i++) {
964 if (!strcmp(shortname, session.graphs[i]->fname)) {
965 unique = 0;
966 break;
967 }
968 }
969
970 if (unique) {
971 break;
972 }
973 }
974 }
975
976 /* Callback for a command on the pattern "gname <- plotspec".
977 Note @gname may contain non-ASCII characters (which will be
978 in UTF-8). So we'd best not use @gname to construct a filename
979 for the graph in case we're on a non-UTF-8 system.
980 */
981
cli_add_graph_to_session(const char * fname,const char * gname,GretlObjType type,int display)982 int cli_add_graph_to_session (const char *fname, const char *gname,
983 GretlObjType type, int display)
984 {
985 SESSION_GRAPH *graph = NULL;
986 char shortname[MAXSAVENAME];
987 char grpath[MAXLEN];
988 int replace = 0;
989 int ret = 0;
990
991 errno = 0;
992
993 if (!session_dir_ok()) {
994 errbox(_("Failed to copy graph file"));
995 return ADD_OBJECT_FAIL;
996 }
997
998 gretl_chdir(gretl_dotdir());
999
1000 graph = get_session_graph_by_name(gname);
1001
1002 if (graph != NULL) {
1003 /* replacing */
1004 session_file_make_path(grpath, graph->fname);
1005 replace = 1;
1006 } else {
1007 /* ensure unique filename */
1008 make_graph_filename(shortname);
1009 session_file_make_path(grpath, shortname);
1010 }
1011
1012 if (copyfile(fname, grpath)) {
1013 errbox(_("Failed to copy graph file"));
1014 return ADD_OBJECT_FAIL;
1015 }
1016
1017 /* we copied the plot commands file, @fname, into the
1018 session directory; now delete the original */
1019 gretl_remove(fname);
1020
1021 if (replace) {
1022 ret = replace_session_graph(graph, NULL, type);
1023 } else {
1024 ret = real_add_graph_to_session(shortname, gname, type, &graph);
1025 }
1026
1027 if (ret == ADD_OBJECT_REPLACE) {
1028 /* don't keep a stale plot window open */
1029 GtkWidget *pwin = get_window_for_plot(graph);
1030
1031 if (pwin != NULL) {
1032 gtk_widget_destroy(pwin);
1033 }
1034 }
1035
1036 if (ret != ADD_OBJECT_FAIL && display) {
1037 display_session_graph_by_data(graph);
1038 }
1039
1040 return ret;
1041 }
1042
get_session_object_by_name(const char * name,GretlObjType * type)1043 void *get_session_object_by_name (const char *name, GretlObjType *type)
1044 {
1045 int i;
1046
1047 for (i=0; i<session.nmodels; i++) {
1048 if (!strcmp(name, session.models[i]->name)) {
1049 *type = session.models[i]->type;
1050 return session.models[i]->ptr;
1051 }
1052 }
1053
1054 for (i=0; i<session.ngraphs; i++) {
1055 if (!strcmp(name, session.graphs[i]->name)) {
1056 *type = GRETL_OBJ_GRAPH;
1057 return session.graphs[i];
1058 }
1059 }
1060
1061 for (i=0; i<session.ntexts; i++) {
1062 if (!strcmp(name, session.texts[i]->name)) {
1063 *type = GRETL_OBJ_TEXT;
1064 return session.texts[i];
1065 }
1066 }
1067
1068 return NULL;
1069 }
1070
get_session_model_by_data(const void * ptr)1071 static SESSION_MODEL *get_session_model_by_data (const void *ptr)
1072 {
1073 int i;
1074
1075 for (i=0; i<session.nmodels; i++) {
1076 if (ptr == session.models[i]->ptr) {
1077 return session.models[i];
1078 }
1079 }
1080
1081 return NULL;
1082 }
1083
delete_icon_for_data(void * data)1084 static void delete_icon_for_data (void *data)
1085 {
1086 gui_obj *gobj = get_gui_obj_by_data(data);
1087
1088 if (gobj != NULL) {
1089 /* icon is shown: delete it */
1090 session_delete_icon(gobj);
1091 }
1092 }
1093
show_model_in_window(void * ptr,GretlObjType type)1094 static int show_model_in_window (void *ptr, GretlObjType type)
1095 {
1096 char *name = NULL;
1097 PRN *prn;
1098
1099 if (type != GRETL_OBJ_EQN &&
1100 type != GRETL_OBJ_VAR &&
1101 type != GRETL_OBJ_SYS) {
1102 return 1;
1103 }
1104
1105 if (bufopen(&prn)) {
1106 return 1;
1107 }
1108
1109 gretl_object_compose_unique_name(ptr, type);
1110 name = gretl_object_get_name(ptr, type);
1111
1112 if (type == GRETL_OBJ_EQN) {
1113 MODEL *pmod = (MODEL *) ptr;
1114
1115 printmodel(pmod, dataset, OPT_NONE, prn);
1116 view_model(prn, pmod, name);
1117 } else if (type == GRETL_OBJ_VAR) {
1118 GRETL_VAR *var = (GRETL_VAR *) ptr;
1119
1120 gretl_VAR_print(var, dataset, OPT_NONE, prn);
1121 view_buffer(prn, 78, 450, name, var->ci, var);
1122 } else if (type == GRETL_OBJ_SYS) {
1123 equation_system *sys = (equation_system *) ptr;
1124
1125 gretl_system_print(sys, dataset, OPT_NONE, prn);
1126 view_buffer(prn, 78, 450, name, SYSTEM, sys);
1127 }
1128
1129 return 0;
1130 }
1131
1132 /* Callback (indirectly) from libgretl for a model created via
1133 script command. When this function is called, the model
1134 in question has already been stacked; it is just a matter
1135 of syncing the GUI session with the model stack state.
1136 */
1137
add_model_to_session_callback(void * ptr,GretlObjType type,gretlopt opt)1138 int add_model_to_session_callback (void *ptr, GretlObjType type,
1139 gretlopt opt)
1140 {
1141 SESSION_MODEL *model = NULL;
1142 char *name = gretl_object_get_name(ptr, type);
1143 int err = 0;
1144
1145 if (type == GRETL_OBJ_SYS && (opt & OPT_W)) {
1146 /* we got the --window callback from "estimate" */
1147 return show_model_in_window(ptr, type);
1148 } else if (name == NULL || *name == '\0') {
1149 /* we just got the --window callback */
1150 return show_model_in_window(ptr, type);
1151 }
1152
1153 /* are we replacing a session model's content? */
1154 model = get_session_model_by_name(name);
1155
1156 if (model != NULL) {
1157 windata_t *vwin = get_viewer_for_data(model->ptr);
1158
1159 if (vwin != NULL) {
1160 /* current model window is "orphaned" */
1161 gretl_viewer_destroy(vwin);
1162 }
1163 model->ptr = ptr;
1164 model->type = type;
1165 mark_session_changed();
1166 } else {
1167 err = add_model_to_session(ptr, name, type, &model);
1168 if (!err) {
1169 mark_session_changed();
1170 }
1171 }
1172
1173 if (!err && (opt & OPT_W)) {
1174 /* should open a window for this session model */
1175 display_session_model(model);
1176 }
1177
1178 return err;
1179 }
1180
model_type_from_vwin(windata_t * vwin)1181 static int model_type_from_vwin (windata_t *vwin)
1182 {
1183 if (vwin->role == SYSTEM) {
1184 return GRETL_OBJ_SYS;
1185 } else if (vwin->role == VAR || vwin->role == VECM) {
1186 return GRETL_OBJ_VAR;
1187 } else {
1188 return GRETL_OBJ_EQN;
1189 }
1190 }
1191
close_on_add(GtkAction * action)1192 static int close_on_add (GtkAction *action)
1193 {
1194 if (action == NULL) {
1195 return 1;
1196 } else {
1197 return (strstr(gtk_action_get_name(action), "Close") != NULL);
1198 }
1199 }
1200
model_add_as_icon(GtkAction * action,gpointer p)1201 void model_add_as_icon (GtkAction *action, gpointer p)
1202 {
1203 windata_t *vwin = (windata_t *) p;
1204 void *ptr = vwin->data;
1205 const char *name;
1206 int type;
1207 int err = 0;
1208
1209 if (ptr == NULL) {
1210 return;
1211 }
1212
1213 gretl_error_clear();
1214
1215 #if SESSION_DEBUG
1216 fprintf(stderr, "model_add_as_icon: ptr = %p\n", ptr);
1217 #endif
1218
1219 if (get_session_model_by_data(ptr)) {
1220 /* "can't happen" */
1221 if (close_on_add(action)) {
1222 gretl_viewer_destroy(vwin);
1223 } else {
1224 infobox(_("Model is already saved"));
1225 }
1226 return;
1227 }
1228
1229 type = model_type_from_vwin(vwin);
1230 name = gretl_object_get_name(ptr, type);
1231
1232 if (name != NULL && *name == '\0') {
1233 /* since we didn't get a match by data above, we
1234 need to ensure that this model is given a
1235 unique name */
1236 gretl_object_compose_unique_name(ptr, type);
1237 name = gretl_object_get_name(ptr, type);
1238 }
1239
1240 if (name == NULL) {
1241 nomem();
1242 return;
1243 }
1244
1245 err = add_model_to_session(ptr, name, type, NULL);
1246
1247 if (!err) {
1248 mark_session_changed();
1249 if (close_on_add(action)) {
1250 gretl_viewer_destroy(vwin);
1251 } else {
1252 set_model_save_state(vwin, FALSE);
1253 }
1254 }
1255 }
1256
1257 /* Called (via gui_utils.c) from toolbar.c, to implement
1258 saving displayed bundle as icon; handles VIEW_BUNDLE
1259 and also VIEW_DBNOMICS
1260 */
1261
bundle_add_as_icon(GtkAction * action,gpointer p)1262 void bundle_add_as_icon (GtkAction *action, gpointer p)
1263 {
1264 windata_t *vwin = (windata_t *) p;
1265 gretl_bundle *bundle = vwin->data;
1266 char vname[VNAMELEN];
1267 gchar *blurb;
1268 int resp;
1269
1270 sprintf(vname, "bundle%d", ++session_bundle_count);
1271 blurb = g_strdup_printf("Save bundle\nName (max. %d characters):",
1272 VNAMELEN - 1);
1273 resp = object_name_entry_dialog(vname, GRETL_TYPE_BUNDLE,
1274 blurb, NULL, vwin->main);
1275 g_free(blurb);
1276
1277 if (!canceled(resp)) {
1278 int err = user_var_add(vname, GRETL_TYPE_BUNDLE, bundle);
1279
1280 if (err) {
1281 gui_errmsg(err);
1282 } else {
1283 mark_session_changed();
1284 vwin_action_set_sensitive(vwin, "SaveAsIcon", FALSE);
1285 }
1286 }
1287 }
1288
1289 static void
session_name_from_session_file(char * sname,const char * fname)1290 session_name_from_session_file (char *sname, const char *fname)
1291 {
1292 const char *p = path_last_slash_const(fname);
1293 char *q;
1294
1295 if (p != NULL) {
1296 strcpy(sname, p + 1);
1297 } else {
1298 strcpy(sname, fname);
1299 }
1300
1301 q = strstr(sname, ".gretl");
1302 if (q != NULL && strlen(q) == 6) {
1303 *q = '\0';
1304 }
1305
1306 fprintf(stderr, "session_name_from_session_file: %s -> %s\n",
1307 fname, sname);
1308 }
1309
1310 /* remedial action in case of mis-coded filename */
1311
get_session_dataname(char * fname,struct sample_info * sinfo)1312 static int get_session_dataname (char *fname, struct sample_info *sinfo)
1313 {
1314 const gchar *dname;
1315 GDir *dir;
1316 FILE *fp;
1317 gchar *tmp;
1318 int n, err = E_FOPEN;
1319
1320 tmp = g_strdup(session.dirname);
1321 n = strlen(tmp);
1322
1323 if (tmp[n-1] == '/' || tmp[n-1] == '\\') {
1324 tmp[n-1] = '\0';
1325 }
1326
1327 dir = gretl_opendir(tmp);
1328
1329 if (dir != NULL) {
1330 while ((dname = g_dir_read_name(dir)) != NULL) {
1331 if (has_suffix(dname, ".gdt")) {
1332 session_file_make_path(fname, dname);
1333 fp = gretl_fopen(fname, "r");
1334 if (fp != NULL) {
1335 fclose(fp);
1336 err = 0;
1337 }
1338 break;
1339 }
1340 }
1341 g_dir_close(dir);
1342 }
1343
1344 g_free(tmp);
1345
1346 return err;
1347 }
1348
sinfo_init(struct sample_info * sinfo)1349 static void sinfo_init (struct sample_info *sinfo)
1350 {
1351 strcpy(sinfo->datafile, "data.gdt");
1352 sinfo->t1 = 0;
1353 sinfo->t2 = 0;
1354 sinfo->mask = NULL;
1355 sinfo->restriction = NULL;
1356 sinfo->seed = 0;
1357 sinfo->resample_n = 0;
1358 }
1359
sinfo_free_data(struct sample_info * sinfo)1360 static void sinfo_free_data (struct sample_info *sinfo)
1361 {
1362 if (sinfo->mask != NULL) {
1363 free(sinfo->mask);
1364 }
1365 if (sinfo->restriction != NULL) {
1366 free(sinfo->restriction);
1367 }
1368 }
1369
set_session_dirname(const char * zdirname)1370 static int set_session_dirname (const char *zdirname)
1371 {
1372 char test[2*MAXLEN];
1373 FILE *fp;
1374 int err = 0;
1375
1376 g_return_val_if_fail(zdirname != NULL, 1);
1377
1378 strcpy(session.dirname, zdirname);
1379 sprintf(test, "%s%csession.xml", session.dirname, SLASH);
1380 fp = gretl_fopen(test, "r");
1381
1382 if (fp == NULL) {
1383 err = E_FOPEN;
1384 } else {
1385 fclose(fp);
1386 }
1387
1388 return err;
1389 }
1390
maybe_absolutize_tryfile(void)1391 static char *maybe_absolutize_tryfile (void)
1392 {
1393 char *fname = get_tryfile();
1394
1395 if (!g_path_is_absolute(fname)) {
1396 gchar *cwd = g_get_current_dir();
1397
1398 if (cwd != NULL) {
1399 gchar *tmp = g_build_filename(cwd, fname, NULL);
1400
1401 set_tryfile(tmp);
1402 g_free(tmp);
1403 g_free(cwd);
1404 }
1405 }
1406
1407 return get_tryfile();
1408 }
1409
1410 /* note: the name of the file to be opened is in the gretl.c var
1411 'tryfile' */
1412
do_open_session(void)1413 gboolean do_open_session (void)
1414 {
1415 struct sample_info sinfo;
1416 char xmlname[MAXLEN]; /* path to master session XML file */
1417 char gdtname[MAXLEN]; /* path to session data file */
1418 char fname[MAXLEN]; /* multi-purpose temp variable */
1419 char *tryname = get_tryfile();
1420 gchar *zdirname = NULL;
1421 FILE *fp;
1422 int nodata = 0;
1423 int err = 0;
1424
1425 sinfo_init(&sinfo);
1426
1427 fp = gretl_fopen(tryname, "r");
1428 if (fp != NULL) {
1429 fclose(fp);
1430 } else {
1431 file_read_errbox(tryname);
1432 delete_from_filelist(FILE_LIST_SESSION, tryname);
1433 return FALSE;
1434 }
1435
1436 /* close existing session, if any, and initialize */
1437 close_session(OPT_NONE);
1438
1439 fprintf(stderr, "\nReading session file %s\n", tryname);
1440
1441 /* we're about to change directory: if tryfile is not
1442 an absolute path we'll lose track of it
1443 */
1444 tryname = maybe_absolutize_tryfile();
1445 gretl_chdir(gretl_dotdir());
1446 err = gretl_unzip_session_file(tryname, &zdirname);
1447
1448 if (err) {
1449 gui_errmsg(err);
1450 g_free(zdirname);
1451 goto bailout;
1452 }
1453
1454 session_name_from_session_file(session.name, tryname);
1455
1456 err = set_session_dirname(zdirname);
1457 if (err) {
1458 g_free(zdirname);
1459 fprintf(stderr, "Failed on set_session_dirname\n");
1460 file_read_errbox("session.xml");
1461 goto bailout;
1462 } else {
1463 fprintf(stderr, "set_session_dirname: '%s', OK\n", zdirname);
1464 }
1465
1466 g_free(zdirname);
1467 session_file_make_path(xmlname, "session.xml");
1468
1469 /* try getting the name of the session data file first */
1470 err = get_session_datafile_name(xmlname, &sinfo, &nodata);
1471
1472 if (err) {
1473 fprintf(stderr, "Failed on read_session_xml: err = %d\n", err);
1474 file_read_errbox("session.xml");
1475 goto bailout;
1476 }
1477
1478 if (!nodata) {
1479 /* construct path to session data file */
1480 session_file_make_path(datafile, sinfo.datafile);
1481 fp = gretl_fopen(datafile, "r");
1482
1483 if (fp != NULL) {
1484 /* OK, write good name into gdtname */
1485 fprintf(stderr, "got datafile name '%s'\n", datafile);
1486 strcpy(gdtname, datafile);
1487 fclose(fp);
1488 } else {
1489 /* try remedial action, transform filename? */
1490 fprintf(stderr, "'%s' : not found, trying to fix\n", datafile);
1491 err = get_session_dataname(gdtname, &sinfo);
1492 }
1493
1494 if (!err) {
1495 err = gretl_read_gdt(gdtname, dataset, OPT_B, NULL);
1496 }
1497
1498 if (err) {
1499 /* FIXME more explicit error message? */
1500 file_read_errbox(sinfo.datafile);
1501 goto bailout;
1502 } else {
1503 fprintf(stderr, "Opened session datafile '%s'\n", gdtname);
1504 data_status = USER_DATA;
1505 }
1506 }
1507
1508 /* having opened the data file (or not, if there's none), get the
1509 rest of the info from session.xml
1510 */
1511 err = read_session_xml(xmlname, &sinfo);
1512 if (err) {
1513 fprintf(stderr, "Failed on read_session_xml: err = %d\n", err);
1514 file_read_errbox("session.xml");
1515 goto bailout;
1516 }
1517
1518 err = deserialize_user_vars(session.dirname);
1519
1520 session_file_make_path(fname, "functions.xml");
1521 err = maybe_read_functions_file(fname);
1522
1523 session_file_make_path(fname, "settings.inp");
1524 err = maybe_read_settings_file(fname);
1525
1526 if (!nodata) {
1527 if (sinfo.resample_n > 0) {
1528 err = dataset_resample(dataset, sinfo.resample_n, sinfo.seed);
1529 } else if (sinfo.mask != NULL) {
1530 err = restrict_sample_from_mask(sinfo.mask, dataset, OPT_NONE);
1531 if (!err) {
1532 dataset->restriction = sinfo.restriction;
1533 sinfo.restriction = NULL;
1534 }
1535 }
1536
1537 if (err) {
1538 errbox(_("Couldn't set sample"));
1539 goto bailout;
1540 }
1541
1542 dataset->t1 = sinfo.t1;
1543 dataset->t2 = sinfo.t2;
1544
1545 register_data(OPENED_VIA_SESSION);
1546
1547 if (sinfo.mask != NULL) {
1548 set_sample_label(dataset);
1549 }
1550
1551 sinfo_free_data(&sinfo);
1552 }
1553
1554 set_main_window_title(session.name, FALSE);
1555
1556 bailout:
1557
1558 if (err) {
1559 delete_from_filelist(FILE_LIST_SESSION, tryname);
1560 } else {
1561 strcpy(sessionfile, tryname);
1562 mkfilelist(FILE_LIST_SESSION, sessionfile, 0);
1563
1564 session.status = SESSION_OPEN;
1565
1566 /* sync gui with session */
1567 session_menu_state(TRUE);
1568
1569 view_session();
1570 mark_session_saved();
1571 session_switch_log_location(LOG_OPEN);
1572
1573 if (session.show_notes) {
1574 edit_session_notes();
1575 }
1576 }
1577
1578 return !err;
1579 }
1580
verify_clear_data(void)1581 void verify_clear_data (void)
1582 {
1583 if (dataset_locked()) {
1584 return;
1585 }
1586
1587 if (yes_no_dialog("gretl",
1588 _("Clearing the data set will end\n"
1589 "your current session. Continue?"),
1590 NULL) != GRETL_YES) {
1591 return;
1592 }
1593
1594 close_session(OPT_NONE); /* FIXME opt? */
1595 }
1596
remove_session_dir(void)1597 static int remove_session_dir (void)
1598 {
1599 gchar *fullpath;
1600 int err;
1601
1602 fullpath = gretl_make_dotpath(session.dirname);
1603 err = gretl_chdir(gretl_dotdir());
1604 if (!err) {
1605 err = gretl_deltree(fullpath);
1606 }
1607 g_free(fullpath);
1608
1609 return err;
1610 }
1611
session_init(void)1612 void session_init (void)
1613 {
1614 session.models = NULL;
1615 session.graphs = NULL;
1616 session.texts = NULL;
1617 session.notes = NULL;
1618
1619 session.status = 0; /* note: neither changed nor saved */
1620 session.nmodels = 0;
1621 session.ngraphs = 0;
1622 session.ntexts = 0;
1623
1624 *session.name = '\0';
1625 *session.dirname = '\0';
1626
1627 set_user_var_callback(gui_user_var_callback);
1628 }
1629
free_session(int on_exit)1630 void free_session (int on_exit)
1631 {
1632 int i;
1633
1634 if (session.models) {
1635 for (i=0; i<session.nmodels; i++) {
1636 free_session_model(session.models[i]);
1637 }
1638 free(session.models);
1639 session.models = NULL;
1640 }
1641 session.nmodels = 0;
1642
1643 if (session.graphs) {
1644 for (i=0; i<session.ngraphs; i++) {
1645 free(session.graphs[i]);
1646 }
1647 free(session.graphs);
1648 session.graphs = NULL;
1649 }
1650 session.ngraphs = 0;
1651
1652 if (session.texts) {
1653 for (i=0; i<session.ntexts; i++) {
1654 free_session_text(session.texts[i]);
1655 }
1656 free(session.texts);
1657 session.texts = NULL;
1658 }
1659 session.ntexts = 0;
1660
1661 if (session.notes) {
1662 free(session.notes);
1663 session.notes = NULL;
1664 }
1665
1666 *session.name = '\0';
1667
1668 if (*session.dirname != '\0') {
1669 if (on_exit) {
1670 set_session_log(NULL, LOG_CLOSE);
1671 }
1672 remove_session_dir();
1673 *session.dirname = '\0';
1674 }
1675 }
1676
highest_numbered_variable_in_session(void)1677 int highest_numbered_variable_in_session (void)
1678 {
1679 GretlObjType type;
1680 void *ptr;
1681 int i, mvm, vmax = 0;
1682
1683 if (session.models == NULL) {
1684 return 0;
1685 }
1686
1687 for (i=0; i<session.nmodels; i++) {
1688 ptr = session.models[i]->ptr;
1689 if (ptr == NULL) {
1690 continue;
1691 }
1692 type = session.models[i]->type;
1693 if (type == GRETL_OBJ_EQN) {
1694 mvm = highest_numbered_var_in_model((MODEL *) ptr, dataset);
1695 if (mvm > vmax) {
1696 vmax = mvm;
1697 }
1698 } else if (type == GRETL_OBJ_VAR) {
1699 mvm = gretl_VAR_get_highest_variable((GRETL_VAR *) ptr);
1700 if (mvm > vmax) {
1701 vmax = mvm;
1702 }
1703 } else if (type == GRETL_OBJ_SYS) {
1704 mvm = highest_numbered_var_in_system((equation_system *) ptr,
1705 dataset);
1706 if (mvm > vmax) {
1707 vmax = mvm;
1708 }
1709 }
1710 }
1711
1712 return vmax;
1713 }
1714
session_model_list(void)1715 GList *session_model_list (void)
1716 {
1717 GList *list = NULL;
1718
1719 if (session.models != NULL) {
1720 GretlObjType type;
1721 void *ptr;
1722 int i;
1723
1724 for (i=0; i<session.nmodels; i++) {
1725 ptr = session.models[i]->ptr;
1726 type = session.models[i]->type;
1727 if (ptr != NULL && type == GRETL_OBJ_EQN) {
1728 list = g_list_append(list, ptr);
1729 }
1730 }
1731 }
1732
1733 return list;
1734 }
1735
session_file_is_open(void)1736 int session_file_is_open (void)
1737 {
1738 return (*sessionfile != '\0');
1739 }
1740
gui_clear_dataset(void)1741 void gui_clear_dataset (void)
1742 {
1743 *datafile = 0;
1744
1745 if (dataset->Z != NULL) {
1746 free_Z(dataset);
1747 dataset->Z = NULL;
1748 }
1749
1750 clear_datainfo(dataset, CLEAR_FULL);
1751
1752 clear_varlist(mdata->listbox);
1753 clear_sample_label();
1754 set_db_name(NULL, 0, NULL);
1755
1756 data_status = 0;
1757 orig_vars = 0;
1758 dataset_menubar_state(FALSE);
1759 }
1760
session_clear_data(DATASET * pdinfo)1761 static void session_clear_data (DATASET *pdinfo)
1762 {
1763 gui_restore_sample(pdinfo);
1764 gui_clear_dataset();
1765
1766 /* clear protected model */
1767 clear_model(model);
1768
1769 free_command_stack();
1770 set_model_count(0);
1771 lib_cmd_destroy_context();
1772 }
1773
close_session(gretlopt opt)1774 void close_session (gretlopt opt)
1775 {
1776 int preserve = (opt & OPT_P)? 1 : 0;
1777 int logcode = LOG_NULL;
1778 int iview = 0;
1779
1780 #if SESSION_DEBUG
1781 fprintf(stderr, "close_session: starting cleanup\n");
1782 #endif
1783
1784 if (dataset != NULL && dataset->v > 0) {
1785 logcode = LOG_CLOSE;
1786 session_clear_data(dataset);
1787 }
1788
1789 free_session(0);
1790
1791 clear_model_table(1, NULL);
1792 clear_graph_page(1);
1793
1794 session_menu_state(FALSE);
1795 *scriptfile = '\0';
1796 *sessionfile = '\0';
1797
1798 if (iconview != NULL) {
1799 iview = 1;
1800 gtk_widget_destroy(iconview);
1801 }
1802
1803 session.status = 0; /* not saved, changed or open */
1804 session.show_notes = 0;
1805 commands_recorded = 0;
1806
1807 close_session_windows(opt);
1808 selector_cleanup();
1809 function_call_cleanup();
1810 edit_dialog_special_get_text(NULL);
1811
1812 if (preserve) {
1813 /* preserve non-dataset items */
1814 libgretl_session_cleanup(SESSION_CLEAR_DATASET);
1815 } else {
1816 libgretl_session_cleanup(SESSION_CLEAR_ALL);
1817 }
1818
1819 session_graph_count = 0;
1820 session_bundle_count = 0;
1821 reset_plot_count();
1822 reset_collection_count();
1823
1824 set_session_log(NULL, logcode);
1825
1826 if (iview && have_session_objects()) {
1827 dataset_menubar_state(FALSE);
1828 view_session();
1829 }
1830 }
1831
relpath_from_fname(char * path,const char * fname)1832 static void relpath_from_fname (char *path, const char *fname)
1833 {
1834 const char *p;
1835
1836 strcpy(path, ".");
1837
1838 p = IS_SLASH(*fname) ? fname + 1 : fname;
1839 p = path_last_slash_const(p);
1840
1841 if (p != NULL) {
1842 strcat(path, p + 1);
1843 } else {
1844 strcat(path, fname);
1845 }
1846 }
1847
1848 /* dump the current dataset into the session dir */
1849
real_save_session_dataset(const char * dname)1850 static int real_save_session_dataset (const char *dname)
1851 {
1852 char tmpname[MAXLEN];
1853 char *mask = NULL;
1854 char *restr = NULL;
1855 int save_t1 = dataset->t1;
1856 int save_t2 = dataset->t2;
1857 int write_err = 0;
1858 int err = 0;
1859
1860 /* we need to retrieve and save the full version of the dataset */
1861
1862 if (complex_subsampled()) {
1863 mask = copy_dataset_submask(dataset, &err);
1864 if (!err && dataset_is_resampled(dataset)) {
1865 /* can't happen? */
1866 mask = NULL;
1867 }
1868 if (dataset->restriction != NULL) {
1869 restr = gretl_strdup(dataset->restriction);
1870 }
1871 }
1872
1873 if (!err) {
1874 err = restore_full_sample(dataset, NULL);
1875 }
1876
1877 if (!err) {
1878 session_file_make_path(tmpname, dname);
1879 write_err = gretl_write_gdt(tmpname, NULL, dataset,
1880 OPT_NONE, 1);
1881 }
1882
1883 if (mask != NULL) {
1884 /* reset the prior subsample */
1885 if (!err) {
1886 err = restrict_sample_from_mask(mask, dataset,
1887 OPT_NONE);
1888 }
1889 free(mask);
1890 }
1891 if (restr != NULL) {
1892 dataset->restriction = restr;
1893 }
1894
1895 dataset->t1 = save_t1;
1896 dataset->t2 = save_t2;
1897
1898 if (!err) {
1899 err = write_err;
1900 }
1901
1902 if (!err) {
1903 /* flag the fact that the data are saved */
1904 data_status &= ~MODIFIED_DATA;
1905 }
1906
1907 return err;
1908 }
1909
unpath(const char * fname)1910 static const char *unpath (const char *fname)
1911 {
1912 int i, n = strlen(fname);
1913
1914 for (i=n-1; i>=0; i--) {
1915 if (fname[i] == '/') {
1916 return fname + i + 1;
1917 }
1918 #ifdef G_OS_WIN32
1919 if (fname[i] == '\\') {
1920 return fname + i + 1;
1921 }
1922 #endif
1923 }
1924
1925 return fname;
1926 }
1927
1928 /* called in the context of a re-opened session */
1929
save_session_dataset(void)1930 int save_session_dataset (void)
1931 {
1932 int err = real_save_session_dataset(unpath(datafile));
1933
1934 if (err) {
1935 gui_errmsg(err);
1936 }
1937
1938 return err;
1939 }
1940
make_session_dataname(char * datname)1941 static void make_session_dataname (char *datname)
1942 {
1943 int changed = 0;
1944
1945 if (*datafile != '\0') {
1946 char *p;
1947
1948 strcpy(datname, unpath(datafile));
1949 p = strrchr(datname, '.');
1950 if (p == NULL) {
1951 strcat(datname, ".gdt");
1952 changed = 1;
1953 } else if (strcmp(p, ".gdt")) {
1954 strcpy(p, ".gdt");
1955 changed = 1;
1956 }
1957 } else {
1958 strcpy(datname, "data.gdt");
1959 changed = 1;
1960 }
1961
1962 if (changed) {
1963 GtkWidget *dlabel;
1964
1965 dlabel = g_object_get_data(G_OBJECT(mdata->main), "dlabel");
1966 if (dlabel != NULL) {
1967 gtk_label_set_text(GTK_LABEL(dlabel), datname);
1968 }
1969 }
1970 }
1971
1972 #define SAVE_DEBUG 1
1973
save_session(char * fname)1974 int save_session (char *fname)
1975 {
1976 char *dirbak = NULL;
1977 char datname[MAXLEN];
1978 char dirname[MAXLEN];
1979 int len, err = 0;
1980 int log_code = LOG_SAVE;
1981
1982 if (fname == NULL) {
1983 /* re-saving session 'as is' */
1984 fname = sessionfile;
1985 }
1986
1987 #if SAVE_DEBUG
1988 if (fname == sessionfile) {
1989 fprintf(stderr, "save_session:\n sessionfile='%s'\n",
1990 sessionfile);
1991 } else {
1992 fprintf(stderr, "save_session as:\n current session='%s'\n"
1993 " save filename='%s'\n", sessionfile, fname);
1994 }
1995 #endif
1996
1997 if (!session_dir_ok()) {
1998 errbox("Couldn't make session directory");
1999 return 1;
2000 }
2001
2002 /* organize directory and file names */
2003 relpath_from_fname(dirname, fname);
2004 len = strlen(fname);
2005 if (len > 6 && !strncmp(fname + len - 6, ".gretl", 6)) {
2006 dirname[strlen(dirname) - 6] = '\0';
2007 } else {
2008 strcat(fname, ".gretl");
2009 }
2010
2011 #if SAVE_DEBUG
2012 fprintf(stderr, " save dirname = '%s'\n", dirname);
2013 fprintf(stderr, " current session.dirname = '%s'\n", session.dirname);
2014 fprintf(stderr, " doing chdir to '%s'\n", gretl_dotdir());
2015 #endif
2016
2017 /* note: paths below are relative to this */
2018 err = gretl_chdir(gretl_dotdir());
2019 if (err) {
2020 fprintf(stderr, " chdir to dotdir failed\n");
2021 gui_errmsg(err);
2022 return 1;
2023 }
2024
2025 if (strcmp(dirname, session.dirname)) {
2026 /* have to rename the session directory */
2027 maybe_suspend_session_log();
2028 log_code = LOG_SAVE_AS;
2029 dirbak = gretl_strdup(session.dirname);
2030 if (gretl_isdir(dirname)) {
2031 /* don't trip over a non-empty dir */
2032 gretl_deltree(dirname);
2033 gretl_error_clear();
2034 }
2035 #ifdef G_OS_WIN32
2036 err = win32_rename_dir(session.dirname, dirname);
2037 #else
2038 err = gretl_rename(session.dirname, dirname);
2039 #endif
2040 if (err) {
2041 fprintf(stderr, " failed to rename session dir: '%s' -> '%s'\n",
2042 session.dirname, dirname);
2043 gui_errmsg(err);
2044 } else {
2045 fprintf(stderr, " renamed session dir OK\n");
2046 strcpy(session.dirname, dirname);
2047 }
2048 }
2049
2050 if (!err) {
2051 *datname = '\0';
2052 if (data_status) {
2053 make_session_dataname(datname);
2054 } else {
2055 strcpy(datname, "none");
2056 }
2057
2058 err = write_session_xml(datname);
2059 #if SAVE_DEBUG
2060 fprintf(stderr, " write_session_xml: err = %d\n", err);
2061 #endif
2062 }
2063
2064 if (!err && data_status) {
2065 err = real_save_session_dataset(datname);
2066 #if SAVE_DEBUG
2067 fprintf(stderr, " real_save_session_dataset: err = %d\n", err);
2068 #endif
2069 if (err) {
2070 gui_errmsg(err);
2071 }
2072 }
2073
2074 if (!err) {
2075 session_switch_log_location(log_code);
2076 }
2077
2078 if (!err) {
2079 /* make zipfile containing session files */
2080 err = gretl_make_zipfile(fname, dirname);
2081
2082 if (err) {
2083 fprintf(stderr, " gretl_make_zipfile: err = %d\n", err);
2084 gui_errmsg(err);
2085 } else {
2086 mkfilelist(FILE_LIST_SESSION, fname, 0);
2087 if (fname != sessionfile) {
2088 session_name_from_session_file(session.name, fname);
2089 strcpy(sessionfile, fname);
2090 data_status |= SESSION_DATA; /* FIXME? */
2091 set_sample_label(dataset);
2092 }
2093 mark_session_saved();
2094 }
2095 }
2096
2097 if (dirbak != NULL) {
2098 if (err) {
2099 /* restore original name on error */
2100 strcpy(session.dirname, dirbak);
2101 }
2102 free(dirbak);
2103 }
2104
2105 fprintf(stderr, "save_session; returning %d\n", err);
2106
2107 return err;
2108 }
2109
session_notes_callback(GtkWidget * w,gpointer p)2110 void session_notes_callback (GtkWidget *w, gpointer p)
2111 {
2112 windata_t *vwin = (windata_t *) p;
2113 const char *opts[] = {
2114 N_("Display notes on opening session file")
2115 };
2116 int active[] = {0};
2117 int resp;
2118
2119 active[0] = session.show_notes;
2120
2121 resp = checks_only_dialog("gretl", NULL, opts, 1,
2122 active, 0, vwin->main);
2123
2124 if (resp >= 0 && session.show_notes != active[0]) {
2125 session.show_notes = active[0];
2126 mark_session_changed();
2127 }
2128 }
2129
save_session_callback(GtkAction * action)2130 void save_session_callback (GtkAction *action)
2131 {
2132 int as_is = 0;
2133
2134 if (session_file_is_open() && action != NULL) {
2135 const gchar *s = gtk_action_get_name(action);
2136
2137 if (!strcmp(s, "SaveSession")) {
2138 as_is = 1;
2139 }
2140 }
2141
2142 if (as_is) {
2143 save_session(sessionfile);
2144 } else {
2145 file_selector(SAVE_SESSION, FSEL_DATA_NONE, NULL);
2146 }
2147 }
2148
save_session_commands(char * fname)2149 int save_session_commands (char *fname)
2150 {
2151 FILE *fp = gretl_fopen(fname, "w");
2152 int err = 0;
2153
2154 if (fp == NULL) {
2155 file_write_errbox(fname);
2156 err = E_FOPEN;
2157 } else {
2158 gchar *s = get_logfile_content(&err);
2159
2160 if (err) {
2161 gui_errmsg(err);
2162 } else {
2163 fputs(s, fp);
2164 g_free(s);
2165 }
2166
2167 fclose(fp);
2168 }
2169
2170 return err;
2171 }
2172
model_cmd_str(MODEL * pmod)2173 static char *model_cmd_str (MODEL *pmod)
2174 {
2175 char *str = NULL;
2176
2177 if (pmod->ci == MLE || pmod->ci == GMM || pmod->ncoeff > 10 ||
2178 pmod->list[0] > 10) {
2179 return NULL;
2180 }
2181
2182 str = malloc(MAXLEN);
2183 if (str == NULL) {
2184 return NULL;
2185 }
2186
2187 sprintf(str, "%s ", gretl_command_word(pmod->ci));
2188
2189 if (pmod->ci == AR) {
2190 model_list_to_string(pmod->arinfo->arlist, str);
2191 strcat(str, "; ");
2192 }
2193
2194 model_list_to_string(pmod->list, str);
2195
2196 return str;
2197 }
2198
graph_str(SESSION_GRAPH * graph)2199 static gchar *graph_str (SESSION_GRAPH *graph)
2200 {
2201 char tmp[MAXLEN];
2202 FILE *fp;
2203 gchar *buf = NULL;
2204
2205 session_file_make_path(tmp, graph->fname);
2206 fp = gretl_fopen(tmp, "r");
2207
2208 /* FIXME boxplots */
2209
2210 if (fp != NULL) {
2211 char line[128], title[64];
2212 char xlabel[24], ylabel[24];
2213 int gottitle = 0;
2214 int gotxy = 0;
2215
2216 while (fgets(line, sizeof line, fp)) {
2217 if (strstr(line, "# timeseries") || strstr(line, "# frequency") ||
2218 !strncmp(line, "plot", 4)) {
2219 break;
2220 } else if (sscanf(line, "set title '%63[^']", title) == 1) {
2221 gottitle = 1;
2222 break;
2223 } else if (sscanf(line, "set xlabel '%23[^']", xlabel) == 1) {
2224 gotxy++;
2225 } else if (sscanf(line, "set ylabel '%23[^']", ylabel) == 1) {
2226 gotxy++;
2227 }
2228 }
2229
2230 if (gottitle) {
2231 buf = g_strdup(title);
2232 } else if (gotxy == 2) {
2233 buf = g_strdup_printf("%s %s %s", ylabel, _("versus"), xlabel);
2234 }
2235
2236 if (buf != NULL && !g_utf8_validate(buf, -1, NULL)) {
2237 /* let's give up! */
2238 g_free(buf);
2239 buf = NULL;
2240 }
2241
2242 fclose(fp);
2243 }
2244
2245 return buf;
2246 }
2247
maybe_raise_object_window(gpointer data)2248 static int maybe_raise_object_window (gpointer data)
2249 {
2250 windata_t *vwin = get_viewer_for_data(data);
2251
2252 if (vwin != NULL) {
2253 gretl_viewer_present(vwin);
2254 return 1;
2255 } else {
2256 return 0;
2257 }
2258 }
2259
display_session_model(SESSION_MODEL * sm)2260 static int display_session_model (SESSION_MODEL *sm)
2261 {
2262 DATASET *dset = dataset;
2263 PRN *prn;
2264
2265 if (maybe_raise_object_window(sm->ptr)) {
2266 return 0;
2267 }
2268
2269 if (sm->type != GRETL_OBJ_SYS && bufopen(&prn)) {
2270 return 1;
2271 }
2272
2273 if (sm->type == GRETL_OBJ_EQN) {
2274 MODEL *pmod = (MODEL *) sm->ptr;
2275
2276 if (pmod->submask == NULL && complex_subsampled()) {
2277 dset = fetch_full_dataset();
2278 }
2279 printmodel(pmod, dset, OPT_NONE, prn);
2280 view_model(prn, pmod, sm->name);
2281 } else if (sm->type == GRETL_OBJ_VAR) {
2282 GRETL_VAR *var = (GRETL_VAR *) sm->ptr;
2283
2284 gretl_VAR_print(var, dset, OPT_NONE, prn);
2285 view_buffer(prn, 78, 450, sm->name, var->ci, var);
2286 } else if (sm->type == GRETL_OBJ_SYS) {
2287 equation_system *sys = (equation_system *) sm->ptr;
2288
2289 edit_dialog(ESTIMATE, sm->name, NULL, NULL,
2290 do_saved_eqn_system, sys,
2291 VARCLICK_NONE, iconview);
2292 }
2293
2294 return 0;
2295 }
2296
2297 /* callback used in objectsave.c */
2298
session_model_callback(void * ptr,int action)2299 void session_model_callback (void *ptr, int action)
2300 {
2301 SESSION_MODEL *mod = get_session_model_by_data(ptr);
2302
2303 if (mod == NULL) {
2304 return;
2305 }
2306
2307 if (action == OBJ_ACTION_SHOW) {
2308 display_session_model(mod);
2309 } else if (action == OBJ_ACTION_FREE) {
2310 delete_icon_for_data(mod);
2311 real_delete_model_from_session(mod);
2312 }
2313 }
2314
open_matrix(gui_obj * obj)2315 static void open_matrix (gui_obj *obj)
2316 {
2317 user_var *u = (user_var *) obj->data;
2318 const char *name = user_var_get_name(u);
2319
2320 edit_user_matrix_by_name(name, iconview);
2321 }
2322
is_dbnomics_bundle(const gretl_bundle * b)2323 static int is_dbnomics_bundle (const gretl_bundle *b)
2324 {
2325 const char *s = gretl_bundle_get_creator((gretl_bundle *) b);
2326
2327 return s != NULL && !strcmp(s, "dbnomics");
2328 }
2329
open_bundle(gui_obj * obj)2330 static void open_bundle (gui_obj *obj)
2331 {
2332 user_var *u = (user_var *) obj->data;
2333 const char *name = user_var_get_name(u);
2334 gretl_bundle *b = user_var_get_value(u);
2335 PRN *prn = NULL;
2336 int role, done = 0;
2337
2338 if (maybe_raise_object_window(b)) {
2339 return;
2340 }
2341
2342 if (!gretl_bundle_has_content(b)) {
2343 warnbox(_("Bundle is empty"));
2344 return;
2345 }
2346
2347 if (bufopen(&prn)) {
2348 return;
2349 }
2350
2351 role = VIEW_BUNDLE;
2352 done = try_exec_bundle_print_function(b, prn);
2353
2354 if (!done) {
2355 gretl_bundle_print(b, prn);
2356 } else if (is_dbnomics_bundle(b)) {
2357 role = VIEW_DBNOMICS;
2358 }
2359
2360 view_buffer(prn, 80, 400, name, role, b);
2361 }
2362
open_gui_text(gui_obj * obj)2363 static void open_gui_text (gui_obj *obj)
2364 {
2365 SESSION_TEXT *text = (SESSION_TEXT *) obj->data;
2366 PRN *prn;
2367
2368 prn = gretl_print_new_with_buffer(g_strdup(text->buf));
2369
2370 if (prn != NULL) {
2371 view_buffer(prn, 80, 400, obj->name, INFO, NULL);
2372 }
2373 }
2374
real_delete_model_from_session(SESSION_MODEL * model)2375 static int real_delete_model_from_session (SESSION_MODEL *model)
2376 {
2377 int nm = session.nmodels - 1;
2378
2379 if (nm == 0) {
2380 free_session_model(session.models[0]);
2381 free(session.models);
2382 session.models = NULL;
2383 } else {
2384 SESSION_MODEL **mods;
2385 int i, j = 0;
2386
2387 for (i=0; i<session.nmodels; i++) {
2388 if (session.models[i]->ptr == model->ptr) {
2389 free_session_model(session.models[i]);
2390 j = i;
2391 break;
2392 }
2393 }
2394
2395 for (i=j; i<nm; i++) {
2396 session.models[i] = session.models[i+1];
2397 }
2398
2399 mods = myrealloc(session.models, nm * sizeof *mods);
2400 if (mods != NULL) {
2401 session.models = mods;
2402 }
2403 }
2404
2405 /* FIXME should delete the model's file in the session
2406 directory? */
2407
2408 session.nmodels = nm;
2409 mark_session_changed();
2410
2411 return 0;
2412 }
2413
real_delete_text_from_session(SESSION_TEXT * junk)2414 static int real_delete_text_from_session (SESSION_TEXT *junk)
2415 {
2416 int nt = session.ntexts;
2417
2418 if (nt == 1) {
2419 free_session_text(session.texts[0]);
2420 free(session.texts);
2421 session.texts = NULL;
2422 } else {
2423 SESSION_TEXT **pptext;
2424 int i, j;
2425
2426 pptext = mymalloc((nt - 1) * sizeof *pptext);
2427 if (pptext == NULL) {
2428 return 1;
2429 }
2430 j = 0;
2431 for (i=0; i<nt; i++) {
2432 if (session.texts[i] != junk) {
2433 pptext[j++] = session.texts[i];
2434 } else {
2435 free_session_text(session.texts[i]);
2436 }
2437 }
2438 free(session.texts);
2439 session.texts = pptext;
2440 }
2441
2442 session.ntexts = nt - 1;
2443 mark_session_changed();
2444
2445 return 0;
2446 }
2447
remove_session_graph_file(SESSION_GRAPH * graph)2448 static void remove_session_graph_file (SESSION_GRAPH *graph)
2449 {
2450 char fname[MAXLEN];
2451
2452 gretl_chdir(gretl_dotdir());
2453 session_file_make_path(fname, graph->fname);
2454 gretl_remove(fname);
2455
2456 if (graph->has_datafile) {
2457 gchar *datfile = g_strdup_printf("%s.dat", fname);
2458
2459 gretl_remove(datfile);
2460 g_free(datfile);
2461 }
2462 }
2463
real_delete_graph_from_session(SESSION_GRAPH * junk)2464 static int real_delete_graph_from_session (SESSION_GRAPH *junk)
2465 {
2466 int ng = session.ngraphs;
2467
2468 if (ng == 1) {
2469 remove_session_graph_file(session.graphs[0]);
2470 free(session.graphs[0]);
2471 free(session.graphs);
2472 session.graphs = NULL;
2473 } else {
2474 SESSION_GRAPH **ppgr;
2475 int i, j, done = 0;
2476
2477 for (i=0; i<ng && !done; i++) {
2478 if (!strcmp(session.graphs[i]->name, junk->name)) {
2479 remove_session_graph_file(session.graphs[i]);
2480 free(session.graphs[i]);
2481 for (j=i; j<ng-1; j++) {
2482 session.graphs[j] = session.graphs[j+1];
2483 }
2484 done = 1;
2485 }
2486 }
2487
2488 if (done) {
2489 ppgr = myrealloc(session.graphs, (ng - 1) * sizeof *ppgr);
2490 if (ppgr == NULL) {
2491 return 1;
2492 }
2493 session.graphs = ppgr;
2494 }
2495 }
2496
2497 session.ngraphs = ng - 1;
2498 mark_session_changed();
2499
2500 return 0;
2501 }
2502
delete_session_object(gui_obj * obj)2503 static int delete_session_object (gui_obj *obj)
2504 {
2505 if (obj->sort == GRETL_OBJ_EQN || obj->sort == GRETL_OBJ_VAR ||
2506 obj->sort == GRETL_OBJ_SYS) {
2507 real_delete_model_from_session(obj->data);
2508 } else if (obj->sort == GRETL_OBJ_GRAPH || obj->sort == GRETL_OBJ_PLOT) {
2509 real_delete_graph_from_session(obj->data);
2510 } else if (obj->sort == GRETL_OBJ_TEXT) {
2511 real_delete_text_from_session(obj->data);
2512 } else if (obj->sort == GRETL_OBJ_MATRIX ||
2513 obj->sort == GRETL_OBJ_BUNDLE) {
2514 user_var_delete(obj->data);
2515 }
2516
2517 session_delete_icon(obj);
2518 mark_session_changed();
2519
2520 return 0;
2521 }
2522
2523 /* run a sanity check on deleting a session object (e.g.
2524 model, graph) before proceeding */
2525
maybe_delete_session_object(gui_obj * obj)2526 static void maybe_delete_session_object (gui_obj *obj)
2527 {
2528 GtkWidget *busywin = NULL;
2529
2530 if (obj->sort == GRETL_OBJ_GRAPH || obj->sort == GRETL_OBJ_PLOT) {
2531 SESSION_GRAPH *graph = (SESSION_GRAPH *) obj->data;
2532
2533 busywin = get_window_for_plot(graph);
2534 if (busywin == NULL) {
2535 char fullname[MAXLEN];
2536
2537 session_file_make_path(fullname, graph->fname);
2538 busywin = vwin_toplevel(get_editor_for_file(fullname));
2539 if (busywin == NULL) {
2540 busywin = get_viewer_for_plot(fullname);
2541 }
2542 }
2543 } else {
2544 gpointer p = NULL;
2545
2546 if (obj->sort == GRETL_OBJ_EQN || obj->sort == GRETL_OBJ_SYS ||
2547 obj->sort == GRETL_OBJ_VAR) {
2548 SESSION_MODEL *mod = obj->data;
2549
2550 p = mod->ptr;
2551 } else if (obj->sort == GRETL_OBJ_BUNDLE) {
2552 p = user_var_get_value((user_var *) obj->data);
2553 } else {
2554 p = obj->data;
2555 }
2556
2557 if (p != NULL) {
2558 if (obj->sort == GRETL_OBJ_MATRIX) {
2559 busywin = get_window_for_data(p);
2560 } else {
2561 busywin = vwin_toplevel(get_viewer_for_data(p));
2562 }
2563 }
2564 }
2565
2566 if (busywin != NULL) {
2567 gtk_window_present(GTK_WINDOW(busywin));
2568 warnbox_printf(_("%s: please close this object's window first"),
2569 obj->name);
2570 } else {
2571 gchar *msg = g_strdup_printf(_("Really delete %s?"), obj->name);
2572
2573 if (yes_no_dialog(_("gretl: delete"), msg, iconview) == GRETL_YES) {
2574 delete_session_object(obj);
2575 }
2576 g_free(msg);
2577 }
2578 }
2579
get_gui_obj_by_data(void * targ)2580 static gui_obj *get_gui_obj_by_data (void *targ)
2581 {
2582 GList *mylist = g_list_first(iconlist);
2583 gui_obj *obj = NULL;
2584
2585 while (mylist != NULL) {
2586 obj = (gui_obj *) mylist->data;
2587 if (obj->data == targ) {
2588 return obj;
2589 }
2590 mylist = mylist->next;
2591 }
2592
2593 return NULL;
2594 }
2595
get_obj_type(GretlType type)2596 static GretlObjType get_obj_type (GretlType type)
2597 {
2598 if (type == GRETL_TYPE_MATRIX) {
2599 return GRETL_OBJ_MATRIX;
2600 } else if (type == GRETL_TYPE_BUNDLE) {
2601 return GRETL_OBJ_BUNDLE;
2602 } else {
2603 return GRETL_OBJ_NULL;
2604 }
2605 }
2606
2607 /* called from DELEET case in library.c */
2608
session_user_var_destroy_by_name(const char * name,GretlObjType type)2609 int session_user_var_destroy_by_name (const char *name,
2610 GretlObjType type)
2611 {
2612 user_var *u = get_user_var_by_name(name);
2613 int err;
2614
2615 if (u == NULL) {
2616 err = E_UNKVAR;
2617 } else {
2618 maybe_close_window_for_user_var(u, type);
2619 if (iconlist != NULL) {
2620 gui_obj *obj = get_gui_obj_by_data(u);
2621
2622 session_delete_icon(obj);
2623 }
2624 err = user_var_delete(u);
2625 }
2626
2627 return err;
2628 }
2629
rename_session_graph(SESSION_GRAPH * graph,const char * newname)2630 static void rename_session_graph (SESSION_GRAPH *graph, const char *newname)
2631 {
2632 int i;
2633
2634 for (i=0; i<session.ngraphs; i++) {
2635 if (!strcmp(session.graphs[i]->name, graph->name)) {
2636 session.graphs[i]->name[0] = '\0';
2637 strncat(session.graphs[i]->name, newname, MAXSAVENAME - 1);
2638 break;
2639 }
2640 }
2641 }
2642
maybe_sync_model_window_name(SESSION_MODEL * sm)2643 static void maybe_sync_model_window_name (SESSION_MODEL *sm)
2644 {
2645 windata_t *vwin = get_viewer_for_data(sm->ptr);
2646
2647 if (vwin != NULL) {
2648 gchar *title = g_strdup_printf("gretl: %s", sm->name);
2649
2650 gretl_viewer_set_title(vwin, title);
2651 g_free(title);
2652 }
2653 }
2654
rename_session_object(gui_obj * obj,const char * newname,GtkWidget * parent)2655 static int rename_session_object (gui_obj *obj, const char *newname,
2656 GtkWidget *parent)
2657 {
2658 int err_shown = 0;
2659 int err = 0;
2660
2661 if (obj->sort == GRETL_OBJ_EQN || obj->sort == GRETL_OBJ_SYS ||
2662 obj->sort == GRETL_OBJ_VAR) {
2663 SESSION_MODEL *sm;
2664
2665 sm = get_session_model_by_name(newname);
2666 if (sm != NULL) {
2667 err = 1;
2668 } else {
2669 sm = obj->data;
2670 gretl_object_rename(sm->ptr, sm->type, newname);
2671 *sm->name = '\0';
2672 strncat(sm->name, newname, MAXSAVENAME - 1);
2673 maybe_sync_model_window_name(sm);
2674 }
2675 } else if (obj->sort == GRETL_OBJ_GRAPH ||
2676 obj->sort == GRETL_OBJ_PLOT) {
2677 SESSION_GRAPH *sg;
2678
2679 sg = get_session_graph_by_name(newname);
2680 if (sg != NULL) {
2681 err = 1;
2682 } else {
2683 sg = obj->data;
2684 rename_session_graph(sg, newname);
2685 }
2686 } else if (obj->sort == GRETL_OBJ_MATRIX ||
2687 obj->sort == GRETL_OBJ_BUNDLE) {
2688 GretlType type = (obj->sort == GRETL_OBJ_MATRIX)?
2689 GRETL_TYPE_MATRIX : GRETL_TYPE_BUNDLE;
2690
2691 err = gui_validate_varname_strict(newname, type, parent);
2692 if (err) {
2693 err_shown = 1;
2694 } else {
2695 user_var_set_name(obj->data, newname);
2696 }
2697 } else if (obj->sort == GRETL_OBJ_TEXT) {
2698 SESSION_TEXT *st;
2699
2700 st = get_session_text_by_name(newname);
2701 if (st != NULL) {
2702 err = 1;
2703 } else {
2704 st = obj->data;
2705 *st->name = '\0';
2706 strncat(st->name, newname, MAXSAVENAME - 1);
2707 }
2708 }
2709
2710 if (err && !err_shown) {
2711 errbox_printf(_("'%s': there is already an object of this name"),
2712 newname);
2713 } else if (!err) {
2714 free(obj->name);
2715 obj->name = g_strdup(newname);
2716 }
2717
2718 return err;
2719 }
2720
copy_session_object(gui_obj * obj,const char * cpyname)2721 static int copy_session_object (gui_obj *obj, const char *cpyname)
2722 {
2723 void *oldp = NULL;
2724 void *p = NULL;
2725 int ptype = 0;
2726 int err = 0;
2727
2728 /* Only graphs and matrices are supported for copying */
2729
2730 if (obj->sort == GRETL_OBJ_GRAPH || obj->sort == GRETL_OBJ_PLOT) {
2731 oldp = get_session_graph_by_name(cpyname);
2732 } else if (obj->sort == GRETL_OBJ_MATRIX) {
2733 oldp = get_user_var_by_name(cpyname);
2734 }
2735
2736 if (oldp != NULL) {
2737 errbox_printf(_("'%s': there is already an object of this name"),
2738 cpyname);
2739 } else if (obj->sort == GRETL_OBJ_GRAPH || obj->sort == GRETL_OBJ_PLOT) {
2740 SESSION_GRAPH *g0 = obj->data;
2741
2742 errno = 0;
2743 if (!session_dir_ok()) {
2744 err = 1;
2745 } else {
2746 char fname1[MAXSAVENAME];
2747 char path0[FILENAME_MAX];
2748 char path1[FILENAME_MAX];
2749
2750 err = gretl_chdir(gretl_dotdir());
2751 if (!err) {
2752 make_graph_filename(fname1);
2753 session_file_make_path(path0, g0->fname);
2754 session_file_make_path(path1, fname1);
2755 err = copyfile(path0, path1);
2756 }
2757 if (!err) {
2758 p = session_append_graph(cpyname, fname1, g0->type);
2759 ptype = g0->type;
2760 err = (p == NULL);
2761 }
2762 }
2763 } else if (obj->sort == GRETL_OBJ_MATRIX) {
2764 user_var *u = obj->data;
2765
2766 err = copy_matrix_as(user_var_get_value(u), cpyname, 0);
2767 if (!err) {
2768 p = get_user_var_by_name(cpyname);
2769 ptype = GRETL_OBJ_MATRIX;
2770 err = (p == NULL);
2771 }
2772 }
2773
2774 if (!err) {
2775 session_add_icon(p, ptype, ICON_ADD_SINGLE);
2776 }
2777
2778 return err;
2779 }
2780
copy_object_callback(GtkWidget * widget,dialog_t * dlg)2781 static void copy_object_callback (GtkWidget *widget, dialog_t *dlg)
2782 {
2783 gui_obj *obj = (gui_obj *) edit_dialog_get_data(dlg);
2784 const gchar *cpyname;
2785 int err = 0;
2786
2787 cpyname = edit_dialog_get_text(dlg);
2788
2789 if (cpyname != NULL && *cpyname != '\0') {
2790 err = copy_session_object(obj, cpyname);
2791 if (err) {
2792 errbox(_("Failed to copy object"));
2793 } else {
2794 mark_session_changed();
2795 }
2796 }
2797
2798 if (!err) {
2799 edit_dialog_close(dlg);
2800 }
2801 }
2802
copy_object_dialog(gui_obj * obj)2803 static void copy_object_dialog (gui_obj *obj)
2804 {
2805 int maxlen = MAXSAVENAME - 1;
2806 gchar *tmp;
2807
2808 if (obj->sort != GRETL_OBJ_MATRIX &&
2809 obj->sort != GRETL_OBJ_GRAPH &&
2810 obj->sort != GRETL_OBJ_PLOT) {
2811 dummy_call();
2812 }
2813
2814 if (obj->sort == GRETL_OBJ_MATRIX || obj->sort == GRETL_OBJ_BUNDLE) {
2815 maxlen = VNAMELEN - 1;
2816 }
2817
2818 tmp = g_strdup_printf(_("Enter new name\n(max. %d characters)"),
2819 maxlen);
2820 edit_dialog(0, _("gretl: copy object"), tmp, obj->name,
2821 copy_object_callback, obj,
2822 VARCLICK_NONE, iconview);
2823 g_free(tmp);
2824 }
2825
rename_object_callback(GtkWidget * widget,dialog_t * dlg)2826 static void rename_object_callback (GtkWidget *widget, dialog_t *dlg)
2827 {
2828 gui_obj *obj = (gui_obj *) edit_dialog_get_data(dlg);
2829 const gchar *newname;
2830 int err = 0;
2831
2832 newname = edit_dialog_get_text(dlg);
2833
2834 if (newname != NULL && *newname != '\0' &&
2835 strcmp(newname, obj->name)) {
2836 GtkWidget *parent = edit_dialog_get_window(dlg);
2837 gchar str[2*SHOWNAMELEN];
2838
2839 err = rename_session_object(obj, newname, parent);
2840 if (!err) {
2841 make_short_label_string(str, obj->name);
2842 gtk_label_set_text(GTK_LABEL(obj->label), str);
2843 mark_session_changed();
2844 }
2845 }
2846
2847 if (!err) {
2848 edit_dialog_close(dlg);
2849 }
2850 }
2851
rename_object_dialog(gui_obj * obj)2852 static void rename_object_dialog (gui_obj *obj)
2853 {
2854 int maxlen = MAXSAVENAME - 1;
2855 gchar *tmp;
2856
2857 if (obj->sort == GRETL_OBJ_MATRIX || obj->sort == GRETL_OBJ_BUNDLE) {
2858 maxlen = VNAMELEN - 1;
2859 }
2860
2861 tmp = g_strdup_printf(_("Enter new name\n(max. %d characters)"),
2862 maxlen);
2863 edit_dialog(0, _("gretl: rename object"), tmp, obj->name,
2864 rename_object_callback, obj,
2865 VARCLICK_NONE, iconview);
2866 g_free(tmp);
2867 }
2868
delete_text_from_session(void * p)2869 void delete_text_from_session (void *p)
2870 {
2871 SESSION_TEXT *text = (SESSION_TEXT *) p;
2872 gui_obj *obj;
2873
2874 if (text == NULL) return;
2875
2876 real_delete_text_from_session(text);
2877
2878 obj = get_gui_obj_by_data((void *) text);
2879 if (obj != NULL) {
2880 session_delete_icon(obj);
2881 }
2882 }
2883
display_saved_text(void * p)2884 void display_saved_text (void *p)
2885 {
2886 SESSION_TEXT *text = (SESSION_TEXT *) p;
2887 PRN *prn;
2888
2889 if (text == NULL) return;
2890
2891 prn = gretl_print_new_with_buffer(g_strdup(text->buf));
2892 if (prn != NULL) {
2893 view_buffer(prn, 80, 400, text->name, INFO, NULL);
2894 }
2895 }
2896
session_view_init(void)2897 static void session_view_init (void)
2898 {
2899 iconlist = NULL;
2900 icon_table = NULL;
2901 iconview_width = 0;
2902 iconview_cols = ICONVIEW_MIN_COLS;
2903 }
2904
gui_obj_destroy(gui_obj * obj,gpointer p)2905 static void gui_obj_destroy (gui_obj *obj, gpointer p)
2906 {
2907 if (obj != NULL) {
2908 #if SESSION_DEBUG
2909 fprintf(stderr, "freeing obj at %p (%s)\n", (void *) obj, obj->name);
2910 #endif
2911 if (obj->name != NULL) {
2912 g_free(obj->name);
2913 }
2914 g_object_unref(obj->icon);
2915 g_object_unref(obj->label);
2916 free(obj);
2917 }
2918 }
2919
session_view_free(GtkWidget * w,gpointer data)2920 static void session_view_free (GtkWidget *w, gpointer data)
2921 {
2922 iconview = NULL;
2923
2924 g_list_foreach(iconlist, (GFunc) gui_obj_destroy, NULL);
2925
2926 g_list_free(iconlist);
2927 iconlist = NULL;
2928 }
2929
session_delete_icon(gui_obj * obj)2930 static void session_delete_icon (gui_obj *obj)
2931 {
2932 if (obj == NULL) return;
2933
2934 if (obj->icon != NULL && GTK_IS_WIDGET(obj->icon)) {
2935 gtk_container_remove(GTK_CONTAINER(icon_table), obj->icon);
2936 }
2937 if (obj->label != NULL && GTK_IS_WIDGET(obj->label)) {
2938 gtk_container_remove(GTK_CONTAINER(icon_table), obj->label);
2939 }
2940
2941 iconlist = g_list_first(iconlist);
2942 iconlist = g_list_remove(iconlist, obj);
2943
2944 gui_obj_destroy(obj, NULL);
2945
2946 if (iconlist == NULL) {
2947 fprintf(stderr, "Bad: iconlist has gone NULL\n");
2948 }
2949 }
2950
2951 /* apparatus for getting a white background */
2952
2953 #if GTK_MAJOR_VERSION >= 3
2954
white_bg_style(GtkWidget * widget,gpointer data)2955 static void white_bg_style (GtkWidget *widget, gpointer data)
2956 {
2957 static GdkRGBA rgbw = {1, 1, 1, 1};
2958 static GdkRGBA rgbb;
2959 static int done;
2960
2961 gtk_widget_override_background_color(widget,
2962 GTK_STATE_FLAG_NORMAL,
2963 &rgbw);
2964 if (!done) {
2965 gdk_rgba_parse(&rgbb, "#4a90d9");
2966 }
2967 gtk_widget_override_background_color(widget,
2968 GTK_STATE_FLAG_PRELIGHT,
2969 &rgbb);
2970 }
2971
2972 #else
2973
get_white(void)2974 static GdkColor *get_white (void)
2975 {
2976 GdkColormap *cmap;
2977 GdkColor *white;
2978
2979 white = mymalloc(sizeof *white);
2980 if (white == NULL) return NULL;
2981
2982 cmap = gdk_colormap_get_system();
2983 gdk_color_parse("white", white);
2984 gdk_colormap_alloc_color(cmap, white, FALSE, TRUE);
2985
2986 return white;
2987 }
2988
white_bg_style(GtkWidget * widget,gpointer data)2989 static void white_bg_style (GtkWidget *widget, gpointer data)
2990 {
2991 static GdkColor *white;
2992
2993 if (white == NULL) {
2994 white = get_white();
2995 }
2996
2997 gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, white);
2998 }
2999
3000 #endif
3001
real_pack_icon(gui_obj * obj,int row,int col)3002 static void real_pack_icon (gui_obj *obj, int row, int col)
3003 {
3004 obj->row = row;
3005 obj->col = col;
3006
3007 gtk_table_attach(GTK_TABLE(icon_table), obj->icon,
3008 col, col + 1, row, row + 1,
3009 GTK_EXPAND, GTK_FILL, 5, 5);
3010
3011 gtk_widget_show(obj->icon);
3012 white_bg_style(obj->icon, NULL);
3013
3014 gtk_table_attach(GTK_TABLE(icon_table), obj->label,
3015 col, col + 1, row + 1, row + 2,
3016 GTK_EXPAND, GTK_FILL, 5, 5);
3017
3018 gtk_widget_show(obj->label);
3019 }
3020
pack_single_icon(gui_obj * obj)3021 static void pack_single_icon (gui_obj *obj)
3022 {
3023 int row, col;
3024 gui_obj *last;
3025
3026 iconlist = g_list_last(iconlist);
3027 last = iconlist->data;
3028 row = last->row;
3029 col = last->col;
3030
3031 iconlist = g_list_append(iconlist, obj);
3032
3033 col++;
3034 if (col > 0 && (col % iconview_cols == 0)) {
3035 col = 0;
3036 row += 2;
3037 gtk_table_resize(GTK_TABLE(icon_table), 2 * row, iconview_cols);
3038 }
3039
3040 real_pack_icon(obj, row, col);
3041 }
3042
3043 /* returns the number of rows used, counting 1 per icon + label */
3044
batch_pack_icons(void)3045 static int batch_pack_icons (void)
3046 {
3047 GList *mylist = g_list_first(iconlist);
3048 gui_obj *obj;
3049 int row = 0, col = 0;
3050
3051 while (mylist != NULL) {
3052 obj = (gui_obj *) mylist->data;
3053 real_pack_icon(obj, row, col);
3054 col++;
3055 if (col > 0 && (col % iconview_cols == 0)) {
3056 col = 0;
3057 row += 2;
3058 gtk_table_resize(GTK_TABLE(icon_table), 2 * row, iconview_cols);
3059 }
3060 if (mylist->next == NULL) {
3061 break;
3062 } else {
3063 mylist = mylist->next;
3064 }
3065 }
3066
3067 return row / 2;
3068 }
3069
gui_user_var_callback(const char * name,GretlType type,int action)3070 static int gui_user_var_callback (const char *name, GretlType type,
3071 int action)
3072 {
3073 GretlObjType otype = get_obj_type(type);
3074 user_var *u;
3075 int err = 0;
3076
3077 if (action == UVAR_ADD) {
3078 /* variable has been added, GUI sync wanted */
3079 if (iconview != NULL) {
3080 u = get_user_var_of_type_by_name(name, type);
3081 if (u != NULL) {
3082 session_add_icon(u, otype, ICON_ADD_SINGLE);
3083 }
3084 } else if (type != GRETL_TYPE_MATRIX && autoicon_on()) {
3085 /* auto-open icon view unless we added a matrix */
3086 auto_view_session();
3087 }
3088 if (iconview != NULL && waiting_for_output()) {
3089 gtk_widget_set_sensitive(iconview, FALSE);
3090 }
3091 mark_session_changed();
3092 } else if (action == UVAR_DELETE) {
3093 /* variable not yet deleted (deferred to GUI) */
3094 u = get_user_var_of_type_by_name(name, type);
3095 if (u == NULL) {
3096 err = E_UNKVAR;
3097 } else {
3098 maybe_close_window_for_user_var(u, otype);
3099 if (iconlist != NULL) {
3100 session_delete_icon(get_gui_obj_by_data(u));
3101 }
3102 err = user_var_delete(u);
3103 }
3104 }
3105
3106 return err;
3107 }
3108
maybe_sensitize_iconview(void)3109 void maybe_sensitize_iconview (void)
3110 {
3111 if (iconview != NULL && !gtk_widget_is_sensitive(iconview)) {
3112 gtk_widget_set_sensitive(iconview, TRUE);
3113 }
3114 }
3115
have_session_objects(void)3116 int have_session_objects (void)
3117 {
3118 int n = data_status;
3119
3120 /* Note: the following lines enable the icon view even when
3121 there's no dataset present.
3122 */
3123
3124 if (n == 0) {
3125 n = session.ngraphs + session.ntexts;
3126 }
3127
3128 if (n == 0) {
3129 n = n_user_matrices() + n_user_bundles() + n_user_scalars();
3130 }
3131
3132 return n > 0;
3133 }
3134
add_user_var_icon(gpointer data,gpointer intp)3135 static void add_user_var_icon (gpointer data, gpointer intp)
3136 {
3137 session_add_icon(data, GPOINTER_TO_INT(intp), ICON_ADD_BATCH);
3138 }
3139
3140 /* returns the number of rows of (icon + label) */
3141
add_all_icons(void)3142 static int add_all_icons (void)
3143 {
3144 int show_graph_page = check_for_program(latex);
3145 GList *list = NULL;
3146 int i;
3147
3148 active_object = NULL;
3149
3150 if (data_status) {
3151 session_add_icon(NULL, GRETL_OBJ_INFO, ICON_ADD_BATCH); /* data info */
3152 session_add_icon(NULL, GRETL_OBJ_DSET, ICON_ADD_BATCH); /* data file */
3153 session_add_icon(NULL, GRETL_OBJ_STATS, ICON_ADD_BATCH); /* summary stats */
3154 session_add_icon(NULL, GRETL_OBJ_CORR, ICON_ADD_BATCH); /* correlation matrix */
3155 session_add_icon(NULL, GRETL_OBJ_MODTAB, ICON_ADD_BATCH); /* model table */
3156 }
3157
3158 /* standard icons that don't really require a dataset in place */
3159 session_add_icon(NULL, GRETL_OBJ_SCALARS, ICON_ADD_BATCH); /* scalars */
3160 session_add_icon(NULL, GRETL_OBJ_NOTES, ICON_ADD_BATCH); /* session notes */
3161 if (show_graph_page) {
3162 session_add_icon(NULL, GRETL_OBJ_GPAGE, ICON_ADD_BATCH); /* graph page */
3163 }
3164
3165 for (i=0; i<session.nmodels; i++) {
3166 #if SESSION_DEBUG
3167 fprintf(stderr, "adding session.models[%d] (type %d) to view\n", i,
3168 session.models[i]->type);
3169 #endif
3170 session_add_icon(session.models[i], session.models[i]->type,
3171 ICON_ADD_BATCH);
3172 }
3173
3174 for (i=0; i<session.ngraphs; i++) {
3175 #if SESSION_DEBUG
3176 fprintf(stderr, "adding session.graphs[%d] (type %d) to view\n", i,
3177 session.graphs[i]->type);
3178 #endif
3179 session_add_icon(session.graphs[i], session.graphs[i]->type,
3180 ICON_ADD_BATCH);
3181 }
3182
3183 for (i=0; i<session.ntexts; i++) {
3184 #if SESSION_DEBUG
3185 fprintf(stderr, "adding session.texts[%d] to view\n", i);
3186 #endif
3187 session_add_icon(session.texts[i], GRETL_OBJ_TEXT, ICON_ADD_BATCH);
3188 }
3189
3190 list = user_var_list_for_type(GRETL_TYPE_MATRIX);
3191 g_list_foreach(list, add_user_var_icon, GINT_TO_POINTER(GRETL_OBJ_MATRIX));
3192 g_list_free(list);
3193
3194 list = user_var_list_for_type(GRETL_TYPE_BUNDLE);
3195 g_list_foreach(list, add_user_var_icon, GINT_TO_POINTER(GRETL_OBJ_BUNDLE));
3196 g_list_free(list);
3197
3198 return batch_pack_icons();
3199 }
3200
undisplay_icon(gui_obj * obj,gpointer p)3201 static void undisplay_icon (gui_obj *obj, gpointer p)
3202 {
3203 if (obj->icon && GTK_IS_WIDGET(obj->icon))
3204 gtk_container_remove(GTK_CONTAINER(icon_table), obj->icon);
3205 if (obj->label && GTK_IS_WIDGET(obj->label))
3206 gtk_container_remove(GTK_CONTAINER(icon_table), obj->label);
3207 }
3208
rearrange_icons(void)3209 static void rearrange_icons (void)
3210 {
3211 iconlist = g_list_first(iconlist);
3212 g_list_foreach(iconlist, (GFunc) undisplay_icon, NULL);
3213 batch_pack_icons();
3214 }
3215
catch_iconview_key(GtkWidget * w,GdkEventKey * key,gpointer p)3216 static gint catch_iconview_key (GtkWidget *w, GdkEventKey *key,
3217 gpointer p)
3218 {
3219 #ifdef OS_OSX
3220 if (key->keyval == GDK_w && cmd_key(key)) {
3221 gtk_widget_destroy(w);
3222 }
3223 #endif
3224 /* 'q' quits iconview */
3225 if (key->keyval == GDK_q) {
3226 gtk_widget_destroy(w);
3227 }
3228
3229 return FALSE;
3230 }
3231
mtab_item_set_sensitivity(gui_obj * obj)3232 static void mtab_item_set_sensitivity (gui_obj *obj)
3233 {
3234 SESSION_MODEL *model = obj->data;
3235 int added = in_model_table(model->ptr);
3236
3237 if (mtab_add_item != NULL) {
3238 gtk_widget_set_sensitive(mtab_add_item, !added);
3239 }
3240 }
3241
gpage_item_set_sensitivity(gui_obj * obj)3242 static void gpage_item_set_sensitivity (gui_obj *obj)
3243 {
3244 SESSION_GRAPH *graph = obj->data;
3245 int added = in_graph_page(graph->fname);
3246
3247 if (gpage_add_item != NULL) {
3248 gtk_widget_set_sensitive(gpage_add_item, !added);
3249 }
3250 }
3251
copy_item_set_sensitivity(gui_obj * obj)3252 static void copy_item_set_sensitivity (gui_obj *obj)
3253 {
3254 SESSION_GRAPH *graph = obj->data;
3255
3256 if (graph_copy_item != NULL) {
3257 gtk_widget_set_sensitive(graph_copy_item, !graph->has_datafile);
3258 }
3259 }
3260
3261
object_popup_show(gui_obj * obj,GdkEventButton * event)3262 static void object_popup_show (gui_obj *obj, GdkEventButton *event)
3263 {
3264 GtkWidget *w = NULL;
3265
3266 active_object = obj;
3267
3268 switch (obj->sort) {
3269 case GRETL_OBJ_EQN:
3270 w = model_popup;
3271 mtab_item_set_sensitivity(obj);
3272 break;
3273 case GRETL_OBJ_MODTAB:
3274 w = model_table_popup;
3275 break;
3276 case GRETL_OBJ_GPAGE:
3277 w = graph_page_popup;
3278 break;
3279 case GRETL_OBJ_VAR:
3280 case GRETL_OBJ_SYS:
3281 case GRETL_OBJ_TEXT:
3282 w = generic_popup;
3283 break;
3284 case GRETL_OBJ_GRAPH:
3285 case GRETL_OBJ_PLOT:
3286 gpage_item_set_sensitivity(obj);
3287 copy_item_set_sensitivity(obj);
3288 w = graph_popup;
3289 break;
3290 case GRETL_OBJ_DSET:
3291 w = data_popup;
3292 break;
3293 case GRETL_OBJ_SCALARS:
3294 w = scalars_popup;
3295 break;
3296 case GRETL_OBJ_INFO:
3297 w = info_popup;
3298 break;
3299 case GRETL_OBJ_MATRIX:
3300 w = matrix_popup;
3301 break;
3302 case GRETL_OBJ_BUNDLE:
3303 w = bundle_popup;
3304 break;
3305 default:
3306 break;
3307 }
3308
3309 gtk_menu_popup(GTK_MENU(w), NULL, NULL, NULL, NULL,
3310 event->button, event->time);
3311 }
3312
display_model_table_wrapper(void)3313 static void display_model_table_wrapper (void)
3314 {
3315 display_model_table(1);
3316 }
3317
graph_page_save_wrapper(void)3318 static void graph_page_save_wrapper (void)
3319 {
3320 if (graph_page_get_n_graphs() == 0) {
3321 warnbox(_("The graph page is empty"));
3322 } else {
3323 file_selector(SAVE_TEX, FSEL_DATA_NONE, NULL);
3324 }
3325 }
3326
session_icon_click(GtkWidget * icon,GdkEventButton * event,gpointer data)3327 static gboolean session_icon_click (GtkWidget *icon,
3328 GdkEventButton *event,
3329 gpointer data)
3330 {
3331 gui_obj *obj = (gui_obj *) data;
3332
3333 if (event->type == GDK_2BUTTON_PRESS) {
3334 switch (obj->sort) {
3335 case GRETL_OBJ_EQN:
3336 case GRETL_OBJ_VAR:
3337 case GRETL_OBJ_SYS:
3338 display_session_model(obj->data);
3339 break;
3340 case GRETL_OBJ_GRAPH:
3341 case GRETL_OBJ_PLOT:
3342 open_gui_graph(obj);
3343 break;
3344 case GRETL_OBJ_TEXT:
3345 open_gui_text(obj);
3346 break;
3347 case GRETL_OBJ_DSET:
3348 show_spreadsheet(SHEET_EDIT_DATASET);
3349 break;
3350 case GRETL_OBJ_SCALARS:
3351 edit_scalars();
3352 break;
3353 case GRETL_OBJ_MATRIX:
3354 open_matrix(obj);
3355 break;
3356 case GRETL_OBJ_BUNDLE:
3357 open_bundle(obj);
3358 break;
3359 case GRETL_OBJ_INFO:
3360 dataset_info();
3361 break;
3362 case GRETL_OBJ_NOTES:
3363 edit_session_notes();
3364 break;
3365 case GRETL_OBJ_MODTAB:
3366 display_model_table_wrapper();
3367 break;
3368 case GRETL_OBJ_GPAGE:
3369 display_graph_page(iconview);
3370 break;
3371 case GRETL_OBJ_CORR:
3372 do_menu_op(ALL_CORR, NULL, OPT_NONE, iconview);
3373 break;
3374 case GRETL_OBJ_STATS:
3375 do_menu_op(ALL_SUMMARY, NULL, OPT_NONE, iconview);
3376 break;
3377 }
3378 return TRUE;
3379 } else {
3380 if (right_click(event)) {
3381 if (obj->sort == GRETL_OBJ_EQN || obj->sort == GRETL_OBJ_GRAPH ||
3382 obj->sort == GRETL_OBJ_TEXT || obj->sort == GRETL_OBJ_DSET ||
3383 obj->sort == GRETL_OBJ_INFO || obj->sort == GRETL_OBJ_GPAGE ||
3384 obj->sort == GRETL_OBJ_PLOT || obj->sort == GRETL_OBJ_MODTAB ||
3385 obj->sort == GRETL_OBJ_VAR || obj->sort == GRETL_OBJ_SYS ||
3386 obj->sort == GRETL_OBJ_MATRIX || obj->sort == GRETL_OBJ_BUNDLE ||
3387 obj->sort == GRETL_OBJ_SCALARS) {
3388 object_popup_show(obj, event);
3389 }
3390 return TRUE;
3391 }
3392 }
3393
3394 return FALSE;
3395 }
3396
session_view_click(GtkWidget * widget,GdkEventButton * event,gpointer data)3397 static gboolean session_view_click (GtkWidget *widget,
3398 GdkEventButton *event,
3399 gpointer data)
3400 {
3401 if (!in_icon) {
3402 if (right_click(event)) {
3403 /* right-click on iconview background */
3404 gtk_menu_popup(GTK_MENU(global_popup), NULL, NULL, NULL, NULL,
3405 event->button, event->time);
3406 return TRUE;
3407 }
3408 }
3409
3410 return FALSE;
3411 }
3412
global_popup_callback(GtkWidget * widget,gpointer data)3413 static void global_popup_callback (GtkWidget *widget, gpointer data)
3414 {
3415 gchar *item = (gchar *) data;
3416
3417 if (!strcmp(item, _("Save session"))) {
3418 if (sessionfile[0]) {
3419 if (session.status & SESSION_CHANGED) {
3420 save_session(NULL);
3421 } else {
3422 mark_session_saved();
3423 }
3424 } else {
3425 file_selector(SAVE_SESSION, FSEL_DATA_NONE, NULL);
3426 }
3427 } else if (!strcmp(item, _("Arrange icons"))) {
3428 rearrange_icons();
3429 } else if (!strcmp(item, _("Add matrix..."))) {
3430 gui_new_matrix(iconview);
3431 } else if (!strcmp(item, _("Windows"))) {
3432 window_list_popup(widget, NULL, iconview);
3433 } else if (!strcmp(item, _("Close window"))) {
3434 gtk_widget_destroy(iconview);
3435 }
3436 }
3437
info_popup_callback(GtkWidget * widget,gpointer data)3438 static void info_popup_callback (GtkWidget *widget, gpointer data)
3439 {
3440 dataset_info();
3441 }
3442
matrix_popup_callback(GtkWidget * widget,gpointer data)3443 static void matrix_popup_callback (GtkWidget *widget, gpointer data)
3444 {
3445 gchar *item = (gchar *) data;
3446 gui_obj *obj = active_object;
3447 user_var *u = (user_var *) obj->data;
3448 const char *name = user_var_get_name(u);
3449 gretl_matrix *m;
3450
3451 if (!strcmp(item, _("View"))) {
3452 PRN *prn;
3453
3454 m = user_var_get_value(u);
3455 if (m != NULL && bufopen(&prn) == 0) {
3456 gretl_matrix_print_to_prn(m, name, prn);
3457 view_buffer(prn, 78, 400, name, PRINT, NULL);
3458 }
3459 } else if (!strcmp(item, _("Edit"))) {
3460 edit_user_matrix_by_name(name, iconview);
3461 } else if (!strcmp(item, _("Properties"))) {
3462 m = user_var_get_value(u);
3463 view_matrix_properties(m, name);
3464 } else if (!strcmp(item, _("Copy as CSV..."))) {
3465 m = user_var_get_value(u);
3466 if (gretl_is_null_matrix(m)) {
3467 warnbox("matrix is null");
3468 } else {
3469 matrix_to_clipboard_as_csv(m, iconview);
3470 }
3471 } else if (!strcmp(item, _("Rename"))) {
3472 rename_object_dialog(obj);
3473 } else if (!strcmp(item, _("Delete"))) {
3474 maybe_delete_session_object(obj);
3475 } else if (!strcmp(item, _("Copy"))) {
3476 copy_object_dialog(obj);
3477 }
3478 }
3479
bundle_popup_callback(GtkWidget * widget,gpointer data)3480 static void bundle_popup_callback (GtkWidget *widget, gpointer data)
3481 {
3482 gchar *item = (gchar *) data;
3483 gui_obj *obj = active_object;
3484
3485 if (!strcmp(item, _("View"))) {
3486 open_bundle(obj);
3487 } else if (!strcmp(item, _("Rename"))) {
3488 rename_object_dialog(obj);
3489 } else if (!strcmp(item, _("Delete"))) {
3490 maybe_delete_session_object(obj);
3491 }
3492 }
3493
data_popup_callback(GtkWidget * widget,gpointer data)3494 static void data_popup_callback (GtkWidget *widget, gpointer data)
3495 {
3496 gchar *item = (gchar *) data;
3497
3498 if (!strcmp(item, _("Edit"))) {
3499 show_spreadsheet(SHEET_EDIT_DATASET);
3500 } else if (!strcmp(item, _("Export as CSV..."))) {
3501 file_save(mdata, EXPORT_CSV);
3502 } else if (!strcmp(item, _("Copy as CSV..."))) {
3503 csv_to_clipboard(iconview);
3504 }
3505 }
3506
scalars_popup_callback(GtkWidget * widget,gpointer data)3507 static void scalars_popup_callback (GtkWidget *widget, gpointer data)
3508 {
3509 gchar *item = (gchar *) data;
3510
3511 if (!strcmp(item, _("Edit"))) {
3512 edit_scalars();
3513 } else if (!strcmp(item, _("Copy as CSV..."))) {
3514 scalars_to_clipboard_as_csv(iconview);
3515 }
3516 }
3517
object_get_window_title(gui_obj * obj)3518 static gchar *object_get_window_title (gui_obj *obj)
3519 {
3520 gchar *title = NULL;
3521
3522 if (obj != NULL) {
3523 title = g_strdup_printf("gretl: %s", obj->name);
3524 }
3525
3526 return title;
3527 }
3528
object_popup_callback(GtkWidget * widget,gpointer data)3529 static void object_popup_callback (GtkWidget *widget, gpointer data)
3530 {
3531 gchar *item = (gchar *) data;
3532 gui_obj *obj = active_object;
3533
3534 if (!strcmp(item, _("Display"))) {
3535 if (obj->sort == GRETL_OBJ_EQN ||
3536 obj->sort == GRETL_OBJ_VAR ||
3537 obj->sort == GRETL_OBJ_SYS) {
3538 display_session_model(obj->data);
3539 } else if (obj->sort == GRETL_OBJ_TEXT) {
3540 open_gui_text(obj);
3541 } else if (obj->sort == GRETL_OBJ_MODTAB) {
3542 display_model_table_wrapper();
3543 } else if (obj->sort == GRETL_OBJ_GPAGE) {
3544 display_graph_page(iconview);
3545 } else if (obj->sort == GRETL_OBJ_GRAPH ||
3546 obj->sort == GRETL_OBJ_PLOT) {
3547 open_gui_graph(obj);
3548 }
3549 } else if (!strcmp(item, _("Edit plot commands"))) {
3550 if (obj->sort == GRETL_OBJ_GRAPH || obj->sort == GRETL_OBJ_PLOT) {
3551 SESSION_GRAPH *graph = (SESSION_GRAPH *) obj->data;
3552 char fullname[MAXLEN];
3553 gchar *title;
3554 windata_t *vwin;
3555 int err;
3556
3557 err = gretl_chdir(gretl_dotdir());
3558 if (err) {
3559 gui_errmsg(err);
3560 } else {
3561 session_file_make_path(fullname, graph->fname);
3562 /* the following handles error message if needed */
3563 err = remove_png_term_from_plot_by_name(fullname);
3564 }
3565 if (!err) {
3566 title = object_get_window_title(obj);
3567 vwin = view_file_with_title(fullname, 1, 0, 78, 400,
3568 EDIT_GP, title);
3569 g_free(title);
3570 /* add flag so we can mark the session as modified
3571 if the plot file is changed */
3572 vwin->flags |= VWIN_SESSION_GRAPH;
3573 if (graph->has_datafile) {
3574 vwin->data = graph;
3575 }
3576 }
3577 }
3578 } else if (!strcmp(item, _("Add to graph page"))) {
3579 if (obj->sort == GRETL_OBJ_GRAPH || obj->sort == GRETL_OBJ_PLOT) {
3580 SESSION_GRAPH *graph = (SESSION_GRAPH *) obj->data;
3581
3582 if (!in_graph_page(graph->fname)) {
3583 graph_page_add_file(graph->fname);
3584 }
3585 }
3586 } else if (!strcmp(item, _("Rename"))) {
3587 rename_object_dialog(obj);
3588 } else if (!strcmp(item, _("Delete"))) {
3589 /* note: "Delete" = "Clear" in some translations */
3590 if (obj->sort == GRETL_OBJ_MODTAB) {
3591 clear_model_table(0, NULL);
3592 } else if (obj->sort == GRETL_OBJ_GPAGE) {
3593 clear_graph_page(0);
3594 } else {
3595 maybe_delete_session_object(obj);
3596 }
3597 } else if (!strcmp(item, _("Add to model table"))) {
3598 if (obj->sort == GRETL_OBJ_EQN) {
3599 SESSION_MODEL *mod = (SESSION_MODEL *) obj->data;
3600
3601 add_to_model_table(mod->ptr, MODEL_ADD_FROM_MENU, 0, NULL);
3602 }
3603 } else if (!strcmp(item, _("Clear"))) {
3604 if (obj->sort == GRETL_OBJ_MODTAB) {
3605 clear_model_table(0, NULL);
3606 } else if (obj->sort == GRETL_OBJ_GPAGE) {
3607 clear_graph_page(0);
3608 }
3609 } else if (!strcmp(item, _("Help"))) {
3610 if (obj->sort == GRETL_OBJ_MODTAB) {
3611 show_gui_help(MODELTAB);
3612 } else if (obj->sort == GRETL_OBJ_GPAGE) {
3613 show_gui_help(GRAPHPG);
3614 }
3615 } else if (!strcmp(item, _("Save as TeX..."))) {
3616 if (obj->sort == GRETL_OBJ_GPAGE) {
3617 graph_page_save_wrapper();
3618 }
3619 } else if (!strcmp(item, _("Copy"))) {
3620 if (obj->sort == GRETL_OBJ_GRAPH || obj->sort == GRETL_OBJ_PLOT) {
3621 copy_object_dialog(obj);
3622 }
3623 }
3624 }
3625
icon_entered(GtkWidget * icon,GdkEventCrossing * event,gui_obj * obj)3626 static gboolean icon_entered (GtkWidget *icon, GdkEventCrossing *event,
3627 gui_obj *obj)
3628 {
3629 #if GTK_MAJOR_VERSION == 3
3630 gtk_widget_set_state_flags(icon, GTK_STATE_FLAG_PRELIGHT, FALSE);
3631 #else
3632 gtk_widget_set_state(icon, GTK_STATE_SELECTED);
3633 #endif
3634 in_icon = 1;
3635
3636 return FALSE;
3637 }
3638
icon_left(GtkWidget * icon,GdkEventCrossing * event,gui_obj * obj)3639 static gboolean icon_left (GtkWidget *icon, GdkEventCrossing *event,
3640 gui_obj *obj)
3641 {
3642 gtk_widget_set_state(icon, GTK_STATE_NORMAL);
3643 in_icon = 0;
3644
3645 return FALSE;
3646 }
3647
3648 static MODEL *drag_model_src;
3649
3650 static void
session_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,gpointer p)3651 session_data_received (GtkWidget *widget,
3652 GdkDragContext *context,
3653 gint x,
3654 gint y,
3655 GtkSelectionData *data,
3656 guint info,
3657 guint time,
3658 gpointer p)
3659 {
3660 const guchar *seldata = NULL;
3661
3662 if (data != NULL) {
3663 seldata = gtk_selection_data_get_data(data);
3664 }
3665
3666 if (info == GRETL_MODEL_PTR && seldata != NULL) {
3667 MODEL *pmod = drag_model_src;
3668
3669 if (pmod != NULL) {
3670 add_to_model_table(pmod, MODEL_ADD_BY_DRAG, 0, NULL);
3671 drag_model_src = NULL;
3672 }
3673 } else if (info == GRETL_GRAPH_FILE && seldata != NULL) {
3674 gchar *fname = (gchar *) seldata;
3675
3676 if (fname != NULL) {
3677 graph_page_add_file(fname);
3678 }
3679 }
3680 }
3681
session_drag_setup(gui_obj * obj)3682 static void session_drag_setup (gui_obj *obj)
3683 {
3684 GtkWidget *w = GTK_WIDGET(obj->icon);
3685 GtkTargetEntry *targ;
3686
3687 if (obj->sort == GRETL_OBJ_MODTAB) {
3688 targ = &gretl_drag_targets[GRETL_MODEL_PTR];
3689 } else {
3690 targ = &gretl_drag_targets[GRETL_GRAPH_FILE];
3691 }
3692
3693 gtk_drag_dest_set(w,
3694 GTK_DEST_DEFAULT_ALL,
3695 targ, 1,
3696 GDK_ACTION_COPY);
3697
3698 g_signal_connect(G_OBJECT(w), "drag-data-received",
3699 G_CALLBACK(session_data_received),
3700 NULL);
3701 }
3702
drag_graph(GtkWidget * w,GdkDragContext * context,GtkSelectionData * sel,guint info,guint t,SESSION_GRAPH * graph)3703 static void drag_graph (GtkWidget *w, GdkDragContext *context,
3704 GtkSelectionData *sel, guint info, guint t,
3705 SESSION_GRAPH *graph)
3706 {
3707 gtk_selection_data_set(sel, GDK_SELECTION_TYPE_STRING, 8,
3708 (const guchar *) graph->fname,
3709 strlen(graph->fname));
3710 }
3711
graph_drag_connect(GtkWidget * w,SESSION_GRAPH * graph)3712 static void graph_drag_connect (GtkWidget *w, SESSION_GRAPH *graph)
3713 {
3714 gtk_drag_source_set(w, GDK_BUTTON1_MASK,
3715 &gretl_drag_targets[GRETL_GRAPH_FILE],
3716 1, GDK_ACTION_COPY);
3717 g_signal_connect(G_OBJECT(w), "drag-data-get",
3718 G_CALLBACK(drag_graph), graph);
3719 }
3720
drag_model(GtkWidget * w,GdkDragContext * context,GtkSelectionData * sel,guint info,guint t,SESSION_MODEL * mod)3721 static void drag_model (GtkWidget *w, GdkDragContext *context,
3722 GtkSelectionData *sel, guint info, guint t,
3723 SESSION_MODEL *mod)
3724 {
3725 drag_model_src = mod->ptr;
3726 gtk_selection_data_set(sel, GDK_SELECTION_TYPE_STRING, 8,
3727 (const guchar *) &mod->ptr,
3728 sizeof mod->ptr);
3729 }
3730
model_drag_connect(GtkWidget * w,SESSION_MODEL * mod)3731 static void model_drag_connect (GtkWidget *w, SESSION_MODEL *mod)
3732 {
3733 gtk_drag_source_set(w, GDK_BUTTON1_MASK,
3734 &gretl_drag_targets[GRETL_MODEL_PTR],
3735 1, GDK_ACTION_COPY);
3736 g_signal_connect(G_OBJECT(w), "drag-data-get",
3737 G_CALLBACK(drag_model), mod);
3738 }
3739
3740 #define WANT_TOOLTIP(t) (t == GRETL_OBJ_EQN || \
3741 t == GRETL_OBJ_GRAPH || \
3742 t == GRETL_OBJ_PLOT)
3743
session_add_icon(gpointer data,int sort,int mode)3744 static gui_obj *session_add_icon (gpointer data, int sort, int mode)
3745 {
3746 gui_obj *obj;
3747 gchar *name = NULL;
3748 SESSION_GRAPH *graph = NULL;
3749 SESSION_MODEL *mod = NULL;
3750 SESSION_TEXT *text = NULL;
3751 int icon_named = 0;
3752
3753 switch (sort) {
3754 case GRETL_OBJ_EQN:
3755 case GRETL_OBJ_VAR:
3756 case GRETL_OBJ_SYS:
3757 mod = (SESSION_MODEL *) data;
3758 name = g_strdup(mod->name);
3759 break;
3760 case GRETL_OBJ_PLOT:
3761 case GRETL_OBJ_GRAPH:
3762 graph = (SESSION_GRAPH *) data;
3763 name = g_strdup(graph->name);
3764 break;
3765 case GRETL_OBJ_TEXT:
3766 text = (SESSION_TEXT *) data;
3767 name = g_strdup(text->name);
3768 break;
3769 case GRETL_OBJ_DSET:
3770 name = g_strdup(_("Data set"));
3771 break;
3772 case GRETL_OBJ_SCALARS:
3773 name = g_strdup(_("Scalars"));
3774 break;
3775 case GRETL_OBJ_INFO:
3776 name = g_strdup(_("Data info"));
3777 break;
3778 case GRETL_OBJ_NOTES:
3779 name = g_strdup(_("Notes"));
3780 break;
3781 case GRETL_OBJ_CORR:
3782 name = g_strdup(_("Correlations"));
3783 break;
3784 case GRETL_OBJ_STATS:
3785 name = g_strdup(_("Summary"));
3786 break;
3787 case GRETL_OBJ_MODTAB:
3788 name = g_strdup(_("Model table"));
3789 break;
3790 case GRETL_OBJ_GPAGE:
3791 name = g_strdup(_("Graph page"));
3792 break;
3793 case GRETL_OBJ_MATRIX:
3794 case GRETL_OBJ_BUNDLE:
3795 name = g_strdup(user_var_get_name((user_var *) data));
3796 break;
3797 default:
3798 break;
3799 }
3800
3801 if (name == NULL) {
3802 fprintf(stderr, "session_add_icon: NULL name for object of sort %d\n",
3803 sort);
3804 return NULL;
3805 }
3806
3807 obj = gui_object_new(name, sort, data);
3808
3809 /* full-length object name as tooltip */
3810 if (g_utf8_strlen(name, -1) > SHOWNAMELEN) {
3811 gretl_tooltips_add(GTK_WIDGET(obj->icon), name);
3812 icon_named = 1;
3813 }
3814
3815 /* set up for drag and drop */
3816 if (sort == GRETL_OBJ_EQN) {
3817 model_drag_connect(obj->icon, obj->data);
3818 } else if (sort == GRETL_OBJ_GRAPH) {
3819 graph_drag_connect(obj->icon, obj->data);
3820 }
3821
3822 /* second try at adding a tooltip */
3823 if (WANT_TOOLTIP(sort) && !icon_named) {
3824 char *str = NULL;
3825
3826 if (sort == GRETL_OBJ_EQN) {
3827 MODEL *pmod = (MODEL *) mod->ptr;
3828
3829 str = model_cmd_str(pmod);
3830 } else if (sort == GRETL_OBJ_GRAPH ||
3831 sort == GRETL_OBJ_PLOT) {
3832 str = graph_str(graph);
3833 }
3834 if (str != NULL) {
3835 gretl_tooltips_add(GTK_WIDGET(obj->icon), str);
3836 free(str);
3837 }
3838 }
3839
3840 if (sort == GRETL_OBJ_DSET) {
3841 obj->data = datafile;
3842 }
3843
3844 if (mode == ICON_ADD_SINGLE) {
3845 pack_single_icon(obj);
3846 } else if (mode == ICON_ADD_BATCH) {
3847 iconlist = g_list_append(iconlist, obj);
3848 }
3849
3850 return obj;
3851 }
3852
create_pop_item(GtkWidget * popup,char * str,GtkCallback callback)3853 static GtkWidget *create_pop_item (GtkWidget *popup, char *str,
3854 GtkCallback callback)
3855 {
3856 GtkWidget *item;
3857
3858 item = gtk_menu_item_new_with_label(str);
3859 g_signal_connect(G_OBJECT(item), "activate",
3860 G_CALLBACK(callback),
3861 str);
3862 gtk_widget_show(item);
3863 gtk_menu_shell_append(GTK_MENU_SHELL(popup), item);
3864
3865 if (!strcmp(str, _("Save session"))) {
3866 save_item = item;
3867 if (session.status == 0) {
3868 gtk_widget_set_sensitive(item, FALSE);
3869 }
3870 }
3871
3872 return item;
3873 }
3874
session_build_popups(void)3875 static void session_build_popups (void)
3876 {
3877 GtkWidget *item;
3878 size_t i, n;
3879
3880 mtab_add_item = NULL;
3881 gpage_add_item = NULL;
3882 graph_copy_item = NULL;
3883
3884 if (global_popup == NULL) {
3885 global_popup = gtk_menu_new();
3886 n = G_N_ELEMENTS(global_items);
3887 for (i=0; i<n; i++) {
3888 create_pop_item(global_popup, _(global_items[i]),
3889 global_popup_callback);
3890 }
3891 }
3892
3893 if (model_popup == NULL) {
3894 model_popup = gtk_menu_new();
3895 n = G_N_ELEMENTS(model_items);
3896 for (i=0; i<n; i++) {
3897 item = create_pop_item(model_popup, _(model_items[i]),
3898 object_popup_callback);
3899 if (i == ADD_TO_MTAB_IDX) {
3900 mtab_add_item = item;
3901 }
3902 }
3903 }
3904
3905 if (model_table_popup == NULL) {
3906 model_table_popup = gtk_menu_new();
3907 n = G_N_ELEMENTS(model_table_items);
3908 for (i=0; i<n; i++) {
3909 create_pop_item(model_table_popup, _(model_table_items[i]),
3910 object_popup_callback);
3911 }
3912 }
3913
3914 if (generic_popup == NULL) {
3915 generic_popup = gtk_menu_new();
3916 n = G_N_ELEMENTS(generic_items);
3917 for (i=0; i<n; i++) {
3918 create_pop_item(generic_popup, _(generic_items[i]),
3919 object_popup_callback);
3920 }
3921 }
3922
3923 if (graph_popup == NULL) {
3924 graph_popup = gtk_menu_new();
3925 n = G_N_ELEMENTS(graph_items);
3926 for (i=0; i<n; i++) {
3927 item = create_pop_item(graph_popup, _(graph_items[i]),
3928 object_popup_callback);
3929 if (i == ADD_TO_GPAGE_IDX) {
3930 gpage_add_item = item;
3931 } else if (i == GRAPH_COPY_IDX) {
3932 graph_copy_item = item;
3933 }
3934 }
3935 }
3936
3937 if (graph_page_popup == NULL) {
3938 graph_page_popup = gtk_menu_new();
3939 n = G_N_ELEMENTS(graph_page_items);
3940 for (i=0; i<n; i++) {
3941 create_pop_item(graph_page_popup, _(graph_page_items[i]),
3942 object_popup_callback);
3943 }
3944 }
3945
3946 if (data_popup == NULL) {
3947 data_popup = gtk_menu_new();
3948 n = G_N_ELEMENTS(dataset_items);
3949 for (i=0; i<n; i++) {
3950 create_pop_item(data_popup, _(dataset_items[i]),
3951 data_popup_callback);
3952 }
3953 }
3954
3955 if (scalars_popup == NULL) {
3956 scalars_popup = gtk_menu_new();
3957 n = G_N_ELEMENTS(scalars_items);
3958 for (i=0; i<n; i++) {
3959 create_pop_item(scalars_popup, _(scalars_items[i]),
3960 scalars_popup_callback);
3961 }
3962 }
3963
3964 if (info_popup == NULL) {
3965 info_popup = gtk_menu_new();
3966 n = G_N_ELEMENTS(info_items);
3967 for (i=0; i<n; i++) {
3968 create_pop_item(info_popup, _(info_items[i]),
3969 info_popup_callback);
3970 }
3971 }
3972
3973 if (matrix_popup == NULL) {
3974 matrix_popup = gtk_menu_new();
3975 n = G_N_ELEMENTS(matrix_items);
3976 for (i=0; i<n; i++) {
3977 create_pop_item(matrix_popup, _(matrix_items[i]),
3978 matrix_popup_callback);
3979 }
3980 }
3981
3982 if (bundle_popup == NULL) {
3983 bundle_popup = gtk_menu_new();
3984 n = G_N_ELEMENTS(bundle_items);
3985 for (i=0; i<n; i++) {
3986 create_pop_item(bundle_popup, _(bundle_items[i]),
3987 bundle_popup_callback);
3988 }
3989 }
3990 }
3991
3992 static gboolean
iconview_resize_callback(GtkWidget * w,GdkEventConfigure * e,gpointer p)3993 iconview_resize_callback (GtkWidget *w, GdkEventConfigure *e, gpointer p)
3994 {
3995 if (e->width != iconview_width) {
3996 if (iconview_width > 0) {
3997 int cols = e->width / 100;
3998
3999 if (cols >= ICONVIEW_MIN_COLS && cols != iconview_cols) {
4000 iconview_cols = cols;
4001 rearrange_icons();
4002 }
4003 }
4004 iconview_width = e->width;
4005 }
4006
4007 return FALSE;
4008 }
4009
view_session(void)4010 void view_session (void)
4011 {
4012 GtkWidget *ebox, *scroller;
4013 gchar *title;
4014 int hmax = get_screen_height() / 2;
4015 int hmin = 280;
4016 int height;
4017
4018 if (iconview != NULL) {
4019 gtk_window_present(GTK_WINDOW(iconview));
4020 return;
4021 }
4022
4023 session_view_init();
4024
4025 iconview = gretl_gtk_window();
4026 gtk_window_set_position(GTK_WINDOW(iconview), GTK_WIN_POS_MOUSE);
4027 title = g_strdup_printf("gretl: %s", _("icon view"));
4028 gtk_window_set_title(GTK_WINDOW(iconview), title);
4029 g_free(title);
4030
4031 gtk_container_set_border_width(GTK_CONTAINER(iconview), 0);
4032 g_signal_connect(G_OBJECT(iconview), "destroy",
4033 G_CALLBACK(session_view_free), NULL);
4034
4035 session_build_popups();
4036
4037 ebox = gtk_event_box_new();
4038 gtk_container_set_border_width(GTK_CONTAINER(ebox), 5);
4039 gtk_container_add(GTK_CONTAINER(iconview), ebox);
4040 g_signal_connect(G_OBJECT(ebox), "button-press-event",
4041 G_CALLBACK(session_view_click), NULL);
4042
4043 scroller = gtk_scrolled_window_new(NULL, NULL);
4044 gtk_container_set_border_width(GTK_CONTAINER(scroller), 0);
4045 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
4046 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
4047 gtk_container_add(GTK_CONTAINER(ebox), scroller);
4048
4049 icon_table = gtk_table_new(2, ICONVIEW_MIN_COLS, FALSE);
4050 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroller),
4051 icon_table);
4052
4053 height = 90 * add_all_icons();
4054 if (height < hmin) {
4055 height = hmin;
4056 } else if (height > hmax) {
4057 height = hmax;
4058 }
4059 gtk_window_set_default_size(GTK_WINDOW(iconview), 440, height);
4060
4061 window_list_add(iconview, OPEN_SESSION);
4062 g_signal_connect(G_OBJECT(iconview), "key-press-event",
4063 G_CALLBACK(catch_iconview_key), NULL);
4064 g_signal_connect(G_OBJECT(iconview), "configure-event",
4065 G_CALLBACK(iconview_resize_callback), NULL);
4066
4067 gtk_widget_show_all(iconview);
4068
4069 gtk_container_foreach(GTK_CONTAINER(scroller),
4070 (GtkCallback) white_bg_style,
4071 NULL);
4072
4073 gtk_widget_set_can_focus(icon_table, TRUE);
4074 gtk_widget_grab_focus(icon_table);
4075 }
4076
4077 static int view_session_deferred;
4078
auto_view_session(void)4079 static void auto_view_session (void)
4080 {
4081 if (waiting_for_output()) {
4082 view_session_deferred = 1;
4083 } else {
4084 view_session();
4085 }
4086 }
4087
maybe_view_session(void)4088 void maybe_view_session (void)
4089 {
4090 if (view_session_deferred) {
4091 view_session_deferred = 0;
4092 view_session();
4093 }
4094 }
4095
make_short_label_string(char * targ,const char * src)4096 static void make_short_label_string (char *targ, const char *src)
4097 {
4098 if (g_utf8_strlen(src, -1) > SHOWNAMELEN) {
4099 g_utf8_strncpy(targ, src, SHOWNAMELEN - 3);
4100 strcat(targ, "...");
4101 } else {
4102 strcpy(targ, src);
4103 }
4104 }
4105
4106 #ifdef REMEDY_LABELS
4107
rewrite_icon_label(const char * s)4108 static gchar *rewrite_icon_label (const char *s)
4109 {
4110 gchar *ret = NULL;
4111 int i, l1, l2, ld, ldmin = 100;
4112 int pos = 0;
4113
4114 for (i=0; s[i] != '\0'; i++) {
4115 if (s[i] == ' ') {
4116 l1 = g_utf8_strlen(s, i);
4117 l2 = g_utf8_strlen(s + i + 1, -1);
4118 ld = abs(l1 - l2);
4119 if (ld < ldmin) {
4120 ldmin = ld;
4121 pos = i;
4122 }
4123 }
4124 }
4125
4126 if (pos > 0) {
4127 ret = g_strdup(s);
4128 ret[pos] = '\n';
4129 }
4130
4131 return ret;
4132 }
4133
4134 #endif
4135
create_gobj_icon(gui_obj * obj,const char ** xpm)4136 static void create_gobj_icon (gui_obj *obj, const char **xpm)
4137 {
4138 GdkPixbuf *pbuf;
4139 GtkWidget *image;
4140
4141 pbuf = gdk_pixbuf_new_from_xpm_data(xpm);
4142
4143 obj->icon = gtk_event_box_new();
4144 gtk_widget_set_size_request(obj->icon, 44, 36);
4145 obj->label = NULL;
4146
4147 image = gtk_image_new_from_pixbuf(pbuf);
4148 g_object_unref(G_OBJECT(pbuf));
4149
4150 gtk_container_add(GTK_CONTAINER(obj->icon), image);
4151 gtk_widget_show(image);
4152
4153 if (obj->sort == GRETL_OBJ_MODTAB || obj->sort == GRETL_OBJ_GPAGE) {
4154 session_drag_setup(obj);
4155 }
4156
4157 #ifdef REMEDY_LABELS
4158 if (g_utf8_strlen(obj->name, -1) > 12 && strchr(obj->name, ' ')) {
4159 gchar *tmp = rewrite_icon_label(obj->name);
4160
4161 if (tmp != NULL) {
4162 obj->label = gtk_label_new(tmp);
4163 g_free(tmp);
4164 }
4165 }
4166 #endif
4167 if (obj->label == NULL) {
4168 obj->label = gtk_label_new(obj->name);
4169 }
4170 gtk_label_set_width_chars(GTK_LABEL(obj->label), 12);
4171 gtk_label_set_max_width_chars(GTK_LABEL(obj->label), SHOWNAMELEN);
4172 gtk_label_set_line_wrap(GTK_LABEL(obj->label), TRUE);
4173 gtk_label_set_justify(GTK_LABEL(obj->label), GTK_JUSTIFY_CENTER);
4174
4175 g_object_ref(obj->icon);
4176 g_object_ref(obj->label);
4177
4178 g_signal_connect(G_OBJECT(obj->icon), "button-press-event",
4179 G_CALLBACK(session_icon_click), obj);
4180 g_signal_connect(G_OBJECT(obj->icon), "enter-notify-event",
4181 G_CALLBACK(icon_entered), obj);
4182 g_signal_connect(G_OBJECT(obj->icon), "leave-notify-event",
4183 G_CALLBACK(icon_left), obj);
4184 }
4185
gui_object_new(gchar * name,int sort,gpointer data)4186 static gui_obj *gui_object_new (gchar *name, int sort, gpointer data)
4187 {
4188 gui_obj *obj;
4189 char **xpm = NULL;
4190
4191 obj = mymalloc(sizeof *obj);
4192 if (obj == NULL) {
4193 return NULL;
4194 }
4195
4196 obj->name = name;
4197 obj->sort = sort;
4198 obj->data = data;
4199
4200 #if SESSION_DEBUG
4201 fprintf(stderr, "Allocated obj at %p (%s)\n", (void *) obj, obj->name);
4202 #endif
4203
4204 switch (sort) {
4205 case GRETL_OBJ_EQN:
4206 case GRETL_OBJ_VAR:
4207 case GRETL_OBJ_SYS: xpm = model_xpm; break;
4208 case GRETL_OBJ_PLOT: xpm = boxplot_xpm; break;
4209 case GRETL_OBJ_GRAPH: xpm = gnuplot_xpm; break;
4210 case GRETL_OBJ_DSET: xpm = dot_sc_xpm; break;
4211 case GRETL_OBJ_SCALARS: xpm = dot_sc_xpm; break;
4212 case GRETL_OBJ_INFO: xpm = xfm_info_xpm; break;
4213 case GRETL_OBJ_TEXT:
4214 case GRETL_OBJ_NOTES: xpm = text_xpm; break;
4215 case GRETL_OBJ_CORR: xpm = rhohat_xpm; break;
4216 case GRETL_OBJ_STATS: xpm = summary_xpm; break;
4217 case GRETL_OBJ_MODTAB: xpm = model_table_xpm; break;
4218 case GRETL_OBJ_GPAGE: xpm = graph_page_xpm; break;
4219 case GRETL_OBJ_MATRIX: xpm = matrix_xpm; break;
4220 case GRETL_OBJ_BUNDLE: xpm = bundle_xpm; break;
4221 default: break;
4222 }
4223
4224 create_gobj_icon(obj, (const char **) xpm);
4225
4226 return obj;
4227 }
4228
real_open_session_graph(SESSION_GRAPH * graph)4229 static void real_open_session_graph (SESSION_GRAPH *graph)
4230 {
4231 GtkWidget *plotwin = get_window_for_plot(graph);
4232
4233 if (plotwin != NULL) {
4234 gtk_window_present(GTK_WINDOW(plotwin));
4235 } else {
4236 char tmp[MAXLEN];
4237
4238 session_file_make_path(tmp, graph->fname);
4239 display_session_graph(tmp, graph->name, graph);
4240 }
4241 }
4242
open_gui_graph(gui_obj * obj)4243 static void open_gui_graph (gui_obj *obj)
4244 {
4245 real_open_session_graph((SESSION_GRAPH *) obj->data);
4246 }
4247
display_session_graph_by_data(void * p)4248 void display_session_graph_by_data (void *p)
4249 {
4250 real_open_session_graph((SESSION_GRAPH *) p);
4251 }
4252
session_graph_get_filename(void * p)4253 gchar *session_graph_get_filename (void *p)
4254 {
4255 if (p != NULL) {
4256 SESSION_GRAPH *graph = p;
4257 char tmp[MAXLEN];
4258
4259 session_file_make_path(tmp, graph->fname);
4260 return g_strdup(tmp);
4261 } else {
4262 return NULL;
4263 }
4264 }
4265
is_idempotent(const gretl_matrix * m,const gretl_matrix * evals)4266 static int is_idempotent (const gretl_matrix *m,
4267 const gretl_matrix *evals)
4268 {
4269 double tol = 1.0e-12;
4270
4271 if (evals != NULL) {
4272 int i;
4273 double x;
4274 for (i=0; i<m->rows; i++) {
4275 x = fabs(evals->val[i] * (1.0 - evals->val[i])) > tol;
4276 if (x > tol) {
4277 return 0;
4278 }
4279 }
4280 }
4281
4282 return gretl_matrix_is_idempotent(m, tol);
4283 }
4284
print_int_formatted(char * s,int k,PRN * prn)4285 static void print_int_formatted (char *s, int k, PRN *prn)
4286 {
4287 int len = 12, n = strlen(s) - g_utf8_strlen(s, -1);
4288 char fmt[24];
4289
4290 if (n > 0) {
4291 len += n;
4292 }
4293
4294 sprintf(fmt, "%%-%ds %%3d\n", len);
4295 pprintf(prn, fmt, s, k);
4296 }
4297
print_double_formatted(char * s,double x,PRN * prn)4298 static void print_double_formatted (char *s, double x, PRN *prn)
4299 {
4300 int len = 16, n = strlen(s) - g_utf8_strlen(s, -1);
4301 char fmt[24];
4302
4303 if (n > 0) {
4304 len += n;
4305 }
4306
4307 sprintf(fmt, "%%-%ds %%.8g\n", len);
4308 pprintf(prn, fmt, s, x);
4309 }
4310
4311 void
view_matrix_properties(const gretl_matrix * m,const char * name)4312 view_matrix_properties (const gretl_matrix *m, const char *name)
4313 {
4314 gretl_matrix *A = NULL;
4315 gretl_matrix *evals = NULL;
4316 gchar *title;
4317 PRN *prn;
4318 int s, err = 0;
4319
4320 if (m == NULL || bufopen(&prn)) {
4321 return;
4322 }
4323
4324 pprintf(prn, _("Properties of matrix %s"), (name != NULL)? name : "");
4325 pputs(prn, "\n\n");
4326
4327 if (m->rows == 0 || m->cols == 0) {
4328 pprintf(prn, _("Null matrix, %d x %d\n"), m->rows, m->cols);
4329 goto done;
4330 } else if (m->rows == 1 && m->cols == 1) {
4331 pprintf(prn, _("Scalar matrix, value %g\n"), m->val[0]);
4332 goto done;
4333 } else if (gretl_is_identity_matrix(m)) {
4334 pprintf(prn, _("Identity matrix, order %d\n"), m->rows);
4335 goto done;
4336 } else if (gretl_is_zero_matrix(m)) {
4337 pprintf(prn, _("Null matrix, %d x %d\n"), m->rows, m->cols);
4338 goto done;
4339 }
4340
4341 print_int_formatted(_("Rows"), m->rows, prn);
4342 print_int_formatted(_("Columns"), m->cols, prn);
4343 print_int_formatted(_("Rank"), gretl_matrix_rank(m, &err), prn);
4344
4345 s = gretl_matrix_get_structure(m);
4346
4347 if (s > 0) {
4348 pprintf(prn, "%s\n", _("Square"));
4349 }
4350
4351 if (s == GRETL_MATRIX_DIAGONAL) {
4352 pprintf(prn, "%s\n", _("Diagonal"));
4353 } else if (s == GRETL_MATRIX_LOWER_TRIANGULAR) {
4354 pprintf(prn, "%s\n", _("Lower triangular"));
4355 } else if (s == GRETL_MATRIX_UPPER_TRIANGULAR) {
4356 pprintf(prn, "%s\n", _("Upper triangular"));
4357 } else if (s == GRETL_MATRIX_SYMMETRIC) {
4358 pprintf(prn, "%s\n", _("Symmetric"));
4359 A = gretl_matrix_copy(m);
4360 if (A != NULL) {
4361 err = gretl_matrix_cholesky_decomp(A);
4362 if (!err) {
4363 pprintf(prn, "%s\n", _("Positive definite"));
4364 } else {
4365 pprintf(prn, "%s\n", _("Not positive definite"));
4366 }
4367 gretl_matrix_copy_values(A, m);
4368 err = 0;
4369 evals = gretl_symmetric_matrix_eigenvals(A, 0, &err);
4370 }
4371 }
4372
4373 if (s > 0 && (s != GRETL_MATRIX_SYMMETRIC || evals == NULL)) {
4374 evals = gretl_general_matrix_eigenvals(m, &err);
4375 }
4376
4377 if (s > 0) {
4378 if (is_idempotent(m, evals)) {
4379 pprintf(prn, "%s\n", _("Idempotent"));
4380 } else {
4381 pprintf(prn, "%s\n", _("Not idempotent"));
4382 }
4383 }
4384
4385 pputc(prn, '\n');
4386
4387 print_double_formatted(_("1-norm"), gretl_matrix_one_norm(m), prn);
4388 print_double_formatted(_("Infinity-norm"), gretl_matrix_infinity_norm(m), prn);
4389
4390 if (m->rows == m->cols) {
4391 double det;
4392
4393 print_double_formatted(_("Trace"), gretl_matrix_trace(m), prn);
4394 if (A == NULL) {
4395 A = gretl_matrix_copy(m);
4396 } else {
4397 gretl_matrix_copy_values(A, m);
4398 }
4399 if (A != NULL) {
4400 det = gretl_matrix_determinant(A, &err);
4401 if (!err) {
4402 print_double_formatted(_("Determinant"), det, prn);
4403 }
4404 }
4405 }
4406
4407 if (evals != NULL) {
4408 int i;
4409
4410 pprintf(prn, "\n%s:\n", _("Eigenvalues"));
4411
4412 for (i=0; i<m->rows; i++) {
4413 if (s != GRETL_MATRIX_SYMMETRIC) {
4414 pprintf(prn, " (%.8g, %.8g)\n", gretl_matrix_get(evals, i, 0),
4415 gretl_matrix_get(evals, i, 1));
4416 } else {
4417 pprintf(prn, " %.8g\n", evals->val[i]);
4418 }
4419 }
4420
4421 gretl_matrix_free(evals);
4422 }
4423
4424 if (A != NULL) {
4425 gretl_matrix_free(A);
4426 }
4427
4428 done:
4429
4430 title = gretl_window_title(name);
4431 view_buffer(prn, 78, 400, title, PRINT, NULL);
4432 g_free(title);
4433 }
4434