Remove some unused variables
[pspp-builds.git] / src / ui / gui / psppire-var-sheet.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18 #include "psppire-var-sheet.h"
19 #include <ui/gui/sheet/psppire-axis-impl.h>
20
21 #include "helper.h"
22
23 #include "customentry.h"
24 #include <data/variable.h>
25 #include "psppire-var-store.h"
26
27 #include <gettext.h>
28 #define _(msgid) gettext (msgid)
29 #define N_(msgid) msgid
30
31
32 static void psppire_var_sheet_class_init  (PsppireVarSheetClass *klass);
33 static void psppire_var_sheet_init        (PsppireVarSheet      *vs);
34
35 enum
36   {
37     PSPPIRE_VAR_SHEET_MAY_CREATE_VARS = 1
38   };
39
40 GType
41 psppire_var_sheet_get_type (void)
42 {
43   static GType vs_type = 0;
44
45   if (!vs_type)
46     {
47       static const GTypeInfo vs_info =
48       {
49         sizeof (PsppireVarSheetClass),
50         NULL, /* base_init */
51         NULL, /* base_finalize */
52         (GClassInitFunc) psppire_var_sheet_class_init,
53         NULL, /* class_finalize */
54         NULL, /* class_data */
55         sizeof (PsppireVarSheet),
56         0,
57         (GInstanceInitFunc) psppire_var_sheet_init,
58       };
59
60       vs_type = g_type_register_static (PSPPIRE_TYPE_SHEET, "PsppireVarSheet",
61                                         &vs_info, 0);
62     }
63
64   return vs_type;
65 }
66
67 static GObjectClass * parent_class = NULL;
68
69 static void
70 psppire_var_sheet_dispose (GObject *obj)
71 {
72   PsppireVarSheet *vs = (PsppireVarSheet *)obj;
73
74   if (vs->dispose_has_run)
75     return;
76
77   /* Make sure dispose does not run twice. */
78   vs->dispose_has_run = TRUE;
79
80   /* Chain up to the parent class */
81   G_OBJECT_CLASS (parent_class)->dispose (obj);
82 }
83
84 static void
85 psppire_var_sheet_finalize (GObject *obj)
86 {
87    /* Chain up to the parent class */
88    G_OBJECT_CLASS (parent_class)->finalize (obj);
89 }
90
91
92 struct column_parameters
93 {
94   gchar label[20];
95   gint width ;
96 };
97
98 #define n_ALIGNMENTS 3
99
100 const gchar *const alignments[n_ALIGNMENTS + 1]={
101   N_("Left"),
102   N_("Right"),
103   N_("Center"),
104   0
105 };
106
107 const gchar *const measures[n_MEASURES + 1]={
108   N_("Nominal"),
109   N_("Ordinal"),
110   N_("Scale"),
111   0
112 };
113
114
115
116 /* Create a list store from an array of strings */
117 static GtkListStore *
118 create_label_list (const gchar *const *labels)
119 {
120   const gchar *s;
121   gint i = 0;
122   GtkTreeIter iter;
123
124   GtkListStore *list_store = gtk_list_store_new (1, G_TYPE_STRING);
125
126   while ( (s = labels[i++]))
127     {
128       gtk_list_store_append (list_store, &iter);
129       gtk_list_store_set (list_store, &iter,
130                           0, gettext (s),
131                           -1);
132     }
133
134   return list_store;
135 }
136
137
138 static void
139 psppire_var_sheet_set_property (GObject      *object,
140                                 guint         property_id,
141                                 const GValue *value,
142                                 GParamSpec   *pspec)
143 {
144   PsppireVarSheet *self = (PsppireVarSheet *) object;
145
146   switch (property_id)
147     {
148     case PSPPIRE_VAR_SHEET_MAY_CREATE_VARS:
149       self->may_create_vars = g_value_get_boolean (value);
150       break;
151
152     default:
153       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
154       break;
155     }
156 }
157
158 static void
159 psppire_var_sheet_get_property (GObject      *object,
160                                 guint         property_id,
161                                 GValue       *value,
162                                 GParamSpec   *pspec)
163 {
164   PsppireVarSheet *self = (PsppireVarSheet *) object;
165
166   switch (property_id)
167     {
168     case PSPPIRE_VAR_SHEET_MAY_CREATE_VARS:
169       g_value_set_boolean (value, self->may_create_vars);
170       break;
171
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
174       break;
175     }
176 }
177
178
179
180 static void
181 psppire_var_sheet_class_init (PsppireVarSheetClass *klass)
182 {
183   GObjectClass *object_class = G_OBJECT_CLASS (klass);
184   GParamSpec *pspec;
185
186   parent_class = g_type_class_peek_parent (klass);
187
188   object_class->dispose = psppire_var_sheet_dispose;
189   object_class->finalize = psppire_var_sheet_finalize;
190   object_class->set_property = psppire_var_sheet_set_property;
191   object_class->get_property = psppire_var_sheet_get_property;
192
193   pspec = g_param_spec_boolean ("may-create-vars",
194                                 "May create variables",
195                                 "Whether the user may create more variables",
196                                 TRUE,
197                                 G_PARAM_READWRITE);
198   g_object_class_install_property (object_class,
199                                    PSPPIRE_VAR_SHEET_MAY_CREATE_VARS,
200                                    pspec);
201
202   klass->measure_list = create_label_list (measures);
203   klass->alignment_list = create_label_list (alignments);
204 }
205
206
207
208 /* Callback for when the alignment combo box
209    item is selected */
210 static void
211 change_alignment (GtkComboBox *cb,
212                   struct variable *var)
213 {
214   gint active_item = gtk_combo_box_get_active (cb);
215
216   if ( active_item < 0 ) return ;
217
218   var_set_alignment (var, active_item);
219 }
220
221
222
223 /* Callback for when the measure combo box
224    item is selected */
225 static void
226 change_measure (GtkComboBox *cb,
227                 struct variable *var)
228 {
229   gint active_item = gtk_combo_box_get_active (cb);
230
231   if ( active_item < 0 ) return ;
232
233   var_set_measure (var, active_item);
234 }
235
236
237 /* Moves the focus to a new cell.
238    Returns TRUE iff the move should be disallowed */
239 static gboolean
240 traverse_cell_callback (PsppireSheet *sheet,
241                         const PsppireSheetCell *existing_cell,
242                         PsppireSheetCell *new_cell)
243 {
244   PsppireVarSheet *var_sheet = PSPPIRE_VAR_SHEET (sheet);
245   PsppireVarStore *var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
246
247   gint n_vars = psppire_var_store_get_var_cnt (var_store);
248
249   if (new_cell->row >= n_vars && !var_sheet->may_create_vars)
250     return TRUE;
251
252   if ( existing_cell->row == n_vars && new_cell->row >= n_vars)
253     {
254       GtkEntry *entry = psppire_sheet_get_entry (sheet);
255
256       const gchar *name = gtk_entry_get_text (entry);
257
258       if (! psppire_dict_check_name (var_store->dict, name, TRUE))
259         return TRUE;
260
261       psppire_dict_insert_variable (var_store->dict, existing_cell->row, name);
262
263       return FALSE;
264     }
265
266
267   /* If the destination cell is outside the current  variables, then
268      automatically create variables for the new rows.
269   */
270   if ( ((new_cell->row > n_vars) ||
271         (new_cell->row == n_vars &&
272          new_cell->col != PSPPIRE_VAR_STORE_COL_NAME)) )
273     {
274       gint i;
275       for ( i = n_vars ; i <= new_cell->row; ++i )
276         psppire_dict_insert_variable (var_store->dict, i, NULL);
277     }
278
279   return FALSE;
280 }
281
282
283
284
285 /*
286    Callback whenever the active cell changes on the var sheet.
287 */
288 static void
289 var_sheet_change_active_cell (PsppireVarSheet *vs,
290                               gint row, gint column,
291                               gint oldrow, gint oldcolumn,
292                               gpointer data)
293 {
294   PsppireSheetCellAttr attributes;
295   PsppireVarStore *var_store;
296   PsppireVarSheetClass *vs_class =
297     PSPPIRE_VAR_SHEET_CLASS(G_OBJECT_GET_CLASS (vs));
298
299   struct variable *var ;
300   PsppireSheet *sheet = PSPPIRE_SHEET (vs);
301
302   g_return_if_fail (sheet != NULL);
303
304   var_store = PSPPIRE_VAR_STORE (psppire_sheet_get_model (sheet));
305
306   g_assert (var_store);
307
308   g_return_if_fail (oldcolumn == PSPPIRE_VAR_STORE_COL_NAME ||
309                     row < psppire_var_store_get_var_cnt (var_store));
310
311   psppire_sheet_get_attributes (sheet, row, column, &attributes);
312
313   var = psppire_var_store_get_var (var_store, row);
314
315   switch (column)
316     {
317     case PSPPIRE_VAR_STORE_COL_ALIGN:
318       {
319         GtkEntry *entry;
320         static GtkListStore *list_store = NULL;
321         GtkComboBoxEntry *cbe;
322         psppire_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
323         entry = psppire_sheet_get_entry (sheet);
324         cbe = GTK_COMBO_BOX_ENTRY (GTK_WIDGET (entry)->parent);
325
326         if ( ! list_store) list_store = create_label_list (alignments);
327
328         gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
329                                 GTK_TREE_MODEL (vs_class->alignment_list));
330
331         gtk_combo_box_entry_set_text_column (cbe, 0);
332
333         g_signal_connect (G_OBJECT (cbe),"changed",
334                          G_CALLBACK (change_alignment), var);
335       }
336       break;
337
338     case PSPPIRE_VAR_STORE_COL_MEASURE:
339       {
340         GtkEntry *entry;
341         GtkComboBoxEntry *cbe;
342         psppire_sheet_change_entry (sheet, GTK_TYPE_COMBO_BOX_ENTRY);
343         entry = psppire_sheet_get_entry (sheet);
344         cbe = GTK_COMBO_BOX_ENTRY (GTK_WIDGET (entry)->parent);
345
346         gtk_combo_box_set_model (GTK_COMBO_BOX (cbe),
347                                 GTK_TREE_MODEL (vs_class->measure_list));
348
349         gtk_combo_box_entry_set_text_column (cbe, 0);
350
351         g_signal_connect (G_OBJECT (cbe),"changed",
352                           G_CALLBACK (change_measure), var);
353       }
354       break;
355
356     case PSPPIRE_VAR_STORE_COL_VALUES:
357       {
358         PsppireCustomEntry *customEntry;
359
360         psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
361
362         customEntry =
363           PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
364
365         if ( var_is_long_string (var))
366           g_object_set (customEntry,
367                         "editable", FALSE,
368                         NULL);
369
370         val_labs_dialog_set_target_variable (vs->val_labs_dialog, var);
371
372         g_signal_connect_swapped (customEntry,
373                                   "clicked",
374                                   G_CALLBACK (val_labs_dialog_show),
375                                   vs->val_labs_dialog);
376       }
377       break;
378
379     case PSPPIRE_VAR_STORE_COL_MISSING:
380       {
381         PsppireCustomEntry *customEntry;
382
383         psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
384
385         customEntry =
386           PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
387
388         if ( var_is_long_string (var))
389           g_object_set (customEntry,
390                         "editable", FALSE,
391                         NULL);
392
393
394         vs->missing_val_dialog->pv =
395           psppire_var_store_get_var (var_store, row);
396
397         g_signal_connect_swapped (customEntry,
398                                   "clicked",
399                                   G_CALLBACK (missing_val_dialog_show),
400                                   vs->missing_val_dialog);
401       }
402       break;
403
404     case PSPPIRE_VAR_STORE_COL_TYPE:
405       {
406         PsppireCustomEntry *customEntry;
407
408         psppire_sheet_change_entry (sheet, PSPPIRE_CUSTOM_ENTRY_TYPE);
409
410         customEntry =
411           PSPPIRE_CUSTOM_ENTRY (psppire_sheet_get_entry (sheet));
412
413
414         /* Popup the Variable Type dialog box */
415         vs->var_type_dialog->pv = var;
416
417         g_signal_connect_swapped (customEntry,
418                                  "clicked",
419                                  G_CALLBACK (var_type_dialog_show),
420                                   vs->var_type_dialog);
421       }
422       break;
423
424     case PSPPIRE_VAR_STORE_COL_WIDTH:
425     case PSPPIRE_VAR_STORE_COL_DECIMALS:
426     case PSPPIRE_VAR_STORE_COL_COLUMNS:
427       {
428         if ( attributes.is_editable)
429           {
430             gint r_min, r_max;
431
432             const gchar *s = psppire_sheet_cell_get_text (sheet, row, column);
433
434             if (s)
435               {
436                 GtkSpinButton *spinButton ;
437                 const gint current_value  = g_strtod (s, NULL);
438                 GtkObject *adj ;
439
440                 const struct fmt_spec *fmt = var_get_write_format (var);
441                 switch (column)
442                   {
443                   case PSPPIRE_VAR_STORE_COL_WIDTH:
444                     r_min = MAX (fmt->d + 1, fmt_min_output_width (fmt->type));
445                     r_max = fmt_max_output_width (fmt->type);
446                     break;
447                   case PSPPIRE_VAR_STORE_COL_DECIMALS:
448                     r_min = 0 ;
449                     r_max = fmt_max_output_decimals (fmt->type, fmt->w);
450                     break;
451                   case PSPPIRE_VAR_STORE_COL_COLUMNS:
452                     r_min = 1;
453                     r_max = 255 ; /* Is this a sensible value ? */
454                     break;
455                   default:
456                     g_assert_not_reached ();
457                   }
458
459                 adj = gtk_adjustment_new (current_value,
460                                          r_min, r_max,
461                                          1.0, 1.0, 1.0 /* steps */
462                                          );
463
464                 psppire_sheet_change_entry (sheet, GTK_TYPE_SPIN_BUTTON);
465
466                 spinButton =
467                   GTK_SPIN_BUTTON (psppire_sheet_get_entry (sheet));
468
469                 gtk_spin_button_set_adjustment (spinButton, GTK_ADJUSTMENT (adj));
470                 gtk_spin_button_set_digits (spinButton, 0);
471               }
472           }
473       }
474       break;
475
476     default:
477       psppire_sheet_change_entry (sheet, GTK_TYPE_ENTRY);
478       break;
479     }
480 }
481
482
483 static void
484 psppire_var_sheet_init (PsppireVarSheet *vs)
485 {
486   GtkBuilder *builder = builder_new ("data-editor.ui");
487
488   vs->val_labs_dialog = val_labs_dialog_create (builder);
489   vs->missing_val_dialog = missing_val_dialog_create (builder);
490   vs->var_type_dialog = var_type_dialog_create (builder);
491
492   connect_help (builder);
493
494   g_object_unref (builder);
495
496   vs->dispose_has_run = FALSE;
497   vs->may_create_vars = TRUE;
498
499   g_signal_connect (vs, "activate",
500                     G_CALLBACK (var_sheet_change_active_cell),
501                     NULL);
502
503   g_signal_connect (vs, "traverse",
504                     G_CALLBACK (traverse_cell_callback), NULL);
505 }
506
507
508 static const struct column_parameters column_def[] = {
509   { N_("Name"),    80},
510   { N_("Type"),    100},
511   { N_("Width"),   57},
512   { N_("Decimals"),91},
513   { N_("Label"),   95},
514   { N_("Values"),  103},
515   { N_("Missing"), 95},
516   { N_("Columns"), 80},
517   { N_("Align"),   69},
518   { N_("Measure"), 99},
519 };
520
521 GtkWidget*
522 psppire_var_sheet_new (void)
523 {
524   gint i;
525   PsppireAxisImpl *ha = psppire_axis_impl_new ();
526   PsppireAxisImpl *va = psppire_axis_impl_new ();
527
528   GtkWidget *w = g_object_new (psppire_var_sheet_get_type (), NULL);
529
530   for (i = 0 ; i < 10 ; ++i)
531     psppire_axis_impl_append (ha, column_def[i].width);
532
533   g_object_set (va,
534                 "default-size", 25,
535                 NULL);
536
537   g_object_set (ha, "minimum-extent", 0,
538                 NULL);
539
540   g_object_set (w,
541                 "horizontal-axis", ha,
542                 "vertical-axis", va,
543                 NULL);
544
545   return w;
546 }