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 			 &notes_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