Cleaned up GUI, by objectifying the data editor. Removed a number of global variables.
[pspp-builds.git] / src / ui / gui / data-editor.c
1 /*
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2006  Free Software Foundation
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 2 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, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18     02110-1301, USA. */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <gettext.h>
23
24 #include <glade/glade.h>
25 #include <gtk/gtk.h>
26
27
28 #include <gtksheet/gtksheet.h>
29
30 #include "helper.h"
31 #include "about.h"
32
33 #define _(msgid) gettext (msgid)
34 #define N_(msgid) msgid
35
36 #include "data-editor.h"
37 #include "syntax-editor.h"
38 #include "window-manager.h"
39
40 #include "psppire-data-store.h"
41 #include "psppire-var-store.h"
42
43 /* Switch between the VAR SHEET and the DATA SHEET */
44 enum {PAGE_DATA_SHEET = 0, PAGE_VAR_SHEET};
45
46 static gboolean click2column (GtkWidget *w, gint col, gpointer data);
47
48 static gboolean click2row (GtkWidget *w, gint row, gpointer data);
49
50
51 static void select_sheet (struct data_editor *de, guint page_num);
52
53
54 static void data_var_select (GtkNotebook *notebook,
55                             GtkNotebookPage *page,
56                             guint page_num,
57                             gpointer user_data);
58
59 static void status_bar_activate (GtkCheckMenuItem *, gpointer);
60
61 static void grid_lines_activate (GtkCheckMenuItem *, gpointer);
62
63 static void data_sheet_activate (GtkCheckMenuItem *, gpointer);
64
65 static void variable_sheet_activate (GtkCheckMenuItem *, gpointer );
66
67 static void fonts_activate (GtkMenuItem *, gpointer);
68
69 static void value_labels_activate (GtkCheckMenuItem *, gpointer);
70 static void value_labels_toggled (GtkToggleToolButton *, gpointer);
71
72
73 static void file_quit (GtkCheckMenuItem *, gpointer );
74
75
76 /*
77   Create a new data editor.
78 */
79 struct data_editor *
80 new_data_editor (void)
81 {
82   struct data_editor *de ;
83   struct editor_window *e;
84
85   de = g_malloc (sizeof (*de));
86
87   e = (struct editor_window *) de;
88
89   de->xml = glade_xml_new (PKGDATADIR "/data-editor.glade", NULL, NULL);
90
91   e->window = get_widget_assert (de->xml, "data_editor");
92
93   g_signal_connect (get_widget_assert (de->xml,"file_new_data"),
94                     "activate",
95                     G_CALLBACK (new_data_window),
96                     e->window);
97
98   g_signal_connect (get_widget_assert (de->xml,"file_open_data"),
99                     "activate",
100                     G_CALLBACK (open_data_window),
101                     e->window);
102
103   g_signal_connect (get_widget_assert (de->xml,"file_new_syntax"),
104                     "activate",
105                     G_CALLBACK (new_syntax_window),
106                     e->window);
107
108   g_signal_connect (get_widget_assert (de->xml,"file_open_syntax"),
109                     "activate",
110                     G_CALLBACK (open_syntax_window),
111                     e->window);
112
113   g_signal_connect (get_widget_assert (de->xml,"help_about"),
114                     "activate",
115                     G_CALLBACK (about_new),
116                     e->window);
117
118
119   g_signal_connect (get_widget_assert (de->xml,"data_sheet"),
120                     "double-click-column",
121                     G_CALLBACK (click2column),
122                     de);
123
124
125   g_signal_connect (get_widget_assert (de->xml, "variable_sheet"),
126                     "double-click-row",
127                     GTK_SIGNAL_FUNC (click2row),
128                     de);
129
130
131   g_signal_connect (get_widget_assert (de->xml, "notebook"),
132                     "switch-page",
133                     G_CALLBACK (data_var_select), de);
134
135
136
137   g_signal_connect (get_widget_assert (de->xml, "view_statusbar"),
138                     "activate",
139                     G_CALLBACK (status_bar_activate), de);
140
141
142   g_signal_connect (get_widget_assert (de->xml, "view_gridlines"),
143                     "activate",
144                     G_CALLBACK (grid_lines_activate), de);
145
146
147
148   g_signal_connect (get_widget_assert (de->xml, "view_data"),
149                     "activate",
150                     G_CALLBACK (data_sheet_activate), de);
151
152   g_signal_connect (get_widget_assert (de->xml, "view_variables"),
153                     "activate",
154                     G_CALLBACK (variable_sheet_activate), de);
155
156
157
158   g_signal_connect (get_widget_assert (de->xml, "view_fonts"),
159                     "activate",
160                     G_CALLBACK (fonts_activate), de);
161
162
163
164   g_signal_connect (get_widget_assert (de->xml, "view_valuelabels"),
165                     "activate",
166                     G_CALLBACK (value_labels_activate), de);
167
168
169   g_signal_connect (get_widget_assert (de->xml, "togglebutton-value-labels"),
170                     "toggled",
171                     G_CALLBACK (value_labels_toggled), de);
172
173
174   g_signal_connect (get_widget_assert (de->xml, "file_quit"),
175                     "activate",
176                     G_CALLBACK (file_quit), de);
177
178
179   select_sheet (de, PAGE_DATA_SHEET);
180
181   return de;
182 }
183
184
185 /* Callback which occurs when the var sheet's row title
186    button is double clicked */
187 static gboolean
188 click2row (GtkWidget *w, gint row, gpointer data)
189 {
190   struct data_editor *de = data;
191
192   gint current_row, current_column;
193
194   GtkWidget *data_sheet  = get_widget_assert (de->xml, "data_sheet");
195
196   data_editor_select_sheet (de, PAGE_DATA_SHEET);
197
198   gtk_sheet_get_active_cell (GTK_SHEET(data_sheet),
199                              &current_row, &current_column);
200
201   gtk_sheet_set_active_cell (GTK_SHEET(data_sheet), current_row, row);
202
203   return FALSE;
204 }
205
206
207 /* Callback which occurs when the data sheet's column title
208    is double clicked */
209 static gboolean
210 click2column (GtkWidget *w, gint col, gpointer data)
211 {
212   struct data_editor *de = data;
213
214   gint current_row, current_column;
215
216   GtkWidget *var_sheet  = get_widget_assert (de->xml, "variable_sheet");
217
218   data_editor_select_sheet (de, PAGE_VAR_SHEET);
219
220   gtk_sheet_get_active_cell (GTK_SHEET(var_sheet),
221                              &current_row, &current_column);
222
223   gtk_sheet_set_active_cell (GTK_SHEET(var_sheet), col, current_column);
224
225   return FALSE;
226 }
227
228
229
230
231 void
232 new_data_window (GtkMenuItem *menuitem, gpointer parent)
233 {
234   window_create (WINDOW_DATA, NULL);
235 }
236
237
238 static void
239 select_sheet (struct data_editor *de, guint page_num)
240 {
241   GtkWidget *insert_variable = get_widget_assert (de->xml, "insert-variable");
242   GtkWidget *insert_cases = get_widget_assert (de->xml, "insert-cases");
243
244   GtkWidget *view_data = get_widget_assert (de->xml, "view_data");
245   GtkWidget *view_variables = get_widget_assert (de->xml, "view_variables");
246
247   switch (page_num)
248     {
249     case PAGE_VAR_SHEET:
250       gtk_widget_hide (view_variables);
251       gtk_widget_show (view_data);
252       gtk_widget_set_sensitive (insert_variable, TRUE);
253       gtk_widget_set_sensitive (insert_cases, FALSE);
254       break;
255     case PAGE_DATA_SHEET:
256       gtk_widget_show (view_variables);
257       gtk_widget_hide (view_data);
258       gtk_widget_set_sensitive (insert_variable, FALSE);
259       gtk_widget_set_sensitive (insert_cases, TRUE);
260       break;
261     default:
262       g_assert_not_reached ();
263       break;
264     }
265 }
266
267
268 static void
269 data_var_select (GtkNotebook *notebook,
270                 GtkNotebookPage *page,
271                 guint page_num,
272                 gpointer user_data)
273 {
274   struct data_editor *de = user_data;
275
276   select_sheet (de, page_num);
277 }
278
279
280
281
282 void
283 data_editor_select_sheet (struct data_editor *de, gint page)
284 {
285   gtk_notebook_set_current_page
286    (
287     GTK_NOTEBOOK (get_widget_assert (de->xml,"notebook")), page
288     );
289 }
290
291
292 void
293 open_data_window (GtkMenuItem *menuitem, gpointer parent)
294 {
295   bool finished = FALSE;
296
297   GtkWidget *dialog;
298
299   GtkFileFilter *filter ;
300
301   dialog = gtk_file_chooser_dialog_new (_("Open"),
302                                         GTK_WINDOW (parent),
303                                         GTK_FILE_CHOOSER_ACTION_OPEN,
304                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
305                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
306                                         NULL);
307
308   filter = gtk_file_filter_new ();
309   gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
310   gtk_file_filter_add_pattern (filter, "*.sav");
311   gtk_file_filter_add_pattern (filter, "*.SAV");
312   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
313
314   filter = gtk_file_filter_new ();
315   gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
316   gtk_file_filter_add_pattern (filter, "*.por");
317   gtk_file_filter_add_pattern (filter, "*.POR");
318   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
319
320   filter = gtk_file_filter_new ();
321   gtk_file_filter_set_name (filter, _("All Files"));
322   gtk_file_filter_add_pattern (filter, "*");
323   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
324
325   do {
326
327     if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
328       {
329         gchar *file_name =
330           gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
331
332         g_free (file_name);
333       }
334     else
335       finished = TRUE;
336
337   } while ( ! finished ) ;
338
339   gtk_widget_destroy (dialog);
340 }
341
342
343
344
345 static void
346 status_bar_activate (GtkCheckMenuItem *menuitem, gpointer data)
347 {
348   struct data_editor *de = data;
349   GtkWidget *statusbar = get_widget_assert (de->xml, "statusbar");
350
351   if ( gtk_check_menu_item_get_active (menuitem) )
352     gtk_widget_show (statusbar);
353   else
354     gtk_widget_hide (statusbar);
355 }
356
357
358
359
360 static void
361 grid_lines_activate (GtkCheckMenuItem *menuitem, gpointer data)
362 {
363   struct data_editor *de = data;
364   const bool grid_visible = gtk_check_menu_item_get_active (menuitem);
365
366   gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml,
367                                                      "variable_sheet")),
368                        grid_visible);
369
370   gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml, "data_sheet")),
371                        grid_visible);
372 }
373
374
375
376 static void
377 data_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
378 {
379   struct data_editor *de = data;
380
381   data_editor_select_sheet (de, PAGE_DATA_SHEET);
382 }
383
384
385 static void
386 variable_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
387 {
388   struct data_editor *de = data;
389
390   data_editor_select_sheet (de, PAGE_VAR_SHEET);
391 }
392
393
394 static void
395 fonts_activate (GtkMenuItem *menuitem, gpointer data)
396 {
397   struct data_editor *de = data;
398   GtkWidget *dialog =
399     gtk_font_selection_dialog_new (_("Font Selection"));
400
401   gtk_window_set_transient_for (GTK_WINDOW (dialog),
402                                 GTK_WINDOW (get_widget_assert (de->xml,
403                                                                "data_editor")));
404   if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
405     {
406       GtkSheet *data_sheet =
407         GTK_SHEET(get_widget_assert (de->xml, "data_sheet"));
408
409       GtkSheet *var_sheet =
410         GTK_SHEET(get_widget_assert (de->xml, "variable_sheet"));
411
412       PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
413       PsppireVarStore *vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
414
415       const gchar *font = gtk_font_selection_dialog_get_font_name
416         (GTK_FONT_SELECTION_DIALOG (dialog));
417
418       PangoFontDescription* font_desc =
419         pango_font_description_from_string (font);
420
421       psppire_var_store_set_font (vs, font_desc);
422       psppire_data_store_set_font (ds, font_desc);
423     }
424
425   gtk_widget_hide (dialog);
426 }
427
428
429 /* The next two callbacks are mutually co-operative */
430
431 /* Callback for the value labels menu item */
432 static void
433 value_labels_activate (GtkCheckMenuItem *menuitem, gpointer data)
434 {
435   struct data_editor *de = data;
436
437   GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
438
439   GtkToggleToolButton *tb =
440     GTK_TOGGLE_TOOL_BUTTON (get_widget_assert (de->xml,
441                                                "togglebutton-value-labels"));
442
443   PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
444
445   gboolean show_value_labels = gtk_check_menu_item_get_active (menuitem);
446
447   gtk_toggle_tool_button_set_active (tb, show_value_labels);
448
449   psppire_data_store_show_labels (ds, show_value_labels);
450 }
451
452
453 /* Callback for the value labels tooglebutton */
454 static void
455 value_labels_toggled (GtkToggleToolButton *toggle_tool_button,
456                       gpointer data)
457 {
458   struct data_editor *de = data;
459
460   GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
461
462   GtkCheckMenuItem *item =
463     GTK_CHECK_MENU_ITEM (get_widget_assert (de->xml, "view_valuelabels"));
464
465   PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
466
467   gboolean show_value_labels =
468     gtk_toggle_tool_button_get_active (toggle_tool_button);
469
470   gtk_check_menu_item_set_active (item, show_value_labels);
471
472   psppire_data_store_show_labels (ds, show_value_labels);
473 }
474
475
476 static void
477 file_quit (GtkCheckMenuItem *menuitem, gpointer data)
478 {
479   /* FIXME: Need to be more intelligent here.
480      Give the user the opportunity to save any unsaved data.
481   */
482   gtk_main_quit ();
483 }