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