1 /*
2  *  gretl -- Gnu Regression, Econometrics and Time-series Library
3  *  Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "gretl.h"
21 #include "dlgutils.h"
22 #include "dialogs.h"
23 #include "ssheet.h"
24 #include "menustate.h"
25 #include "obsbutton.h"
26 #include "session.h"
27 #include "toolbar.h"
28 #include "datawiz.h"
29 
30 #include "gretl_panel.h"
31 
32 /* The code here answers to (1) the "/Data/Dataset structure" menu item
33    in the main gretl window; (2) finalize_data_open() in gui_utils.c;
34    and (3) the "/File/New data set" main-window menu item.
35 
36    In the first two cases we have a dataset loaded and we're offering
37    the user the chance to impose time-series or panel structure.
38 
39    In the third case the dataset will be empty (dataset->n = 0) and
40    we're determining both the size and the stucture of the dataset
41    the user wants to create.
42 */
43 
44 #define DWDEBUG 0
45 
46 #define PD_SPECIAL -1
47 
48 #define known_panel(p) (p->structure == STACKED_CROSS_SECTION || \
49                         p->structure == STACKED_TIME_SERIES)
50 
51 #define any_panel(p) (p->structure == STACKED_CROSS_SECTION || \
52                       p->structure == STACKED_TIME_SERIES || \
53                       p->structure == PANEL_UNKNOWN)
54 
55 #define time_series(p) (p->structure == TIME_SERIES || \
56                         p->structure == SPECIAL_TIME_SERIES)
57 
58 /* identifiers for steps in the process of setting
59    dataset structure */
60 enum {
61     DW_SET_TYPE = 0,
62     DW_TS_FREQUENCY,
63     DW_WEEKLY_SELECT,
64     DW_STARTING_OBS,
65     DW_PANEL_MODE,
66     DW_PANEL_SIZE,
67     DW_PANEL_VARS,
68     DW_CONFIRM
69 };
70 
71 enum {
72     DW_FORWARD = 0,
73     DW_BACK    = 1
74 };
75 
76 /* flags that may be set on the dataset options structure */
77 enum {
78     DW_CREATE     = 1 << 0,
79     DW_DROPMISS   = 1 << 1,
80     DW_N_PRIME    = 1 << 2,
81     DW_VLIST_DONE = 1 << 3,
82     DW_NP_DONE    = 1 << 4,
83     DW_NO_PANEL   = 1 << 5,
84     DW_SSHEET     = 1 << 6
85 };
86 
87 #define dw_n_is_prime(o) (o->flags & DW_N_PRIME)
88 #define dw_vlist_done(o) (o->flags & DW_VLIST_DONE)
89 
90 typedef struct dw_opts_ dw_opts;
91 
92 struct dw_opts_ {
93     gretlopt flags;      /* state bit-flags */
94     int n_radios;        /* number of radio-button options */
95     int deflt;           /* default setting for current radio variable */
96     int plf;             /* panel: least factor > 1 of # of observations */
97     int uid;             /* panel: ID number of "unit" variable */
98     int tid;             /* panel: ID number of "period" variable */
99     int *setvar;         /* pointer to variable currently being set */
100     int *extra;          /* additional pointer to int variable */
101     GtkWidget *pdspin;   /* used for setting custom time-series frequency */
102     GList *vlist;        /* panel: list of candidates for uid, tid */
103     GtkWidget *dspin[4]; /* dataset dimension setters (new dataset) */
104     int dvals[4];        /* dataset dimension values (new dataset) */
105 };
106 
wizcode_string(int code)107 static const char *wizcode_string (int code)
108 {
109     const char *titles[] = {
110 	N_("Structure of dataset"),
111 	N_("Time series frequency"),
112 	N_("Daily date to represent week"),
113 	N_("Starting observation"),
114 	N_("Panel data organization"),
115 	N_("Panel structure"),
116 	N_("Panel index variables"),
117 	N_("Confirm dataset structure")
118     };
119 
120     if (code <= DW_CONFIRM) {
121 	return titles[code];
122     } else {
123 	return "";
124     }
125 }
126 
127 static int translate_panel_vars (dw_opts *opts, int *uv, int *tv);
128 
129 /* Initialize the "dummy" DATASET structure @dwinfo, based
130    on the current data info. This will just be a cross-section
131    unless the user has decided to modify an already-structured
132    dataset under /Data/Dataset structure.
133 */
134 
dwinfo_init(DATASET * dwinfo)135 static void dwinfo_init (DATASET *dwinfo)
136 {
137     dwinfo->pd = dataset->pd;
138     dwinfo->structure = dataset->structure;
139 
140     dwinfo->n = dataset->n;
141     strcpy(dwinfo->stobs, dataset->stobs);
142     strcpy(dwinfo->endobs, dataset->endobs);
143     dwinfo->sd0 = dataset->sd0;
144 
145 #if DWDEBUG
146     fprintf(stderr, "dwinfo_init:\n"
147 	    " pd=%d, structure=%d, sd0=%g, stobs='%s', endobs='%s'\n",
148 	    dwinfo->pd, dwinfo->structure, dwinfo->sd0,
149 	    dwinfo->stobs, dwinfo->endobs);
150 #endif
151 }
152 
153 /* For the case where the structure wizard is being used
154    to create a new dataset, and the user has chosen to type
155    in some values.
156 */
157 
prep_spreadsheet(GtkWidget * widget,dialog_t * dlg)158 static void prep_spreadsheet (GtkWidget *widget, dialog_t *dlg)
159 {
160     GtkWidget *parent = edit_dialog_get_window(dlg);
161     const gchar *buf = edit_dialog_get_text(dlg);
162     int t;
163 
164     if (buf == NULL || gui_validate_varname(buf,
165 					    GRETL_TYPE_SERIES,
166 					    parent)) {
167 	edit_dialog_reset(dlg);
168 	return;
169     }
170 
171     dataset->varname[1][0] = '\0';
172     strncat(dataset->varname[1], buf, VNAMELEN - 1);
173     edit_dialog_close(dlg);
174 
175     /* blank out the auto "index" variable */
176     for (t=0; t<dataset->n; t++) {
177 	dataset->Z[1][t] = NADBL;
178     }
179     series_set_label(dataset, 1, "");
180 
181     show_spreadsheet(SHEET_NEW_DATASET);
182 }
183 
maybe_start_editing(void)184 static void maybe_start_editing (void)
185 {
186     int cancel = 0;
187     gchar *msg;
188 
189     msg = g_strdup_printf(_("Enter name for first variable\n"
190 			    "(max. %d characters)"),
191 			  VNAMELEN - 1);
192 
193     blocking_edit_dialog(CREATE_DATASET, _("gretl: name variable"),
194 			 msg, NULL, prep_spreadsheet, NULL,
195 			 VARCLICK_NONE, NULL, &cancel);
196     g_free(msg);
197 
198     if (cancel) {
199 	/* accept the default blank dataset */
200 	register_data(NULLDATA_STARTED);
201     }
202 }
203 
204 /* for balanced panel checking */
205 
least_factor(int n)206 static int least_factor (int n)
207 {
208     int flim = n;
209     int prime = 1;
210     int factor;
211 
212     if (n % 2 == 0) {
213 	return 2;
214     }
215 
216     for (factor = 3; factor < flim; factor += 2) {
217 	if (n % factor == 0) {
218 	    prime = 0;
219 	    break;
220 	} else {
221 	    flim = n / factor;
222 	}
223     }
224 
225 #if DWDEBUG
226     fprintf(stderr, "least factor: prime = %d, factor = %d\n",
227 	    prime, factor);
228 #endif
229 
230     return (prime)? 1 : factor;
231 }
232 
233 /* figure out if the dataset contains a prime number of
234    observations */
235 
eval_n_is_prime(dw_opts * opts)236 static void eval_n_is_prime (dw_opts *opts)
237 {
238     if (opts->flags & DW_NP_DONE) {
239 	return;
240     }
241 
242     opts->plf = least_factor(dataset->n);
243 
244     if (opts->plf == 1) {
245 	opts->flags |= DW_N_PRIME;
246     } else {
247 	opts->flags &= ~DW_N_PRIME;
248     }
249 
250     opts->flags |= DW_NP_DONE;
251 }
252 
maybe_unrestrict_dataset(void)253 static void maybe_unrestrict_dataset (void)
254 {
255     if (complex_subsampled()) {
256 	maybe_free_full_dataset(dataset);
257 	if (dataset->t1 == 0 &&
258 	    dataset->t2 == dataset->n - 1) {
259 	    restore_sample_state(FALSE);
260 	}
261     }
262 }
263 
264 /* respond to the "Apply" button in the wizard */
265 
dwiz_make_changes(DATASET * dwinfo,dw_opts * opts,GtkWidget * dlg)266 static int dwiz_make_changes (DATASET *dwinfo, dw_opts *opts,
267 			      GtkWidget *dlg)
268 {
269     gchar *setobs_cmd = NULL;
270     gretlopt opt = OPT_NONE;
271     int delmiss = (opts->flags & DW_DROPMISS);
272     int delete_markers = 0;
273     int err = 0;
274 
275 #if DWDEBUG
276     fprintf(stderr, "dwiz_make_changes\n");
277 #endif
278 
279     /* preliminaries */
280     if (time_series(dwinfo)) {
281 	ntolabel(dwinfo->stobs, dwinfo->t1, dwinfo);
282     } else if (known_panel(dwinfo)) {
283 	if (!dataset_is_panel(dataset)) {
284 	    /* Turning a subset of a non-panel dataset into a panel:
285 	       this change will be irreversible */
286 	    maybe_unrestrict_dataset();
287 	}
288     }
289 
290     /* special: reorganizing dataset based on panel index vars */
291     if (dwinfo->structure == PANEL_UNKNOWN) {
292 	int uv, tv;
293 
294 	err = translate_panel_vars(opts, &uv, &tv);
295 	if (!err) {
296 	    err = set_panel_structure_from_vars(uv, tv, dataset);
297 	}
298 	if (!err) {
299 	    setobs_cmd = g_strdup_printf("setobs %s %s --panel-vars",
300 					 dataset->varname[uv],
301 					 dataset->varname[tv]);
302 	}
303 	goto finalize;
304     }
305 
306     /* check for nothing to be done */
307     if (dwinfo->structure == dataset->structure &&
308 	dwinfo->pd == dataset->pd &&
309 	strcmp(dwinfo->stobs, dataset->stobs) == 0) {
310 	if (delmiss) {
311 	    /* recording? */
312 	    goto finalize;
313 	} else {
314 	    infobox(_("No changes were made"));
315 	    return 0;
316 	}
317     }
318 
319     /* if converting to time series, we probably don't want to
320        retain any original observation-marker strings */
321     if (dwinfo->structure == TIME_SERIES &&
322 	dataset->markers && !delmiss) {
323 	delete_markers = 1;
324     }
325 
326     /* handle panel structure */
327     if (known_panel(dwinfo)) {
328 	int nunits = dwinfo->t1;
329 	int nperiods = dataset->n / nunits;
330 
331 	/* we don't offer a choice of "starting obs" */
332 	dwinfo->pd = (dwinfo->structure == STACKED_TIME_SERIES)?
333 	    nperiods : nunits;
334 	strcpy(dwinfo->stobs, "1:1");
335     }
336 
337     /* handle conversion to cross-section */
338     if (dwinfo->structure == CROSS_SECTION) {
339 	strcpy(dwinfo->stobs, "1");
340     }
341 
342     if (dwinfo->structure == TIME_SERIES) {
343 	opt = OPT_T;
344     } else if (dwinfo->structure == STACKED_TIME_SERIES) {
345 	opt = OPT_S;
346     } else if (dwinfo->structure == STACKED_CROSS_SECTION) {
347 	opt = OPT_C;
348     } else if (dwinfo->structure == CROSS_SECTION) {
349 	opt = OPT_X;
350     } else if (dwinfo->structure == SPECIAL_TIME_SERIES) {
351 	opt = OPT_N;
352     }
353 
354     err = simple_set_obs(dataset, dwinfo->pd, dwinfo->stobs, opt);
355 
356 #if DWDEBUG
357     fprintf(stderr, "pd=%d, stobs='%s', opt=%d; set_obs returned %d\n",
358 	    dwinfo->pd, dwinfo->stobs, opt, err);
359 #endif
360 
361     if (!err && setobs_cmd == NULL) {
362 	setobs_cmd = g_strdup_printf("setobs %d %s%s",
363 				     dwinfo->pd, dwinfo->stobs,
364 				     print_flags(opt, SETOBS));
365     }
366 
367  finalize:
368 
369     if (!err && delmiss) {
370 	err = dataset_purge_missing_rows(dataset);
371     }
372 
373     if (err) {
374 	gui_errmsg(err);
375     } else {
376 	if (delete_markers) {
377 	    dataset_destroy_obs_markers(dataset);
378 	}
379 	mark_dataset_as_modified();
380     }
381 
382     if (!err && setobs_cmd != NULL) {
383 	lib_command_strcpy(setobs_cmd);
384 	record_command_verbatim();
385     }
386 
387     g_free(setobs_cmd);
388 
389 #if DWDEBUG
390     fprintf(stderr, "dwiz_make_changes: returning %d\n", err);
391 #endif
392 
393     return err;
394 }
395 
newdata_nobs(DATASET * dwinfo,dw_opts * opts)396 static int newdata_nobs (DATASET *dwinfo, dw_opts *opts)
397 {
398     if (dwinfo->structure == CROSS_SECTION) {
399 	return opts->dvals[0];
400     } else if (dataset_is_time_series(dwinfo)) {
401 	return opts->dvals[1];
402     } else {
403 	return opts->dvals[2] * opts->dvals[3];
404     }
405 }
406 
407 /* alternative to dwiz_make_changes() for use when the existing
408    dataset is empty
409 */
410 
dwiz_replace_dataset(DATASET * dwinfo,dw_opts * opts,GtkWidget * dlg)411 static int dwiz_replace_dataset (DATASET *dwinfo, dw_opts *opts,
412 				 GtkWidget *dlg)
413 {
414     int err, n = newdata_nobs(dwinfo, opts);
415     gretlopt opt = OPT_NONE;
416 
417     err = open_nulldata(dataset, data_status, n, OPT_NONE, NULL);
418     if (err) {
419 	errbox(_("Failed to create empty data set"));
420 	return err;
421     }
422 
423     if (time_series(dwinfo)) {
424 	ntolabel(dwinfo->stobs, dwinfo->t1, dwinfo);
425     }
426 
427     if (dwinfo->structure == TIME_SERIES) {
428 	opt = OPT_T;
429     } else if (dwinfo->structure == STACKED_TIME_SERIES) {
430 	strcpy(dwinfo->stobs, "1:1");
431 	dwinfo->pd = opts->dvals[3];
432 	opt = OPT_S;
433     } else if (dwinfo->structure == CROSS_SECTION) {
434 	opt = OPT_X;
435     } else if (dwinfo->structure == SPECIAL_TIME_SERIES) {
436 	opt = OPT_N;
437     }
438 
439     err = simple_set_obs(dataset, dwinfo->pd, dwinfo->stobs, opt);
440 
441     if (opts->flags & DW_SSHEET) {
442 	gtk_widget_hide(dlg);
443 	maybe_start_editing();
444     } else {
445 	register_data(NULLDATA_STARTED);
446 	lib_command_sprintf("nulldata %d", dataset->n);
447 	record_command_verbatim();
448 	lib_command_sprintf("setobs %d %s%s", dwinfo->pd,
449 			    dwinfo->stobs, print_flags(opt, SETOBS));
450 	record_command_verbatim();
451     }
452 
453     return err;
454 }
455 
456 #define TS_INFO_MAX 10
457 #define PANEL_INFO_MAX 3
458 
459 struct freq_info {
460     int pd;
461     const char *label;
462 };
463 
464 struct freq_info ts_info[] = {
465     {  1, N_("Annual") },
466     {  4, N_("Quarterly") },
467     { 12, N_("Monthly") },
468     { 52, N_("Weekly") },
469     {  5, N_("Daily (5 days)") },
470     {  6, N_("Daily (6 days)") },
471     {  7, N_("Daily (7 days)") },
472     { 24, N_("Hourly") },
473     { 10, N_("Decennial") },
474     { PD_SPECIAL, N_("Other") },
475 };
476 
477 struct panel_info {
478     int code;
479     const char *label;
480 };
481 
482 struct panel_info pan_info[] = {
483     { STACKED_TIME_SERIES,   N_("Stacked time series") },
484     { STACKED_CROSS_SECTION, N_("Stacked cross sections") },
485     { PANEL_UNKNOWN,         N_("Use index variables") }
486 };
487 
ts_frequency_string(const DATASET * dwinfo)488 static const char *ts_frequency_string (const DATASET *dwinfo)
489 {
490     int i, pd = dwinfo->pd;
491 
492     if (pd == PD_SPECIAL) {
493 	return N_("Other");
494     } else if (dwinfo->structure == SPECIAL_TIME_SERIES) {
495 	return N_("Time series");
496     } else {
497 	for (i=0; i<TS_INFO_MAX; i++) {
498 	    if (ts_info[i].pd == pd) {
499 		return ts_info[i].label;
500 	    }
501 	}
502     }
503 
504     return N_("Non-standard frequency");
505 }
506 
507 /* For a step that involves a radio-button choice, figure
508    out the default value */
509 
dwiz_radio_default(DATASET * dwinfo,int step)510 static int dwiz_radio_default (DATASET *dwinfo, int step)
511 {
512     int deflt = 1;
513 
514 #if DWDEBUG
515     fprintf(stderr, "radio_default: step=%d, dwinfo->pd=%d, dwinfo->structure=%d\n",
516 	    step, dwinfo->pd, dwinfo->structure);
517 #endif
518 
519     if (step == DW_SET_TYPE) {
520 	deflt = dwinfo->structure;
521     } else if (step == DW_TS_FREQUENCY) {
522 	if (dwinfo->structure == SPECIAL_TIME_SERIES) {
523 	    deflt = PD_SPECIAL;
524 	} else if (dwinfo->pd == 4 || dwinfo->pd == 5 ||
525 		   dwinfo->pd == 6 || dwinfo->pd == 7 ||
526 		   dwinfo->pd == 10 || dwinfo->pd == 12 ||
527 		   dwinfo->pd == 52) {
528 	    deflt = dwinfo->pd;
529 	}
530     } else if (step == DW_WEEKLY_SELECT) {
531 	deflt = dwinfo->v;
532     } else if (step == DW_PANEL_MODE) {
533 	deflt = dwinfo->structure;
534     }
535 
536 #if DWDEBUG
537     fprintf(stderr, " returning deflt = %d\n", deflt);
538 #endif
539 
540     return deflt;
541 }
542 
543 /* For step @step of the process, figure out the value that
544    should be set by clicking radio button i.
545 */
546 
dwiz_i_to_setval(DATASET * dwinfo,int step,int i)547 static int dwiz_i_to_setval (DATASET *dwinfo, int step, int i)
548 {
549     int setval;
550 
551     if (step == DW_SET_TYPE &&
552 	dwinfo->structure == SPECIAL_TIME_SERIES &&
553 	i == TIME_SERIES) {
554 	setval = SPECIAL_TIME_SERIES;
555     } else if (step == DW_TS_FREQUENCY) {
556 	setval = (i < TS_INFO_MAX)? ts_info[i].pd : 0;
557     } else if (step == DW_PANEL_MODE) {
558 	setval = (i < PANEL_INFO_MAX)? pan_info[i].code : 0;
559     } else {
560 	setval = i;
561     }
562 
563     return setval;
564 }
565 
566 /* For step @step of the process, figure out the label that
567    should be shown alongside radio button i.
568 */
569 
dwiz_radio_strings(int step,int i)570 static const char *dwiz_radio_strings (int step, int i)
571 {
572     if (step == DW_SET_TYPE) {
573 	if (i == 0) return N_("Cross-sectional");
574 	if (i == 1) return N_("Time series");
575 	if (i == 2) return N_("Panel");
576     } else if (step == DW_WEEKLY_SELECT) {
577 	if (i == 0) return N_("Monday");
578 	if (i == 1) return N_("Tuesday");
579 	if (i == 2) return N_("Wednesday");
580 	if (i == 3) return N_("Thursday");
581 	if (i == 4) return N_("Friday");
582 	if (i == 5) return N_("Saturday");
583 	if (i == 6) return N_("Sunday");
584 	if (i == 7) return N_("None (don't use dates)");
585     } else if (step == DW_TS_FREQUENCY) {
586 	return ts_info[i].label;
587     } else if (step == DW_PANEL_MODE) {
588 	return pan_info[i].label;
589     }
590 
591     return "";
592 }
593 
dwiz_set_radio_opt(GtkWidget * w,dw_opts * opts)594 static void dwiz_set_radio_opt (GtkWidget *w, dw_opts *opts)
595 {
596     int val = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "setval"));
597 
598     if (opts->pdspin != NULL) {
599 	if (val == PD_SPECIAL) {
600 	    GtkAdjustment *adj =
601 		gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(opts->pdspin));
602 
603 	    gtk_widget_set_sensitive(opts->pdspin, TRUE);
604 	    val = (int) gtk_adjustment_get_value(adj);
605 	    if (opts->extra != NULL) {
606 		*opts->extra = SPECIAL_TIME_SERIES;
607 	    }
608 	} else {
609 	    gtk_widget_set_sensitive(opts->pdspin, FALSE);
610 	    if (opts->extra != NULL) {
611 		*opts->extra = TIME_SERIES;
612 	    }
613 	}
614     }
615 
616 #if DWDEBUG
617     fprintf(stderr, "dwiz_set_radio_opt: setting setvar to %d\n", val);
618     if (opts->extra != NULL) {
619 	fprintf(stderr, "dwiz_set_radio_opt: extra now = %d\n", *opts->extra);
620     }
621 #endif
622 
623     *opts->setvar = val;
624 }
625 
dw_nobs(DATASET * dwinfo,dw_opts * opts)626 static int dw_nobs (DATASET *dwinfo, dw_opts *opts)
627 {
628     if (dataset->n > 0) {
629 	return dataset->n;
630     } else {
631 	return newdata_nobs(dwinfo, opts);
632     }
633 }
634 
make_confirmation_text(DATASET * dwinfo,dw_opts * opts)635 static gchar *make_confirmation_text (DATASET *dwinfo, dw_opts *opts)
636 {
637     int nobs = dw_nobs(dwinfo, opts);
638     gchar *ret = NULL;
639 
640     if (dwinfo->structure == CROSS_SECTION) {
641 	ret = g_strdup_printf(_("%s, observations 1 to %d"), _("Cross-sectional data"),
642 			      nobs);
643     } else if (time_series(dwinfo)) {
644 	const char *tslabel = ts_frequency_string(dwinfo);
645 	int lastobs = dwinfo->t1 + nobs - 1;
646 	char stobs[OBSLEN];
647 	char endobs[OBSLEN];
648 
649 	if (lastobs > dwinfo->n - 1) {
650 	    dwinfo->n = lastobs + 1;
651 	}
652 	ntolabel(stobs, dwinfo->t1, dwinfo);
653 	ntolabel(endobs, lastobs, dwinfo);
654 	ret = g_strdup_printf(_("%s, %s to %s"), _(tslabel), stobs, endobs);
655 	if (opts->flags & DW_CREATE) {
656 	    GString *gs = g_string_new(ret);
657 
658 	    g_string_append_printf(gs, ", T = %d", nobs);
659 	    g_free(ret);
660 	    ret = g_string_free(gs, FALSE);
661 	}
662     } else if (dwinfo->structure == PANEL_UNKNOWN) {
663 	ret = g_strdup_printf(_("Panel data (%s)\n"
664 				"%d cross-sectional units observed over %d periods"),
665 			      _("stacked time series"), dwinfo->n, dwinfo->pd);
666     } else if (known_panel(dwinfo)) {
667 	int nunits, nperiods;
668 
669 	if (opts->flags & DW_CREATE) {
670 	    nunits = opts->dvals[2];
671 	    nperiods = opts->dvals[3];
672 	} else {
673 	    nunits = dwinfo->t1;
674 	    nperiods = nobs / nunits;
675 	}
676 
677 	ret = g_strdup_printf(_("Panel data (%s)\n"
678 				"%d cross-sectional units observed over %d periods"),
679 			      (dwinfo->structure == STACKED_TIME_SERIES)?
680 			      _("stacked time series") : _("stacked cross sections"),
681 			      nunits, nperiods);
682     }
683 
684     if (opts->flags & DW_DROPMISS) {
685 	gchar *s;
686 
687 	s = g_strdup_printf("%s\n%s", ret, _("(dropping missing observations)"));
688 	g_free(ret);
689 	ret = s;
690     }
691 
692     return ret;
693 }
694 
make_weekly_stobs(DATASET * dwinfo)695 static void make_weekly_stobs (DATASET *dwinfo)
696 {
697     int start_days[] = { 6, 7, 1, 2, 3, 4, 5 };
698 
699     sprintf(dwinfo->stobs, "1800-01-0%d", start_days[dwinfo->v]);
700 }
701 
default_start_decade(void)702 static int default_start_decade (void)
703 {
704     int d = 1700;
705 
706     if (dataset->S != NULL) {
707 	d = positive_int_from_string(dataset->S[0]);
708     }
709 
710     if (d < 0) {
711 	d = 1700;
712     }
713 
714     return d;
715 }
716 
compute_default_ts_info(DATASET * dwinfo)717 static void compute_default_ts_info (DATASET *dwinfo)
718 {
719 #if DWDEBUG
720     char obsstr[OBSLEN];
721 
722     fprintf(stderr, "compute_ts_info() called: pd=%d, structure=%d\n",
723 	    dwinfo->pd, dwinfo->structure);
724     if (dwinfo->pd == PD_SPECIAL) {
725 	fprintf(stderr, "breakage: pd = PD_SPECIAL\n");
726     }
727 #endif
728 
729     if (dwinfo->pd < 0) {
730 	dwinfo->pd = 1;
731     }
732 
733     if (dwinfo->structure == SPECIAL_TIME_SERIES) {
734 	/* non-standard time series */
735 	dwinfo->n = 9999 * dwinfo->pd;
736 	dwinfo->t1 = 0;
737 	if (dwinfo->pd > 1) {
738 	    int p = dwinfo->pd;
739 
740 	    strcpy(dwinfo->stobs, "1:");
741 	    while ((p = p / 10) > 0) {
742 		strcat(dwinfo->stobs, "0");
743 	    }
744 	    strcat(dwinfo->stobs, "1");
745 	} else {
746 	    strcpy(dwinfo->stobs, "1");
747 	}
748     } else if (dwinfo->pd == 1) {
749 	strcpy(dwinfo->stobs, "1");
750 	dwinfo->n = 2100;
751 	dwinfo->t1 = 1959; /* 1960 */
752     } else if (dwinfo->pd == 10) {
753 	int dd = default_start_decade();
754 
755 	sprintf(dwinfo->stobs, "%d", dd);
756 	if (dd > 1700) {
757 	    dwinfo->n = 30;
758 	    dwinfo->t1 = 0;
759 	} else {
760 	    dwinfo->n = 40;
761 	    dwinfo->t1 = 25;
762 	}
763     } else if (dwinfo->pd == 4) {
764 	strcpy(dwinfo->stobs, "1300:1");
765 	dwinfo->n = 1600 + 1400;
766 	dwinfo->t1 = 1600 + 1040; /* 1960:1 */
767     } else if (dwinfo->pd == 12) {
768 	strcpy(dwinfo->stobs, "1300:01");
769 	dwinfo->n = 4800 + 4200;
770 	dwinfo->t1 = 4800 + 3120; /* 1960:01 */
771     } else if (dwinfo->pd == 24) {
772 	strcpy(dwinfo->stobs, "1:01");
773 	dwinfo->n = 1500;
774 	dwinfo->t1 = 0;
775     } else if (dwinfo->pd == 52) {
776 	if (dwinfo->v >= 7) {
777 	    dwinfo->n = 500;
778 	    dwinfo->t1 = 0;
779 	    strcpy(dwinfo->stobs, "1");
780 	} else {
781 	    make_weekly_stobs(dwinfo);
782 	    dwinfo->n = 13000;
783 	    dwinfo->t1 = 7826;
784 	}
785     } else if (dwinfo->pd == 5 ||
786 	       dwinfo->pd == 6 ||
787 	       dwinfo->pd == 7) {
788 	strcpy(dwinfo->stobs, "1900-01-01");
789 	dwinfo->n = 50000;
790 	/* set default start to 1960-01-01 (a Friday) */
791 	if (dwinfo->pd == 5) {
792 	    dwinfo->t1 = 15654;
793 	} else if (dwinfo->pd == 6) {
794 	    dwinfo->t1 = 18784;
795 	} else {
796 	    dwinfo->t1 = 21914;
797 	}
798     }
799 
800     dwinfo->sd0 = get_date_x(dwinfo->pd, dwinfo->stobs);
801 
802     if (dataset->structure == TIME_SERIES &&
803 	dataset->pd == dwinfo->pd) {
804 	/* make the current start the default */
805 	dwinfo->t1 = dateton(dataset->stobs, dwinfo);
806     }
807 
808     ntolabel(dwinfo->endobs, dwinfo->n - 1, dwinfo);
809 
810 #if DWDEBUG
811     ntolabel(obsstr, dwinfo->t1, dwinfo);
812     fprintf(stderr, "dwinfo: v=%d, pd=%d, stobs='%s', endobs='%s', sd0=%g, t1=%d (%s)\n",
813 	    dwinfo->v, dwinfo->pd, dwinfo->stobs, dwinfo->endobs, dwinfo->sd0,
814 	    dwinfo->t1, obsstr);
815 
816     ntolabel(obsstr, dataset->t1, dataset);
817     fprintf(stderr, "dataset: pd=%d, stobs='%s', sd0=%g, t1=%d (%s)\n",
818 	    dataset->pd, dataset->stobs, dataset->sd0, dataset->t1, obsstr);
819 #endif
820 }
821 
default_panel_size(dw_opts * opts,DATASET * dwinfo)822 static int default_panel_size (dw_opts *opts, DATASET *dwinfo)
823 {
824     int sz = opts->plf;
825 
826     if (dwinfo->pd > 1 && dwinfo->n % dwinfo->pd == 0) {
827 	if (dwinfo->structure == STACKED_TIME_SERIES) {
828 	    sz = dwinfo->n / dwinfo->pd;
829 	} else {
830 	    sz = dwinfo->pd;
831 	}
832     }
833 
834     dwinfo->t1 = sz;
835     dwinfo->t2 = dwinfo->n / sz;
836 
837     return sz;
838 }
839 
840 /* translate from the 0-based indexing in the GtkComboBox to
841    dataset indexing, for the unit and period variables */
842 
translate_panel_vars(dw_opts * opts,int * uv,int * tv)843 static int translate_panel_vars (dw_opts *opts, int *uv, int *tv)
844 {
845     GList *list = opts->vlist;
846     int i, vi;
847     int err = 0;
848 
849     *uv = *tv = 0;
850 
851     for (i=0; list != NULL && !err; i++) {
852 	if (i == opts->uid || i == opts->tid) {
853 	    vi = series_index(dataset, (const char *) list->data);
854 	    if (vi == dataset->v) {
855 		err = E_DATA;
856 	    } else if (i == opts->uid) {
857 		*uv = vi;
858 	    } else {
859 		*tv = vi;
860 	    }
861 	}
862 	if (*uv > 0 && *tv > 0) {
863 	    break;
864 	}
865 	list = list->next;
866     }
867 
868 #if DWDEBUG
869     fprintf(stderr, "translate_panel_vars: uid: %d -> %d, tid: %d -> %d\n",
870 	    opts->uid, *uv, opts->tid, *tv);
871 #endif
872 
873     return err;
874 }
875 
diagnose_panel_problem(DATASET * dset,int uv,int tv,int known_problem)876 static int diagnose_panel_problem (DATASET *dset, int uv, int tv,
877 				   int known_problem)
878 {
879     gchar *msg = NULL;
880     double ui, ti;
881     double uj, tj;
882     int i, j;
883     int found = 0;
884 
885     for (i=1; i<dset->n && !found; i++) {
886 	ui = dset->Z[uv][i];
887 	ti = dset->Z[tv][i];
888 	for (j=0; j<i; j++) {
889 	    uj = dset->Z[uv][j];
890 	    tj = dset->Z[tv][j];
891 	    if (uj == ui && tj == ti) {
892 		msg = g_strdup_printf("%s = %g and %s = %g duplicated on "
893 				      "rows %d and %d", dset->varname[uv],
894 				      ui, dset->varname[tv], ti, i+1, j+1);
895 		found = 1;
896 		break;
897 	    }
898 	}
899     }
900 
901     if (!known_problem && !found) {
902 	return 0; /* nothing amiss */
903     }
904 
905     if (msg != NULL) {
906 	errbox(msg);
907 	g_free(msg);
908     } else {
909 	errbox(_("The selected index variables do not represent "
910 		 "a panel structure"));
911     }
912 
913     return E_DATA;
914 }
915 
916 /* Given two user-selected variables that supposedly represent the
917    panel unit and period respectively, check that the selection makes
918    sense.
919 */
920 
process_panel_vars(DATASET * dwinfo,dw_opts * opts)921 static int process_panel_vars (DATASET *dwinfo, dw_opts *opts)
922 {
923     int n = dataset->n;
924     double *uid = NULL;
925     double *tid = NULL;
926     int uv, tv;
927     int nunits = 0;
928     int nperiods = 0;
929     int err = 0;
930 
931     /* FIXME sub-sampled dataset? */
932 
933     err = translate_panel_vars(opts, &uv, &tv);
934     if (err) {
935 	return err;
936     }
937 
938     if (uv == tv) {
939 	/* "can't happen" */
940 	errbox(_("The unit and time index variables must be distinct"));
941 	return E_DATA;
942     }
943 
944     uid = copyvec(dataset->Z[uv], n);
945     tid = copyvec(dataset->Z[tv], n);
946 
947     if (uid == NULL || tid == NULL) {
948 	nomem();
949 	err = E_ALLOC;
950     }
951 
952     if (!err) {
953 	qsort(uid, n, sizeof *uid, gretl_compare_doubles);
954 	nunits = count_distinct_values(uid, n);
955 
956 	qsort(tid, n, sizeof *tid, gretl_compare_doubles);
957 	nperiods = count_distinct_values(tid, n);
958 
959 	/* Heuristic: if a variable represents either the panel
960 	   unit or period, it must have at least two distinct
961 	   values, and must have fewer values than the total
962 	   number of observations.  Further, the product of
963 	   the number of distinct values for the unit and time
964 	   variables must be at least equal to the number of
965 	   observations, otherwise there will be duplicated
966 	   rows (i.e. more than one row claiming to represent
967 	   unit i, period t, for some i, t).
968 
969 	   Note that the product (nunits * nperiods) may be
970 	   _greater_ than total n: this may mean that we have
971 	   some implicit missing observations.
972 	*/
973 
974 	if (nunits == 1 || nperiods == 1 ||
975 	    nunits == n || nperiods == n) {
976 	    errbox(_("The selected index variables do not represent "
977 		     "a panel structure"));
978 	    fprintf(stderr, "nunits=%d, nperiods=%d, n=%d\n",
979 		    nunits, nperiods, n);
980 	    err = E_DATA;
981 	} else {
982 	    int known_problem = nunits * nperiods < n;
983 
984 	    err = diagnose_panel_problem(dataset, uv, tv, known_problem);
985 	}
986 
987 	if (!err) {
988 	    dwinfo->n = nunits;
989 	    dwinfo->pd = nperiods;
990 	}
991     }
992 
993     free(uid);
994     free(tid);
995 
996     return err;
997 }
998 
999 /* Try to assemble a list of at least two potential panel index
1000    variables.  These variables must have nothing but non-negative
1001    integer values, and they must have at least two distinct values
1002    (i.e. cannot be constants).
1003 */
1004 
panelvars_list_ok(dw_opts * opts)1005 static int panelvars_list_ok (dw_opts *opts)
1006 {
1007     GList *vlist = NULL;
1008     int i, t, ok;
1009     double xt;
1010     int err = 0;
1011 
1012     if (opts->flags & DW_VLIST_DONE) {
1013 	return (opts->vlist != NULL);
1014     }
1015 
1016     for (i=1; i<dataset->v; i++) {
1017 	ok = 1;
1018 	for (t=dataset->t1; t<=dataset->t2; t++) {
1019 	    xt = dataset->Z[i][t];
1020 	    if (na(xt) || xt < 0 || xt != floor(xt)) {
1021 		ok = 0;
1022 		break;
1023 	    }
1024 	}
1025 	if (ok) {
1026 	    ok = !gretl_isconst(dataset->t1, dataset->t2, dataset->Z[i]);
1027 	}
1028 	if (ok) {
1029 	    vlist = g_list_append(vlist, dataset->varname[i]);
1030 	}
1031     }
1032 
1033     if (vlist == NULL) {
1034 	err = 1;
1035     } else if (g_list_length(vlist) < 2) {
1036 	g_list_free(vlist);
1037 	vlist = NULL;
1038 	err = 1;
1039     }
1040 
1041     opts->vlist = vlist;
1042     opts->flags |= DW_VLIST_DONE;
1043 
1044 #if DWDEBUG
1045     fprintf(stderr, "panelvars_list_ok: returning %d\n", !err);
1046 #endif
1047 
1048     return !err;
1049 }
1050 
1051 /* Check whether or not it's feasible to offer a panel interpretation
1052    of the current dataset.  This is impossible if the total number of
1053    observations is prime (cannot be factored as n * T) and the dataset
1054    contains no variables that might plausibly represent panel unit and
1055    period respectively.
1056 */
1057 
panel_possible(dw_opts * opts)1058 static int panel_possible (dw_opts *opts)
1059 {
1060     int ok = 1;
1061 
1062     if (opts->flags & DW_NO_PANEL) {
1063 	return 0;
1064     }
1065 
1066     eval_n_is_prime(opts);
1067 
1068     if (opts->flags & DW_N_PRIME) {
1069 	/* are there feasible index vars? */
1070 	ok = panelvars_list_ok(opts);
1071     }
1072 
1073     if (!ok) {
1074 	opts->flags |= DW_NO_PANEL;
1075 	warnbox(_("This dataset cannot be interpreted as a panel"));
1076     }
1077 
1078     return ok;
1079 }
1080 
1081 /* callback from combo: update the panel unit or time variable,
1082    building in a guard against selecting the same variable in
1083    both roles
1084 */
1085 
update_panel_var(GtkWidget * box,dw_opts * opts)1086 static gboolean update_panel_var (GtkWidget *box, dw_opts *opts)
1087 {
1088     gint v = gtk_combo_box_get_active(GTK_COMBO_BOX(box));
1089     int i = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(box), "index"));
1090     GtkWidget *other = g_object_get_data(G_OBJECT(box), "other");
1091 
1092     if (i == 0) {
1093 	opts->uid = v;
1094     } else {
1095 	opts->tid = v;
1096     }
1097 
1098     if (other != NULL) {
1099 	gint v2 = gtk_combo_box_get_active(GTK_COMBO_BOX(other));
1100 
1101 	if (v == v2) {
1102 	    /* we have a conflict: fix it */
1103 	    if (v > 0) {
1104 		gtk_combo_box_set_active(GTK_COMBO_BOX(other), 0);
1105 	    } else {
1106 		gtk_combo_box_set_active(GTK_COMBO_BOX(other), 1);
1107 	    }
1108 	}
1109     }
1110 
1111 #if DWDEBUG
1112     fprintf(stderr, "update_panel_var: i=%d, uid = %d, tid = %d\n",
1113 	    i, opts->uid, opts->tid);
1114 #endif
1115 
1116     return FALSE;
1117 }
1118 
1119 /* Try to find the most likely candidates for the unit (uid) and time
1120    (tid) index variables, given a list of variables that might
1121    perhaps be acceptable.
1122 */
1123 
panelvar_candidates(GList * vlist,int * uid,int * tid)1124 static void panelvar_candidates (GList *vlist, int *uid, int *tid)
1125 {
1126     GList *list = vlist;
1127     const char *vname;
1128     char vtest[VNAMELEN];
1129     int i;
1130 
1131     *uid = *tid = -1;
1132 
1133     for (i=0; list != NULL; i++) {
1134 	vname = (const char *) list->data;
1135 	strcpy(vtest, vname);
1136 	gretl_lower(vtest);
1137 	if (*tid < 0) {
1138 	    if (!strcmp(vtest, "time") ||
1139 		!strcmp(vtest, "year") ||
1140 		!strcmp(vtest, "period")) {
1141 		*tid = i;
1142 	    }
1143 	}
1144 	if (*uid < 0) {
1145 	    if (!strcmp(vtest, "unit") ||
1146 		!strcmp(vtest, "group") ||
1147 		!strcmp(vtest, "country") ||
1148 		!strcmp(vtest, "id")) {
1149 		*uid = i;
1150 	    }
1151 	}
1152 	if (*uid >= 0 && *tid >= 0) {
1153 	    break;
1154 	}
1155 	list = list->next;
1156     }
1157 
1158     /* if we didn't succeed above, just ensure a non-conflicting
1159        assignment to uidx and tidx */
1160 
1161     if (*uid < 0) {
1162 	if (*tid < 0) {
1163 	    *uid = 0;
1164 	    *tid = 1;
1165 	} else {
1166 	    *uid = (*tid == 0)? 1 : 0;
1167 	}
1168     } else if (*tid < 0) {
1169 	*tid = (*uid == 0)? 1 : 0;
1170     }
1171 }
1172 
1173 /* combo box selector for variables possibly representing the
1174    panel unit and time-period */
1175 
dwiz_combo(GList * vlist,dw_opts * opts)1176 static GtkWidget *dwiz_combo (GList *vlist, dw_opts *opts)
1177 {
1178     const char *strs[] = {
1179 	N_("Unit or group index variable"),
1180 	N_("Time index variable")
1181     };
1182     GtkWidget *w;
1183     GtkWidget *table;
1184     GtkWidget *combo[2];
1185     int i;
1186 
1187     panelvar_candidates(vlist, &opts->uid, &opts->tid);
1188 
1189 #if DWDEBUG
1190     fprintf(stderr, "dwiz_combo: uid = %d, tid = %d\n",
1191 	    opts->uid, opts->tid);
1192 #endif
1193 
1194     table = gtk_table_new(2, 2, FALSE);
1195     gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1196     gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1197 
1198     for (i=0; i<2; i++) {
1199 	GList *list = vlist;
1200 
1201 	w = gtk_label_new(_(strs[i]));
1202 	gtk_misc_set_alignment(GTK_MISC(w), 1.0, 0.5);
1203 	gtk_table_attach_defaults(GTK_TABLE(table), w, 0, 1, i, i+1);
1204 
1205 	combo[i] = gtk_combo_box_text_new();
1206 	gtk_table_attach_defaults(GTK_TABLE(table), combo[i], 1, 2, i, i+1);
1207 
1208 	while (list != NULL) {
1209 	    combo_box_append_text(combo[i], list->data);
1210 	    list = list->next;
1211 	}
1212 
1213 	gtk_combo_box_set_active(GTK_COMBO_BOX(combo[i]), (i == 0)? opts->uid : opts->tid);
1214 	g_object_set_data(G_OBJECT(combo[i]), "index", GINT_TO_POINTER(i));
1215 	g_signal_connect(G_OBJECT(combo[i]), "changed",
1216 			 G_CALLBACK(update_panel_var), opts);
1217     }
1218 
1219     /* cross-connect the selectors */
1220     g_object_set_data(G_OBJECT(combo[0]), "other", combo[1]);
1221     g_object_set_data(G_OBJECT(combo[1]), "other", combo[0]);
1222 
1223     return table;
1224 }
1225 
dw_set_custom_frequency(GtkWidget * w,DATASET * dwinfo)1226 static void dw_set_custom_frequency (GtkWidget *w, DATASET *dwinfo)
1227 {
1228     dwinfo->pd = (int) gtk_adjustment_get_value(GTK_ADJUSTMENT(w));
1229 #if DWDEBUG
1230     fprintf(stderr, "dw_set_custom_frequency: set dwinfo->pd = %d\n", dwinfo->pd);
1231 #endif
1232 }
1233 
dw_set_t1(GtkWidget * w,DATASET * dwinfo)1234 static void dw_set_t1 (GtkWidget *w, DATASET *dwinfo)
1235 {
1236     dwinfo->t1 = (int) gtk_adjustment_get_value(GTK_ADJUSTMENT(w));
1237 #if DWDEBUG
1238     fprintf(stderr, "dw_set_t1: set dwinfo->t1 = %d\n", dwinfo->t1);
1239     fprintf(stderr, "(memo: dwinfo->n = %d)\n", dwinfo->n);
1240 #endif
1241 }
1242 
1243 /* spinner for time-series starting observation */
1244 
add_startobs_spinner(GtkWidget * vbox,DATASET * dwinfo,int direction)1245 static void add_startobs_spinner (GtkWidget *vbox,
1246 				  DATASET *dwinfo,
1247 				  int direction)
1248 {
1249     GtkWidget *hbox, *label, *spin;
1250     GtkAdjustment *adj;
1251 
1252     if (direction == DW_FORWARD) {
1253 	compute_default_ts_info(dwinfo);
1254     }
1255 
1256     adj = (GtkAdjustment *) gtk_adjustment_new(dwinfo->t1,
1257 					       0, dwinfo->n - 1,
1258 					       1, 10, 0);
1259     g_signal_connect(G_OBJECT(adj), "value-changed",
1260 		     G_CALLBACK(dw_set_t1), dwinfo);
1261     spin = data_start_button(adj, dwinfo);
1262     gtk_entry_set_activates_default(GTK_ENTRY(spin), TRUE);
1263 
1264     hbox = gtk_hbox_new(FALSE, 5);
1265     label = gtk_label_new(_(ts_frequency_string(dwinfo)));
1266     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
1267     gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
1268     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1269     gtk_widget_show_all(hbox);
1270 }
1271 
1272 /* spinner for selecting custom time-series frequency */
1273 
frequency_spinner(GtkWidget * hbox,DATASET * dwinfo)1274 static GtkWidget *frequency_spinner (GtkWidget *hbox, DATASET *dwinfo)
1275 {
1276     GtkAdjustment *adj;
1277     GtkWidget *spin;
1278     int pdmax = 1000; /* arbitrary */
1279 
1280     adj = (GtkAdjustment *) gtk_adjustment_new(dwinfo->pd, 1, pdmax,
1281 					       1, 10, 0);
1282 
1283     g_signal_connect(G_OBJECT(adj), "value-changed",
1284 		     G_CALLBACK(dw_set_custom_frequency), dwinfo);
1285     spin = gtk_spin_button_new(adj, 1, 0);
1286 
1287     gtk_entry_set_activates_default(GTK_ENTRY(spin), TRUE);
1288     gtk_box_pack_start(GTK_BOX(hbox), spin, FALSE, FALSE, 0);
1289     gtk_widget_show(spin);
1290 
1291     return spin;
1292 }
1293 
1294 /* Panel: callback for setting the number of cross-sectional units, n,
1295    and the number of time periods, T, via spin buttons.  We allow the
1296    user to vary either n or T, subject to the constraint that n * T
1297    equals the total number of observations.
1298 */
1299 
dw_set_panel_dims(GtkSpinButton * w,DATASET * dwinfo)1300 static void dw_set_panel_dims (GtkSpinButton *w, DATASET *dwinfo)
1301 {
1302     int idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "idx"));
1303     int plf = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "plf"));
1304     GtkSpinButton *nspin = NULL, *Tspin = NULL;
1305     int oldn = dwinfo->t1;
1306     int oldT = dwinfo->t2;
1307     int n = 0, T = 0;
1308 
1309     if (idx == 0) {
1310 	nspin = w;
1311 	Tspin = g_object_get_data(G_OBJECT(w), "Tspin");
1312     } else {
1313 	Tspin = w;
1314 	nspin = g_object_get_data(G_OBJECT(w), "nspin");
1315     }
1316 
1317     if (nspin != NULL) {
1318 	n = gtk_spin_button_get_value_as_int(nspin);
1319     }
1320 
1321     if (Tspin != NULL) {
1322 	T = gtk_spin_button_get_value_as_int(Tspin);
1323     }
1324 
1325     if (nspin != NULL && Tspin != NULL) {
1326 	int nTmax = dataset->n / plf;
1327 
1328 	if (n != oldn) {
1329 	    if (n > oldn) {
1330 		while (dataset->n % n && n <= nTmax) {
1331 		    n++;
1332 		}
1333 	    } else if (n < oldn) {
1334 		while (dataset->n % n && n >= plf) {
1335 		    n--;
1336 		}
1337 	    }
1338 	    if (dataset->n % n) {
1339 		n = oldn;
1340 	    }
1341 	    T = dataset->n / n;
1342 	} else if (T != oldT) {
1343 	    if (T > oldT) {
1344 		while (dataset->n % T && T <= nTmax) {
1345 		    T++;
1346 		}
1347 	    } else if (T < oldT) {
1348 		while (dataset->n % T && T >= plf) {
1349 		    T--;
1350 		}
1351 	    }
1352 	    if (dataset->n % T) {
1353 		T = oldT;
1354 	    }
1355 	    n = dataset->n / T;
1356 	}
1357 
1358 	gtk_spin_button_set_value(nspin, (double) n);
1359 	gtk_spin_button_set_value(Tspin, (double) T);
1360     }
1361 
1362     dwinfo->t1 = n;
1363     dwinfo->t2 = T;
1364 
1365 #if DWDEBUG
1366     fprintf(stderr, "dw_set_panel_dims: n: %d -> %d, T: %d -> %d\n",
1367 	    oldn, n, oldT, T);
1368 #endif
1369 }
1370 
dwiz_make_panel_spinners(dw_opts * opts,DATASET * dwinfo,GtkWidget * vbox)1371 static void dwiz_make_panel_spinners (dw_opts *opts,
1372 				      DATASET *dwinfo,
1373 				      GtkWidget *vbox)
1374 {
1375     const char *labels[] = {
1376 	N_("Number of cross-sectional units"),
1377 	N_("Number of time periods")
1378     };
1379     GtkWidget *label;
1380     GtkWidget *table;
1381     GtkAdjustment *adj;
1382     GtkWidget *pspin[2];
1383     int spinmin, spinmax, spinstart;
1384     int i;
1385 
1386     spinmin = opts->plf;
1387     spinmax = dataset->n / opts->plf;
1388     spinstart = default_panel_size(opts, dwinfo);
1389 
1390     table = gtk_table_new(2, 2, FALSE);
1391     gtk_table_set_col_spacings(GTK_TABLE(table), 5);
1392     gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1393 
1394     for (i=0; i<2; i++) {
1395 	label = gtk_label_new(_(labels[i]));
1396 	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1397 	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, i, i+1);
1398 
1399 	if (i == 1) {
1400 	    spinstart = dataset->n / spinstart;
1401 	}
1402 
1403 	adj = (GtkAdjustment *) gtk_adjustment_new(spinstart, spinmin, spinmax,
1404 						   1, 10, 0);
1405 	pspin[i] = gtk_spin_button_new(adj, 1, 0);
1406 	g_object_set_data(G_OBJECT(pspin[i]), "idx", GINT_TO_POINTER(i));
1407 	g_object_set_data(G_OBJECT(pspin[i]), "plf", GINT_TO_POINTER(opts->plf));
1408 	g_signal_connect(G_OBJECT(pspin[i]), "value-changed",
1409 			 G_CALLBACK(dw_set_panel_dims), dwinfo);
1410 	gtk_entry_set_activates_default(GTK_ENTRY(pspin[i]), TRUE);
1411 	gtk_table_attach_defaults(GTK_TABLE(table), pspin[i], 1, 2, i, i+1);
1412     }
1413 
1414     g_object_set_data(G_OBJECT(pspin[0]), "Tspin", pspin[1]);
1415     g_object_set_data(G_OBJECT(pspin[1]), "nspin", pspin[0]);
1416 
1417     gtk_widget_show_all(table);
1418     gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 5);
1419 }
1420 
maybe_add_missobs_purger(GtkWidget * vbox,gretlopt * flags)1421 static void maybe_add_missobs_purger (GtkWidget *vbox, gretlopt *flags)
1422 {
1423     double missfrac = 0.0;
1424     int active = 0;
1425 
1426     if (*flags & DW_DROPMISS) {
1427 	active = 1;
1428     } else {
1429 	missfrac = missing_obs_fraction(dataset);
1430     }
1431 
1432     if (active || (missfrac > 0 && missfrac < 0.12)) {
1433 	GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
1434 	GtkWidget *chk;
1435 
1436 	chk = gretl_option_check_button(_("purge missing observations"),
1437 					flags, (gretlopt) DW_DROPMISS);
1438 	gtk_box_pack_start(GTK_BOX(hbox), chk, FALSE, FALSE, 5);
1439 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1440 	if (active) {
1441 	    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk), TRUE);
1442 	}
1443 	gtk_widget_show_all(hbox);
1444     }
1445 }
1446 
1447 /* Calculate the options set-up for a given step of the wizard
1448    process: How many radio-button options should we show (if any)?
1449    What variable are we setting?  What should be the default value for
1450    this variable?
1451 */
1452 
set_up_dw_opts(dw_opts * opts,int step,DATASET * dwinfo)1453 static void set_up_dw_opts (dw_opts *opts, int step,
1454 			    DATASET *dwinfo)
1455 {
1456     opts->setvar = NULL;
1457     opts->extra = NULL;
1458     opts->pdspin = NULL;
1459     opts->n_radios = 0;
1460 
1461     opts->deflt = dwiz_radio_default(dwinfo, step);
1462 
1463     if (step == DW_SET_TYPE) {
1464 	if (opts->flags & DW_NO_PANEL) {
1465 	    opts->n_radios = 2;
1466 	} else {
1467 	    opts->n_radios = 3;
1468 	}
1469 	opts->setvar = &dwinfo->structure;
1470     } else if (step == DW_TS_FREQUENCY) {
1471 	opts->n_radios = TS_INFO_MAX;
1472 	opts->setvar = &dwinfo->pd;
1473 	opts->extra = &dwinfo->structure;
1474     } else if (step == DW_WEEKLY_SELECT) {
1475 	opts->n_radios = 8;
1476 	opts->setvar = &dwinfo->v;
1477     } else if (step == DW_PANEL_MODE) {
1478 	opts->n_radios = PANEL_INFO_MAX;
1479 	opts->setvar = &dwinfo->structure;
1480 	eval_n_is_prime(opts);
1481     } else if (step == DW_PANEL_SIZE) {
1482 	opts->setvar = &dwinfo->pd;
1483     }
1484 }
1485 
get_dimensions(int s,dw_opts * opts,int * dmax,int * d)1486 static void get_dimensions (int s, dw_opts *opts,
1487 			    int *dmax, int *d)
1488 {
1489     int k = opts->dvals[s];
1490 
1491     if (s >= STACKED_TIME_SERIES) {
1492 	*d = (k == 0)? 10 : k;
1493 	*dmax = 10000;
1494     } else {
1495 	*d = (k == 0)? 100 : k;
1496 	*dmax = 1000000;
1497     }
1498 }
1499 
sensitize_obs_spinners(GtkToggleButton * button,dw_opts * opts)1500 static void sensitize_obs_spinners (GtkToggleButton *button,
1501 				    dw_opts *opts)
1502 {
1503     if (button_is_active(button)) {
1504 	int i, s, sv = widget_get_int(button, "setval");
1505 
1506 	for (i=0; i<4; i++) {
1507 	    s = (i == sv || (sv == 2 && i == 3));
1508 	    gtk_widget_set_sensitive(opts->dspin[i], s);
1509 	}
1510     }
1511 }
1512 
set_initial_obs_sensitivities(DATASET * dwinfo,dw_opts * opts)1513 static void set_initial_obs_sensitivities (DATASET *dwinfo,
1514 					   dw_opts *opts)
1515 {
1516     int i, s[4] = {0};
1517 
1518     if (dwinfo->structure == CROSS_SECTION) {
1519 	s[0] = 1;
1520     } else if (dataset_is_time_series(dwinfo)) {
1521 	s[1] = 1;
1522     } else {
1523 	s[2] = s[3] = 1;
1524     }
1525 
1526     for (i=0; i<4; i++) {
1527 	gtk_widget_set_sensitive(opts->dspin[i], s[i]);
1528     }
1529 }
1530 
dwiz_new_dataset_combo(DATASET * dwinfo,dw_opts * opts,GtkWidget * vbox)1531 static void dwiz_new_dataset_combo (DATASET *dwinfo,
1532 				    dw_opts *opts,
1533 				    GtkWidget *vbox)
1534 {
1535     const gchar *strs[] = {"n =", "T ="};
1536     GSList *group = NULL;
1537     GtkWidget *button = NULL;
1538     GtkWidget *buttons[3];
1539     GtkWidget *label;
1540     GtkWidget *hbox, *table;
1541     int dmax, dval = 0;
1542     int i, j;
1543 
1544     table = gtk_table_new(4, 2, FALSE);
1545     gtk_table_set_row_spacings(GTK_TABLE(table), 5);
1546     gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
1547     gtk_widget_show(table);
1548 
1549     for (i=0; i<3; i++) {
1550 	const char *s = dwiz_radio_strings(DW_SET_TYPE, i);
1551 	int setval = dwiz_i_to_setval(dwinfo, DW_SET_TYPE, i);
1552 
1553 	if (button != NULL) {
1554 	    group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
1555 	} else {
1556 	    group = NULL;
1557 	}
1558 
1559 	/* dataset structure selector */
1560 	buttons[i] = button = gtk_radio_button_new_with_label(group, _(s));
1561 	gtk_table_attach_defaults(GTK_TABLE(table), button, 0, 1, i, i+1);
1562 	g_signal_connect(G_OBJECT(button), "clicked",
1563 			 G_CALLBACK(dwiz_set_radio_opt), opts);
1564 	g_object_set_data(G_OBJECT(button), "setval", GINT_TO_POINTER(setval));
1565 	gtk_widget_show(button);
1566 
1567 	/* dimension (n or T) selector(s) */
1568 	hbox = gtk_hbox_new(FALSE, 5);
1569 	j = (i == 2)? 0 : i;
1570 	label = gtk_label_new(strs[j]);
1571 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
1572 	get_dimensions(i, opts, &dmax, &dval);
1573 	opts->dspin[i] = gtk_spin_button_new_with_range(2, dmax, 1);
1574 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(opts->dspin[i]), dval);
1575 	gtk_box_pack_start(GTK_BOX(hbox), opts->dspin[i], FALSE, FALSE, 5);
1576 	gtk_table_attach_defaults(GTK_TABLE(table), hbox, 1, 2, i, i+1);
1577 	gtk_widget_show_all(hbox);
1578 
1579 	if (i == 2) {
1580 	    /* panel: we need a setter for T as well as n */
1581 	    hbox = gtk_hbox_new(FALSE, 5);
1582 	    label = gtk_label_new(strs[j+1]);
1583 	    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
1584 	    get_dimensions(i+1, opts, &dmax, &dval);
1585 	    opts->dspin[i+1] = gtk_spin_button_new_with_range(2, dmax, 1);
1586 	    gtk_spin_button_set_value(GTK_SPIN_BUTTON(opts->dspin[i+1]), dval);
1587 	    gtk_box_pack_start(GTK_BOX(hbox), opts->dspin[i+1], FALSE, FALSE, 5);
1588 	    gtk_table_attach_defaults(GTK_TABLE(table), hbox, 1, 2, i+1, i+2);
1589 	    gtk_widget_show_all(hbox);
1590 	}
1591 
1592 	if (opts->deflt == setval) {
1593 	    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
1594 	    if (opts->setvar != NULL && setval >= 0) {
1595 		/* preset the variable to its default value */
1596 		*opts->setvar = setval;
1597 	    }
1598 	}
1599 
1600     }
1601 
1602     for (i=0; i<3; i++) {
1603 	/* we defer this hook-up until all the spinners are created */
1604 	g_signal_connect(G_OBJECT(buttons[i]), "toggled",
1605 			 G_CALLBACK(sensitize_obs_spinners), opts);
1606     }
1607 
1608     set_initial_obs_sensitivities(dwinfo, opts);
1609 }
1610 
1611 /* make two or more radio buttons based on the current settings in
1612    the @opts structure
1613 */
1614 
dwiz_build_radios(int step,DATASET * dwinfo,dw_opts * opts,GtkWidget * vbox)1615 static void dwiz_build_radios (int step, DATASET *dwinfo,
1616 			       dw_opts *opts, GtkWidget *vbox)
1617 {
1618     GSList *group = NULL;
1619     GtkWidget *button = NULL;
1620     int i;
1621 
1622     for (i=0; i<opts->n_radios; i++) {
1623 	/* determine the value to be set by button i */
1624 	int setval = dwiz_i_to_setval(dwinfo, step, i);
1625 	GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
1626 
1627 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1628 	gtk_widget_show(hbox);
1629 
1630 	if (button != NULL) {
1631 	    group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
1632 	} else {
1633 	    group = NULL;
1634 	}
1635 	button = gtk_radio_button_new_with_label(group,
1636 						 _(dwiz_radio_strings(step, i)));
1637 	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
1638 
1639 	if (step == DW_TS_FREQUENCY && i == opts->n_radios - 1) {
1640 	    /* time series, "other" (custom) frequency: need spinner */
1641 	    opts->pdspin = frequency_spinner(hbox, dwinfo);
1642 	    gtk_widget_set_sensitive(opts->pdspin, FALSE);
1643 	}
1644 
1645 	g_signal_connect(G_OBJECT(button), "clicked",
1646 			 G_CALLBACK(dwiz_set_radio_opt), opts);
1647 	g_object_set_data(G_OBJECT(button), "setval", GINT_TO_POINTER(setval));
1648 
1649 	if (step == DW_PANEL_MODE && dw_n_is_prime(opts)) {
1650 	    /* only the "index variables" option should be active */
1651 	    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
1652 					 setval == PANEL_UNKNOWN);
1653 	    gtk_widget_set_sensitive(button, setval == PANEL_UNKNOWN);
1654 	} else if (opts->deflt == setval) {
1655 	    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
1656 	    if (opts->setvar != NULL && setval >= 0) {
1657 		/* preset the variable to its default value */
1658 		*opts->setvar = setval;
1659 	    }
1660 	}
1661 
1662 	if (step == DW_PANEL_MODE && i == opts->n_radios - 1) {
1663 	    if (!panelvars_list_ok(opts)) {
1664 		/* disable the "index variables" option */
1665 		gtk_widget_set_sensitive(button, FALSE);
1666 		gretl_tooltips_add(button,
1667 				   _("The data set contains no suitable index variables"));
1668 	    }
1669 	}
1670 
1671 	gtk_widget_show(button);
1672     }
1673 }
1674 
dwiz_panelvars_selector(dw_opts * opts,DATASET * dwinfo,GtkWidget * vbox)1675 static void dwiz_panelvars_selector (dw_opts *opts,
1676 				     DATASET *dwinfo,
1677 				     GtkWidget *vbox)
1678 {
1679     GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
1680     GtkWidget *table = dwiz_combo(opts->vlist, opts);
1681 
1682     gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 5);
1683     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1684     gtk_widget_show_all(hbox);
1685 }
1686 
1687 /* Where should we be going, when the Forward or Back button
1688    is clicked? */
1689 
dwiz_compute_step(int prevstep,int direction,DATASET * dwinfo,dw_opts * opts)1690 static int dwiz_compute_step (int prevstep, int direction, DATASET *dwinfo,
1691 			      dw_opts *opts)
1692 {
1693     int create = opts->flags & DW_CREATE;
1694     int step = 0;
1695 
1696 #if DWDEBUG
1697     fprintf(stderr, "dwiz_compute_step: incoming step = %d\n", prevstep);
1698 #endif
1699 
1700     if (direction == DW_FORWARD) {
1701 	if (prevstep == DW_SET_TYPE) {
1702 	    if (time_series(dwinfo)) {
1703 		step = DW_TS_FREQUENCY;
1704 	    } else if (known_panel(dwinfo)) {
1705 		if (create) {
1706 		    dwinfo->structure = STACKED_TIME_SERIES;
1707 		    step = DW_CONFIRM;
1708 		} else {
1709 		    step = DW_PANEL_MODE;
1710 		}
1711 	    } else if (dwinfo->structure == PANEL_UNKNOWN) {
1712 		step = DW_PANEL_MODE;
1713 	    } else {
1714 		/* cross section */
1715 		dwinfo->pd = 1;
1716 		step = DW_CONFIRM;
1717 	    }
1718 	} else if (prevstep == DW_TS_FREQUENCY) {
1719 	    if (dwinfo->structure != SPECIAL_TIME_SERIES) {
1720 		if (dwinfo->pd == 52) {
1721 		    step = DW_WEEKLY_SELECT;
1722 		} else {
1723 		    step = DW_STARTING_OBS;
1724 		}
1725 	    } else {
1726 		step = DW_STARTING_OBS;
1727 	    }
1728 	} else if (prevstep == DW_WEEKLY_SELECT) {
1729 	    step = DW_STARTING_OBS;
1730 	} else if (prevstep == DW_PANEL_MODE) {
1731 	    if (dwinfo->structure == PANEL_UNKNOWN) {
1732 		step = DW_PANEL_VARS;
1733 	    } else {
1734 		step = DW_PANEL_SIZE;
1735 	    }
1736 	} else if (prevstep == DW_PANEL_VARS) {
1737 	    if (process_panel_vars(dwinfo, opts)) {
1738 		/* error: don't proceed */
1739 		step = DW_PANEL_VARS;
1740 	    } else {
1741 		step = DW_CONFIRM;
1742 	    }
1743 	} else if (prevstep == DW_STARTING_OBS ||
1744 		   prevstep == DW_PANEL_SIZE) {
1745 	    if (prevstep == DW_PANEL_SIZE &&
1746 		dwinfo->structure == STACKED_TIME_SERIES) {
1747 		dwinfo->pd = dwinfo->t2;
1748 	    }
1749 	    step = DW_CONFIRM;
1750 	}
1751     } else if (direction == DW_BACK) {
1752 	if (prevstep == DW_CONFIRM && create) {
1753 	    if (dwinfo->structure == CROSS_SECTION ||
1754 		dwinfo->structure == STACKED_TIME_SERIES) {
1755 		return DW_SET_TYPE;
1756 	    }
1757 	}
1758 	if (prevstep == DW_TS_FREQUENCY || prevstep == DW_PANEL_MODE) {
1759 	    step = DW_SET_TYPE;
1760 	} else if (prevstep == DW_STARTING_OBS) {
1761 	    if (dwinfo->pd == 52) {
1762 		step = DW_WEEKLY_SELECT;
1763 	    } else {
1764 		step = DW_TS_FREQUENCY;
1765 	    }
1766 	} else if (prevstep == DW_WEEKLY_SELECT) {
1767 	    step = DW_TS_FREQUENCY;
1768 	} else if (prevstep == DW_PANEL_SIZE) {
1769 	    step = (create)? DW_SET_TYPE : DW_PANEL_MODE;
1770 	} else if (prevstep == DW_PANEL_VARS) {
1771 	    step = DW_PANEL_MODE;
1772 	} else if (prevstep == DW_CONFIRM) {
1773 	    if (dwinfo->structure == TIME_SERIES ||
1774 		dwinfo->structure == SPECIAL_TIME_SERIES) {
1775 		step = DW_STARTING_OBS;
1776 	    } else if (dwinfo->structure == STACKED_TIME_SERIES ||
1777 		       dwinfo->structure == STACKED_CROSS_SECTION) {
1778 		step = DW_PANEL_SIZE;
1779 	    } else {
1780 		step = DW_SET_TYPE;
1781 	    }
1782 	}
1783     }
1784 
1785 #if DWDEBUG
1786     fprintf(stderr, "dwiz_compute_step: returning step = %d\n", step);
1787 #endif
1788 
1789     return step;
1790 }
1791 
1792 /* clear a given notebook page, but leave the title string
1793    unchanged */
1794 
kill_dwiz_child(GtkWidget * w,gpointer p)1795 static void kill_dwiz_child (GtkWidget *w, gpointer p)
1796 {
1797     int t = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "title"));
1798 
1799     if (!t) {
1800 	gtk_widget_destroy(w);
1801     }
1802 }
1803 
clear_dwiz_page(GtkWidget * page)1804 static void clear_dwiz_page (GtkWidget *page)
1805 {
1806     gtk_container_foreach(GTK_CONTAINER(page),
1807 			  (GtkCallback) kill_dwiz_child,
1808 			  NULL);
1809 }
1810 
1811 /* select the appropriate buttons to show, depending on the
1812    step */
1813 
dwiz_button_visibility(GtkWidget * dlg,int step)1814 static void dwiz_button_visibility (GtkWidget *dlg, int step)
1815 {
1816     GtkWidget *cancel  = g_object_get_data(G_OBJECT(dlg), "cancel");
1817     GtkWidget *back    = g_object_get_data(G_OBJECT(dlg), "back");
1818     GtkWidget *forward = g_object_get_data(G_OBJECT(dlg), "forward");
1819     GtkWidget *apply   = g_object_get_data(G_OBJECT(dlg), "apply");
1820     GtkWidget *help    = g_object_get_data(G_OBJECT(dlg), "help");
1821 
1822     if (step == DW_SET_TYPE) {
1823 	gtk_widget_show(cancel);
1824 	gtk_widget_hide(back);
1825 	gtk_widget_show(forward);
1826 	gtk_widget_hide(apply);
1827     } else if (step == DW_CONFIRM) {
1828 	gtk_widget_show(cancel);
1829 	gtk_widget_show(back);
1830 	gtk_widget_hide(forward);
1831 	gtk_widget_show(apply);
1832     } else {
1833 	gtk_widget_show(cancel);
1834 	gtk_widget_show(back);
1835 	gtk_widget_show(forward);
1836 	gtk_widget_hide(apply);
1837     }
1838 
1839     if (step == DW_PANEL_MODE) {
1840 	gtk_widget_show(help);
1841     } else {
1842 	gtk_widget_hide(help);
1843     }
1844 }
1845 
add_editing_option(GtkWidget * vbox,gretlopt * flags)1846 static void add_editing_option (GtkWidget *vbox, gretlopt *flags)
1847 {
1848     if (g_object_get_data(G_OBJECT(vbox), "edbutton") == NULL) {
1849 	GtkWidget *hbox, *b;
1850 
1851 	hbox = gtk_hbox_new(FALSE, 5);
1852 	b = gretl_option_check_button(_("start entering data values"),
1853 				      flags, (gretlopt) DW_SSHEET);
1854 	gtk_box_pack_start(GTK_BOX(hbox), b, FALSE, FALSE, 5);
1855 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1856 	g_object_set_data(G_OBJECT(vbox), "edbutton", b);
1857     }
1858 }
1859 
1860 /* build the appropriate notebook page for the given step */
1861 
dwiz_prepare_page(GtkNotebook * nb,gint step,gint direction,DATASET * dwinfo)1862 static void dwiz_prepare_page (GtkNotebook *nb,
1863 			       gint step,
1864 			       gint direction,
1865 			       DATASET *dwinfo)
1866 {
1867     GtkWidget *page = gtk_notebook_get_nth_page(nb, step);
1868     GtkWidget *dlg = g_object_get_data(G_OBJECT(nb), "dlg");
1869     dw_opts *opts = g_object_get_data(G_OBJECT(dlg), "opts");
1870 
1871 #if DWDEBUG
1872     fprintf(stderr, "Got Prepare, step = %d\n", step);
1873 #endif
1874 
1875     if (step == DW_CONFIRM) {
1876 	/* the final page */
1877 	GtkWidget *w = g_object_get_data(G_OBJECT(page), "label");
1878 	gchar *ctxt;
1879 
1880 	ctxt = make_confirmation_text(dwinfo, opts);
1881 	gtk_label_set_text(GTK_LABEL(w), ctxt);
1882 	g_free(ctxt);
1883 	if (opts->flags & DW_CREATE) {
1884 	    if (newdata_nobs(dwinfo, opts) <= 100) {
1885 		add_editing_option(page, &opts->flags);
1886 	    }
1887 	}
1888     } else {
1889 	/* all other pages */
1890 	set_up_dw_opts(opts, step, dwinfo);
1891 	clear_dwiz_page(page);
1892 
1893 	if (opts->n_radios > 0) {
1894 	    if (step == DW_SET_TYPE && (opts->flags & DW_CREATE)) {
1895 		dwiz_new_dataset_combo(dwinfo, opts, page);
1896 	    } else {
1897 		dwiz_build_radios(step, dwinfo, opts, page);
1898 	    }
1899 	}
1900 
1901 	if (step == DW_STARTING_OBS) {
1902 	    add_startobs_spinner(page, dwinfo, direction);
1903 	    if (dataset != NULL && dataset->Z != NULL &&
1904 		dataset_is_daily(dwinfo)) {
1905 		maybe_add_missobs_purger(page, &opts->flags);
1906 	    }
1907 	} else if (step == DW_PANEL_SIZE) {
1908 	    dwiz_make_panel_spinners(opts, dwinfo, page);
1909 	} else if (step == DW_PANEL_VARS) {
1910 	    dwiz_panelvars_selector(opts, dwinfo, page);
1911 	}
1912     }
1913 
1914     gtk_widget_show_all(page);
1915     dwiz_button_visibility(dlg, step);
1916 }
1917 
dwiz_finalize(GtkWidget * dlg,DATASET * dwinfo,int cancel)1918 static void dwiz_finalize (GtkWidget *dlg, DATASET *dwinfo,
1919 			   int cancel)
1920 {
1921     dw_opts *opts = g_object_get_data(G_OBJECT(dlg), "opts");
1922 
1923     if (!cancel) {
1924 	if (opts->flags & DW_CREATE) {
1925 	    dwiz_replace_dataset(dwinfo, opts, dlg);
1926 	} else {
1927 	    dwiz_make_changes(dwinfo, opts, dlg);
1928 	}
1929     } else if (opts->flags & DW_CREATE) {
1930 	/* aborting creation of new dataset */
1931 	gui_clear_dataset();
1932     }
1933 
1934     gtk_widget_destroy(dlg);
1935 }
1936 
1937 /* callback for the Cancel button */
1938 
dwiz_cancel(GtkWidget * b,DATASET * dwinfo)1939 static void dwiz_cancel (GtkWidget *b, DATASET *dwinfo)
1940 {
1941     GtkWidget *dlg = g_object_get_data(G_OBJECT(b), "dlg");
1942 
1943     dwiz_finalize(dlg, dwinfo, 1);
1944 }
1945 
1946 /* callback for the Apply button */
1947 
dwiz_apply(GtkWidget * b,DATASET * dwinfo)1948 static void dwiz_apply (GtkWidget *b, DATASET *dwinfo)
1949 {
1950     GtkWidget *dlg = g_object_get_data(G_OBJECT(b), "dlg");
1951 
1952     dwiz_finalize(dlg, dwinfo, 0);
1953 }
1954 
1955 /* callback for the Back button */
1956 
dwiz_back(GtkWidget * b,GtkWidget * dlg)1957 static void dwiz_back (GtkWidget *b, GtkWidget *dlg)
1958 {
1959     GtkNotebook *nb = g_object_get_data(G_OBJECT(dlg), "nb");
1960     int pg = gtk_notebook_get_current_page(nb);
1961     DATASET *dwinfo = g_object_get_data(G_OBJECT(dlg), "dwinfo");
1962     dw_opts *opts = g_object_get_data(G_OBJECT(dlg), "opts");
1963 
1964     pg = dwiz_compute_step(pg, DW_BACK, dwinfo, opts);
1965     dwiz_prepare_page(nb, pg, DW_BACK, dwinfo);
1966     gtk_notebook_set_current_page(nb, pg);
1967 }
1968 
1969 /* callback for the Forward button */
1970 
dwiz_forward(GtkWidget * b,GtkWidget * dlg)1971 static void dwiz_forward (GtkWidget *b, GtkWidget *dlg)
1972 {
1973     GtkNotebook *nb = g_object_get_data(G_OBJECT(dlg), "nb");
1974     int pg = gtk_notebook_get_current_page(nb);
1975     DATASET *dwinfo = g_object_get_data(G_OBJECT(dlg), "dwinfo");
1976     dw_opts *opts = g_object_get_data(G_OBJECT(dlg), "opts");
1977     int newpg;
1978 
1979     if (pg == DW_SET_TYPE) {
1980 	if (any_panel(dwinfo) && !panel_possible(opts)) {
1981 	    /* special case: called for panel but it won't work */
1982 	    dwinfo->structure = dataset->structure;
1983 	    dwiz_prepare_page(nb, DW_SET_TYPE, DW_BACK, dwinfo);
1984 	    gtk_notebook_set_current_page(nb, DW_SET_TYPE);
1985 	    return;
1986 	}
1987 	if (opts->flags & DW_CREATE) {
1988 	    int i;
1989 
1990 	    for (i=0; i<4; i++) {
1991 		opts->dvals[i] = spinner_get_int(opts->dspin[i]);
1992 	    }
1993 	}
1994     }
1995 
1996     newpg = dwiz_compute_step(pg, DW_FORWARD, dwinfo, opts);
1997     if (newpg != pg) {
1998 	dwiz_prepare_page(nb, newpg, DW_FORWARD, dwinfo);
1999 	gtk_notebook_set_current_page(nb, newpg);
2000     }
2001 }
2002 
2003 /* initial setup for the final conformation text */
2004 
dwiz_confirm_label(GtkWidget * page)2005 static void dwiz_confirm_label (GtkWidget *page)
2006 {
2007     GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
2008     GtkWidget *label = gtk_label_new("");
2009 
2010     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
2011     gtk_box_pack_start(GTK_BOX(page), hbox, FALSE, FALSE, 5);
2012     g_object_set_data(G_OBJECT(page), "label", label);
2013 }
2014 
free_dwinfo(GtkWidget * w,DATASET * dwinfo)2015 static void free_dwinfo (GtkWidget *w, DATASET *dwinfo)
2016 {
2017     free(dwinfo);
2018 }
2019 
free_dw_opts(GtkWidget * w,dw_opts * opts)2020 static void free_dw_opts (GtkWidget *w, dw_opts *opts)
2021 {
2022     if (opts->vlist != NULL) {
2023 	g_list_free(opts->vlist);
2024     }
2025     free(opts);
2026 }
2027 
2028 /* Create all the buttons that we'll need.  Which of these will
2029    actually be shown depends on the step */
2030 
build_dwiz_buttons(GtkWidget * dlg,DATASET * dwinfo)2031 static void build_dwiz_buttons (GtkWidget *dlg, DATASET *dwinfo)
2032 {
2033     GtkWidget *hbox = gtk_dialog_get_action_area(GTK_DIALOG(dlg));
2034     GtkWidget *b;
2035 
2036     /* "Cancel" button */
2037     b = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
2038     g_object_set_data(G_OBJECT(b), "dlg", dlg);
2039     g_signal_connect(G_OBJECT(b), "clicked",
2040 		     G_CALLBACK(dwiz_cancel),
2041 		     dwinfo);
2042     gtk_container_add(GTK_CONTAINER(hbox), b);
2043     g_object_set_data(G_OBJECT(dlg), "cancel", b);
2044 
2045     /* "Back" button */
2046     b = gtk_button_new_from_stock(GTK_STOCK_GO_BACK);
2047     g_object_set_data(G_OBJECT(b), "dlg", dlg);
2048     g_signal_connect(G_OBJECT(b), "clicked",
2049 		     G_CALLBACK(dwiz_back),
2050 		     dlg);
2051     gtk_container_add(GTK_CONTAINER(hbox), b);
2052     g_object_set_data(G_OBJECT(dlg), "back", b);
2053 
2054     /* "Forward" button */
2055     b = gtk_button_new_from_stock(GTK_STOCK_GO_FORWARD);
2056     g_object_set_data(G_OBJECT(b), "dlg", dlg);
2057     g_signal_connect(G_OBJECT(b), "clicked",
2058 		     G_CALLBACK(dwiz_forward),
2059 		     dlg);
2060     gtk_container_add(GTK_CONTAINER(hbox), b);
2061     g_object_set_data(G_OBJECT(dlg), "forward", b);
2062 
2063     /* "Apply" button */
2064     b = gtk_button_new_from_stock(GTK_STOCK_APPLY);
2065     g_object_set_data(G_OBJECT(b), "dlg", dlg);
2066     g_signal_connect(G_OBJECT(b), "clicked",
2067 		     G_CALLBACK(dwiz_apply),
2068 		     dwinfo);
2069     gtk_container_add(GTK_CONTAINER(hbox), b);
2070     g_object_set_data(G_OBJECT(dlg), "apply", b);
2071 
2072     /* Help button for panel mode selection */
2073     b = context_help_button(hbox, PANEL_MODE);
2074     g_object_set_data(G_OBJECT(dlg), "help", b);
2075 }
2076 
2077 /* the title for the top of a given notebook page */
2078 
dwiz_page_add_title(GtkWidget * vbox,int i,int smax)2079 static void dwiz_page_add_title (GtkWidget *vbox, int i, int smax)
2080 {
2081     GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
2082     GtkWidget *label= gtk_label_new(NULL);
2083     gchar *buf;
2084 
2085     buf = g_markup_printf_escaped("<span face=\"sans\" "
2086 				  "weight=\"bold\" "
2087 				  "color=\"white\" "
2088 				  "background=\"#6C7B8A\" "
2089 				  "size=\"x-large\"> %-*s </span>",
2090 				  smax, _(wizcode_string(i)));
2091     gtk_label_set_markup(GTK_LABEL(label), buf);
2092     g_free(buf);
2093     g_object_set_data(G_OBJECT(hbox), "title", GINT_TO_POINTER(1));
2094     gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
2095     gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
2096 }
2097 
dw_opts_new(int create)2098 static dw_opts *dw_opts_new (int create)
2099 {
2100     dw_opts *opts = mymalloc(sizeof *opts);
2101 
2102     if (opts != NULL) {
2103 	opts->flags = (create)? DW_CREATE : 0;
2104 	opts->vlist = NULL;
2105 	opts->uid = opts->tid = 0;
2106 	if (create) {
2107 	    int i;
2108 
2109 	    for (i=0; i<4; i++) {
2110 		opts->dvals[i] = 0;
2111 	    }
2112 	}
2113     }
2114 
2115     return opts;
2116 }
2117 
2118 /* The main driver for the "wizard".  If "create" is non-zero that
2119    means we're setting the structure for a newly created dataset,
2120    otherwise we're modifying the structure of an existing dataset.
2121 */
2122 
data_structure_wizard(int create)2123 static void data_structure_wizard (int create)
2124 {
2125     GtkWidget *dialog;
2126     GtkWidget *vbox;
2127     GtkWidget *nb;
2128     GtkWidget *page;
2129     DATASET *dwinfo;
2130     dw_opts *opts;
2131     int i, n, smax = 0;
2132 
2133     dwinfo = datainfo_new();
2134     if (dwinfo == NULL) {
2135 	nomem();
2136 	return;
2137     }
2138 
2139     opts = dw_opts_new(create);
2140     if (opts == NULL) {
2141 	free(dwinfo);
2142 	return;
2143     }
2144 
2145     /* copy current relevant info */
2146     dwinfo_init(dwinfo);
2147 
2148     /* GTK dialog wrapper */
2149     dialog = gretl_dialog_new(_("Data structure wizard"), mdata->main,
2150 			      GRETL_DLG_QUASI_MODAL);
2151     g_object_set_data(G_OBJECT(dialog), "dwinfo", dwinfo);
2152     g_object_set_data(G_OBJECT(dialog), "opts", opts);
2153     vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
2154 
2155     /* notebook to hold the steps */
2156     nb = gtk_notebook_new();
2157     g_object_set_data(G_OBJECT(nb), "dlg", dialog);
2158     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(nb), FALSE);
2159     gtk_notebook_set_show_border(GTK_NOTEBOOK(nb), FALSE);
2160     gtk_container_add(GTK_CONTAINER(vbox), nb);
2161 
2162     g_object_set_data(G_OBJECT(dialog), "nb", nb);
2163 
2164     /* free allocated memory on exit */
2165     g_signal_connect(G_OBJECT(dialog), "destroy",
2166 		     G_CALLBACK(free_dwinfo),
2167 		     dwinfo);
2168     g_signal_connect(G_OBJECT(dialog), "destroy",
2169 		     G_CALLBACK(free_dw_opts),
2170 		     opts);
2171 
2172     for (i=0; i<=DW_CONFIRM; i++) {
2173 	n = g_utf8_strlen(_(wizcode_string(i)), -1);
2174 	if (n > smax) {
2175 	    smax = n;
2176 	}
2177     }
2178 
2179     /* make all the notebook pages */
2180     for (i=0; i<=DW_CONFIRM; i++) {
2181 	page = gtk_vbox_new(FALSE, 5);
2182 	gtk_container_set_border_width(GTK_CONTAINER(page), 5);
2183 	dwiz_page_add_title(page, i, smax);
2184 	gtk_notebook_append_page(GTK_NOTEBOOK(nb), page, NULL);
2185 	if (i == DW_CONFIRM) {
2186 	    dwiz_confirm_label(page);
2187 	}
2188 	gtk_widget_show(page);
2189     }
2190 
2191     build_dwiz_buttons(dialog, dwinfo);
2192     gtk_widget_show(nb);
2193 
2194     dwiz_prepare_page(GTK_NOTEBOOK(nb), 0, DW_FORWARD, dwinfo);
2195     gtk_notebook_set_current_page(GTK_NOTEBOOK(nb), 0);
2196 
2197     /* note: we can't use gtk_widget_show_all() here
2198        because component widgets may be displayed
2199        selectively */
2200     gtk_widget_show(dialog);
2201 }
2202 
2203 /* public interface */
2204 
2205 /* Take the user through a series of dialogs to define the structure
2206    of the data set, either when creating a new data set or by way of
2207    restructuring an existing data set.
2208 */
2209 
data_structure_dialog(void)2210 void data_structure_dialog (void)
2211 {
2212     data_structure_wizard(0);
2213 }
2214 
new_data_structure_dialog(void)2215 void new_data_structure_dialog (void)
2216 {
2217     data_structure_wizard(1);
2218 }
2219