61b5aea0228975867f5ba32fab7d20bb51cf9caf
[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
44 /* Switch between the VAR SHEET and the DATA SHEET */
45 enum {PAGE_DATA_SHEET = 0, PAGE_VAR_SHEET};
46
47 static gboolean click2column (GtkWidget *w, gint col, gpointer data);
48
49 static gboolean click2row (GtkWidget *w, gint row, gpointer data);
50
51
52 static void select_sheet (struct data_editor *de, guint page_num);
53
54
55 static void data_var_select (GtkNotebook *notebook,
56                             GtkNotebookPage *page,
57                             guint page_num,
58                             gpointer user_data);
59
60 static void status_bar_activate (GtkCheckMenuItem *, gpointer);
61
62 static void grid_lines_activate (GtkCheckMenuItem *, gpointer);
63
64 static void data_sheet_activate (GtkCheckMenuItem *, gpointer);
65
66 static void variable_sheet_activate (GtkCheckMenuItem *, gpointer );
67
68 static void fonts_activate (GtkMenuItem *, gpointer);
69
70 static void value_labels_activate (GtkCheckMenuItem *, gpointer);
71 static void value_labels_toggled (GtkToggleToolButton *, gpointer);
72
73
74 static void file_quit (GtkCheckMenuItem *, gpointer );
75
76 static void on_clear_activate (GtkMenuItem *, gpointer);
77
78 static void
79 enable_edit_clear (GtkWidget *w, gint row, gpointer data)
80 {
81   struct data_editor *de = data;
82
83   GtkWidget *menuitem = get_widget_assert (de->xml, "edit_clear");
84
85   gtk_widget_set_sensitive (menuitem, TRUE);
86 }
87
88 static gboolean
89 disable_edit_clear (GtkWidget *w, gint x, gint y, gpointer data)
90 {
91   struct data_editor *de = data;
92
93   GtkWidget *menuitem = get_widget_assert (de->xml, "edit_clear");
94
95   gtk_widget_set_sensitive (menuitem, FALSE);
96
97   return FALSE;
98 }
99
100
101
102 /*
103   Create a new data editor.
104 */
105 struct data_editor *
106 new_data_editor (void)
107 {
108   struct data_editor *de ;
109   struct editor_window *e;
110
111   de = g_malloc (sizeof (*de));
112
113   e = (struct editor_window *) de;
114
115   de->xml = glade_xml_new (PKGDATADIR "/data-editor.glade", NULL, NULL);
116
117   e->window = get_widget_assert (de->xml, "data_editor");
118
119   g_signal_connect (get_widget_assert (de->xml,"file_new_data"),
120                     "activate",
121                     G_CALLBACK (new_data_window),
122                     e->window);
123
124   g_signal_connect (get_widget_assert (de->xml,"file_open_data"),
125                     "activate",
126                     G_CALLBACK (open_data_window),
127                     e->window);
128
129   g_signal_connect (get_widget_assert (de->xml,"file_new_syntax"),
130                     "activate",
131                     G_CALLBACK (new_syntax_window),
132                     e->window);
133
134   g_signal_connect (get_widget_assert (de->xml,"file_open_syntax"),
135                     "activate",
136                     G_CALLBACK (open_syntax_window),
137                     e->window);
138
139
140   g_signal_connect (get_widget_assert (de->xml,"edit_clear"),
141                     "activate",
142                     G_CALLBACK (on_clear_activate),
143                     de);
144
145
146
147   g_signal_connect (get_widget_assert (de->xml,"help_about"),
148                     "activate",
149                     G_CALLBACK (about_new),
150                     e->window);
151
152
153   g_signal_connect (get_widget_assert (de->xml,"data_sheet"),
154                     "double-click-column",
155                     G_CALLBACK (click2column),
156                     de);
157
158
159   g_signal_connect (get_widget_assert (de->xml, "variable_sheet"),
160                     "double-click-row",
161                     GTK_SIGNAL_FUNC (click2row),
162                     de);
163
164
165   g_signal_connect (get_widget_assert (de->xml, "variable_sheet"),
166                     "select-row",
167                     GTK_SIGNAL_FUNC (enable_edit_clear),
168                     de);
169
170   g_signal_connect (get_widget_assert (de->xml, "variable_sheet"),
171                     "activate",
172                     GTK_SIGNAL_FUNC (disable_edit_clear),
173                     de);
174
175
176   g_signal_connect (get_widget_assert (de->xml, "notebook"),
177                     "switch-page",
178                     G_CALLBACK (data_var_select), de);
179
180
181
182   g_signal_connect (get_widget_assert (de->xml, "view_statusbar"),
183                     "activate",
184                     G_CALLBACK (status_bar_activate), de);
185
186
187   g_signal_connect (get_widget_assert (de->xml, "view_gridlines"),
188                     "activate",
189                     G_CALLBACK (grid_lines_activate), de);
190
191
192
193   g_signal_connect (get_widget_assert (de->xml, "view_data"),
194                     "activate",
195                     G_CALLBACK (data_sheet_activate), de);
196
197   g_signal_connect (get_widget_assert (de->xml, "view_variables"),
198                     "activate",
199                     G_CALLBACK (variable_sheet_activate), de);
200
201
202
203   g_signal_connect (get_widget_assert (de->xml, "view_fonts"),
204                     "activate",
205                     G_CALLBACK (fonts_activate), de);
206
207
208
209   g_signal_connect (get_widget_assert (de->xml, "view_valuelabels"),
210                     "activate",
211                     G_CALLBACK (value_labels_activate), de);
212
213
214   g_signal_connect (get_widget_assert (de->xml, "togglebutton-value-labels"),
215                     "toggled",
216                     G_CALLBACK (value_labels_toggled), de);
217
218
219   g_signal_connect (get_widget_assert (de->xml, "file_quit"),
220                     "activate",
221                     G_CALLBACK (file_quit), de);
222
223
224   select_sheet (de, PAGE_DATA_SHEET);
225
226   return de;
227 }
228
229
230 /* Callback which occurs when the var sheet's row title
231    button is double clicked */
232 static gboolean
233 click2row (GtkWidget *w, gint row, gpointer data)
234 {
235   struct data_editor *de = data;
236
237   gint current_row, current_column;
238
239   GtkWidget *data_sheet  = get_widget_assert (de->xml, "data_sheet");
240
241   data_editor_select_sheet (de, PAGE_DATA_SHEET);
242
243   gtk_sheet_get_active_cell (GTK_SHEET (data_sheet),
244                              &current_row, &current_column);
245
246   gtk_sheet_set_active_cell (GTK_SHEET (data_sheet), current_row, row);
247
248   return FALSE;
249 }
250
251
252 /* Callback which occurs when the data sheet's column title
253    is double clicked */
254 static gboolean
255 click2column (GtkWidget *w, gint col, gpointer data)
256 {
257   struct data_editor *de = data;
258
259   gint current_row, current_column;
260
261   GtkWidget *var_sheet  = get_widget_assert (de->xml, "variable_sheet");
262
263   data_editor_select_sheet (de, PAGE_VAR_SHEET);
264
265   gtk_sheet_get_active_cell (GTK_SHEET (var_sheet),
266                              &current_row, &current_column);
267
268   gtk_sheet_set_active_cell (GTK_SHEET (var_sheet), col, current_column);
269
270   return FALSE;
271 }
272
273
274
275
276 void
277 new_data_window (GtkMenuItem *menuitem, gpointer parent)
278 {
279   window_create (WINDOW_DATA, NULL);
280 }
281
282
283 static void
284 select_sheet (struct data_editor *de, guint page_num)
285 {
286   GtkWidget *insert_variable = get_widget_assert (de->xml, "insert-variable");
287   GtkWidget *insert_cases = get_widget_assert (de->xml, "insert-cases");
288
289   GtkWidget *view_data = get_widget_assert (de->xml, "view_data");
290   GtkWidget *view_variables = get_widget_assert (de->xml, "view_variables");
291
292   switch (page_num)
293     {
294     case PAGE_VAR_SHEET:
295       gtk_widget_hide (view_variables);
296       gtk_widget_show (view_data);
297       gtk_widget_set_sensitive (insert_variable, TRUE);
298       gtk_widget_set_sensitive (insert_cases, FALSE);
299       break;
300     case PAGE_DATA_SHEET:
301       gtk_widget_show (view_variables);
302       gtk_widget_hide (view_data);
303       gtk_widget_set_sensitive (insert_variable, FALSE);
304       gtk_widget_set_sensitive (insert_cases, TRUE);
305       break;
306     default:
307       g_assert_not_reached ();
308       break;
309     }
310 }
311
312
313 static void
314 data_var_select (GtkNotebook *notebook,
315                 GtkNotebookPage *page,
316                 guint page_num,
317                 gpointer user_data)
318 {
319   struct data_editor *de = user_data;
320
321   select_sheet (de, page_num);
322 }
323
324
325
326
327 void
328 data_editor_select_sheet (struct data_editor *de, gint page)
329 {
330   gtk_notebook_set_current_page
331    (
332     GTK_NOTEBOOK (get_widget_assert (de->xml,"notebook")), page
333     );
334 }
335
336
337 void
338 open_data_window (GtkMenuItem *menuitem, gpointer parent)
339 {
340   bool finished = FALSE;
341
342   GtkWidget *dialog;
343
344   GtkFileFilter *filter ;
345
346   dialog = gtk_file_chooser_dialog_new (_("Open"),
347                                         GTK_WINDOW (parent),
348                                         GTK_FILE_CHOOSER_ACTION_OPEN,
349                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
350                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
351                                         NULL);
352
353   filter = gtk_file_filter_new ();
354   gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
355   gtk_file_filter_add_pattern (filter, "*.sav");
356   gtk_file_filter_add_pattern (filter, "*.SAV");
357   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
358
359   filter = gtk_file_filter_new ();
360   gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
361   gtk_file_filter_add_pattern (filter, "*.por");
362   gtk_file_filter_add_pattern (filter, "*.POR");
363   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
364
365   filter = gtk_file_filter_new ();
366   gtk_file_filter_set_name (filter, _("All Files"));
367   gtk_file_filter_add_pattern (filter, "*");
368   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
369
370   do {
371
372     if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
373       {
374         gchar *file_name =
375           gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
376
377         g_free (file_name);
378       }
379     else
380       finished = TRUE;
381
382   } while ( ! finished ) ;
383
384   gtk_widget_destroy (dialog);
385 }
386
387
388
389
390 static void
391 status_bar_activate (GtkCheckMenuItem *menuitem, gpointer data)
392 {
393   struct data_editor *de = data;
394   GtkWidget *statusbar = get_widget_assert (de->xml, "statusbar");
395
396   if ( gtk_check_menu_item_get_active (menuitem) )
397     gtk_widget_show (statusbar);
398   else
399     gtk_widget_hide (statusbar);
400 }
401
402
403
404
405 static void
406 grid_lines_activate (GtkCheckMenuItem *menuitem, gpointer data)
407 {
408   struct data_editor *de = data;
409   const bool grid_visible = gtk_check_menu_item_get_active (menuitem);
410
411   gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml,
412                                                      "variable_sheet")),
413                        grid_visible);
414
415   gtk_sheet_show_grid (GTK_SHEET (get_widget_assert (de->xml, "data_sheet")),
416                        grid_visible);
417 }
418
419
420
421 static void
422 data_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
423 {
424   struct data_editor *de = data;
425
426   data_editor_select_sheet (de, PAGE_DATA_SHEET);
427 }
428
429
430 static void
431 variable_sheet_activate (GtkCheckMenuItem *menuitem, gpointer data)
432 {
433   struct data_editor *de = data;
434
435   data_editor_select_sheet (de, PAGE_VAR_SHEET);
436 }
437
438
439 static void
440 fonts_activate (GtkMenuItem *menuitem, gpointer data)
441 {
442   struct data_editor *de = data;
443   GtkWidget *dialog =
444     gtk_font_selection_dialog_new (_("Font Selection"));
445
446   gtk_window_set_transient_for (GTK_WINDOW (dialog),
447                                 GTK_WINDOW (get_widget_assert (de->xml,
448                                                                "data_editor")));
449   if ( GTK_RESPONSE_OK == gtk_dialog_run (GTK_DIALOG (dialog)) )
450     {
451       GtkSheet *data_sheet =
452         GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
453
454       GtkSheet *var_sheet =
455         GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
456
457       PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
458       PsppireVarStore *vs = PSPPIRE_VAR_STORE (gtk_sheet_get_model (var_sheet));
459
460       const gchar *font = gtk_font_selection_dialog_get_font_name
461         (GTK_FONT_SELECTION_DIALOG (dialog));
462
463       PangoFontDescription* font_desc =
464         pango_font_description_from_string (font);
465
466       psppire_var_store_set_font (vs, font_desc);
467       psppire_data_store_set_font (ds, font_desc);
468     }
469
470   gtk_widget_hide (dialog);
471 }
472
473
474 /* The next two callbacks are mutually co-operative */
475
476 /* Callback for the value labels menu item */
477 static void
478 value_labels_activate (GtkCheckMenuItem *menuitem, gpointer data)
479 {
480   struct data_editor *de = data;
481
482   GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
483
484   GtkToggleToolButton *tb =
485     GTK_TOGGLE_TOOL_BUTTON (get_widget_assert (de->xml,
486                                                "togglebutton-value-labels"));
487
488   PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
489
490   gboolean show_value_labels = gtk_check_menu_item_get_active (menuitem);
491
492   gtk_toggle_tool_button_set_active (tb, show_value_labels);
493
494   psppire_data_store_show_labels (ds, show_value_labels);
495 }
496
497
498 /* Callback for the value labels tooglebutton */
499 static void
500 value_labels_toggled (GtkToggleToolButton *toggle_tool_button,
501                       gpointer data)
502 {
503   struct data_editor *de = data;
504
505   GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet"));
506
507   GtkCheckMenuItem *item =
508     GTK_CHECK_MENU_ITEM (get_widget_assert (de->xml, "view_valuelabels"));
509
510   PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet));
511
512   gboolean show_value_labels =
513     gtk_toggle_tool_button_get_active (toggle_tool_button);
514
515   gtk_check_menu_item_set_active (item, show_value_labels);
516
517   psppire_data_store_show_labels (ds, show_value_labels);
518 }
519
520
521 static void
522 file_quit (GtkCheckMenuItem *menuitem, gpointer data)
523 {
524   /* FIXME: Need to be more intelligent here.
525      Give the user the opportunity to save any unsaved data.
526   */
527   gtk_main_quit ();
528 }
529
530
531
532 /* Callback for when the Clear item in the edit menu is activated */
533 static void
534 on_clear_activate (GtkMenuItem *menuitem, gpointer data)
535 {
536   struct data_editor *de = data;
537
538   GtkNotebook *notebook = GTK_NOTEBOOK (get_widget_assert (de->xml,
539                                                            "notebook"));
540
541   switch ( gtk_notebook_get_current_page (notebook) )
542     {
543     case PAGE_VAR_SHEET:
544       {
545         GtkSheet *var_sheet =
546           GTK_SHEET (get_widget_assert (de->xml, "variable_sheet"));
547
548         PsppireVarStore *vs = PSPPIRE_VAR_STORE
549           (gtk_sheet_get_model (var_sheet) );
550
551         /* This shouldn't be able to happen, because the menuitem
552            should be disabled */
553         g_return_if_fail (var_sheet->state  ==  GTK_SHEET_ROW_SELECTED );
554
555         psppire_dict_delete_variables (vs->dict,
556                                        var_sheet->range.row0,
557                                        1 +
558                                        var_sheet->range.rowi -
559                                        var_sheet->range.row0 );
560       }
561       break;
562       case PAGE_DATA_SHEET:
563         break;
564       default:
565         g_assert_not_reached ();
566     }
567 }