Internationalisation.
[pspp-builds.git] / src / ui / gui / menu-actions.c
1 /* 
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2004, 2005  Free Software Foundation
4     Written by John Darrington
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19     02110-1301, USA. */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <gettext.h>
24 #define _(msgid) gettext (msgid)
25 #define N_(msgid) msgid
26
27
28 #include <data/file-handle-def.h>
29 #include <data/sys-file-reader.h>
30 #include <data/case.h>
31
32 #include <glade/glade.h>
33 #include <gtk/gtk.h>
34
35 #include <gtksheet/gtksheet.h>
36 #include "helper.h"
37 #include "menu-actions.h"
38 #include "psppire-variable.h"
39 #include "psppire-dict.h"
40
41 #include "var-sheet.h"
42 #include "data-sheet.h"
43
44 #include "psppire-var-store.h"
45 #include "psppire-data-store.h"
46
47
48
49 extern GladeXML *xml;
50
51
52 extern PsppireDict *the_dictionary ;
53 extern PsppireCaseArray *the_cases ;
54
55
56 static struct file_handle *psppire_handle = 0;
57
58 static const gchar handle_name[] = "psppire_handle";
59
60 static const gchar untitled[] = N_("Untitled");
61
62 static const gchar window_title[] = N_("PSPP Data Editor");
63
64
65 /* Sets the title bar to TEXT */
66 static void
67 psppire_set_window_title(const gchar *text)
68 {
69   GtkWidget *data_editor = get_widget_assert(xml, "data_editor");
70   
71   gchar *title = g_strdup_printf("%s --- %s", text, gettext(window_title));
72
73   gtk_window_set_title(GTK_WINDOW(data_editor), title);
74 }
75
76
77 gboolean
78 clear_file(void)
79 {
80   GtkWidget *data_sheet = get_widget_assert(xml, "data_sheet");
81   GtkWidget *var_sheet = get_widget_assert(xml, "variable_sheet");
82  
83   gtk_sheet_set_active_cell(GTK_SHEET(data_sheet), -1, -1);
84
85   gtk_sheet_set_active_cell(GTK_SHEET(var_sheet), 0, 0);
86
87   psppire_dict_clear(the_dictionary);
88   psppire_case_array_clear(the_cases);
89   
90   psppire_set_window_title(gettext(untitled));
91
92   if (psppire_handle)
93     fh_free(psppire_handle);
94   psppire_handle = 0 ;
95
96   return TRUE;
97 }
98
99 void
100 on_new1_activate                       (GtkMenuItem     *menuitem,
101                                         gpointer         user_data)
102 {
103   clear_file();
104 }
105
106
107
108 static gboolean
109 populate_case_from_reader(struct ccase *c, gpointer aux)
110 {
111   struct sfm_reader *reader = aux;
112
113   return sfm_read_case(reader, c);
114 }
115
116
117 /* Load a system file.
118    Return TRUE if successfull
119 */
120 gboolean
121 load_system_file(const gchar *file_name)
122 {
123   int ni ;
124   gint case_num;
125
126   PsppireVarStore *var_store ;
127   PsppireDataStore *data_store ;
128   struct dictionary *new_dict;
129   struct sfm_read_info ri;
130   struct sfm_reader *reader ; 
131
132   GtkWidget *data_sheet = get_widget_assert(xml, "data_sheet");
133   GtkWidget *var_sheet = get_widget_assert(xml, "variable_sheet");
134
135
136   g_assert(data_sheet);
137   g_assert(var_sheet);
138
139   if ( psppire_handle ) 
140     fh_free(psppire_handle);
141
142   psppire_handle = 
143     fh_create_file (handle_name, file_name, fh_default_properties());
144
145   if ( !psppire_handle ) 
146     {
147       g_warning("Cannot read handle for reading system file \"%s\"\n", 
148                 file_name);
149       return FALSE;
150     }
151
152
153   reader = sfm_open_reader (psppire_handle, &new_dict, &ri);
154       
155   if ( ! reader ) 
156     return FALSE;
157
158   /* FIXME: We need a better way of updating a dictionary than this */
159   the_dictionary = psppire_dict_new_from_dict(new_dict);
160
161   var_store = 
162     PSPPIRE_VAR_STORE(gtk_sheet_get_model(GTK_SHEET(var_sheet)));
163         
164   psppire_var_store_set_dictionary(var_store, the_dictionary);
165
166
167   data_store = 
168     PSPPIRE_DATA_STORE(gtk_sheet_get_model(GTK_SHEET(data_sheet)));
169         
170   psppire_data_store_set_dictionary(data_store,
171                                     the_dictionary);
172
173   psppire_case_array_clear(data_store->cases);
174
175
176   psppire_set_window_title(basename(file_name));
177
178   ni = dict_get_next_value_idx(the_dictionary->dict);
179   if ( ni == 0 ) 
180     return FALSE;
181
182   for(case_num=0;;case_num++)
183     {
184       if (!psppire_case_array_append_case(the_cases, 
185                                           populate_case_from_reader, 
186                                           reader))
187         break;
188     }
189
190
191   sfm_close_reader(reader);
192
193   return TRUE;
194 }
195
196
197 void
198 on_open1_activate                      (GtkMenuItem     *menuitem,
199                                         gpointer         user_data)
200 {
201   bool finished = FALSE;
202
203   GtkWidget *dialog;
204   GtkWidget *data_editor  = get_widget_assert(xml, "data_editor");
205   GtkFileFilter *filter ;
206  
207   dialog = gtk_file_chooser_dialog_new (_("Open"),
208                                         GTK_WINDOW(data_editor),
209                                         GTK_FILE_CHOOSER_ACTION_OPEN,
210                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
211                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
212                                         NULL);
213
214   filter = gtk_file_filter_new();
215   gtk_file_filter_set_name(filter, _("System Files (*.sav)"));
216   gtk_file_filter_add_pattern(filter, "*.sav");
217   gtk_file_filter_add_pattern(filter, "*.SAV");
218   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
219
220   filter = gtk_file_filter_new();
221   gtk_file_filter_set_name(filter, _("Portable Files (*.por) "));
222   gtk_file_filter_add_pattern(filter, "*.por");
223   gtk_file_filter_add_pattern(filter, "*.POR");
224   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
225
226   filter = gtk_file_filter_new();
227   gtk_file_filter_set_name(filter, _("All Files"));
228   gtk_file_filter_add_pattern(filter, "*");
229   gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
230
231   do {
232
233     if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
234       {
235         gchar *file_name = 
236           gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
237         
238         finished =  load_system_file(file_name) ;
239
240         g_free(file_name);
241       }
242     else
243       finished = TRUE;
244
245   } while ( ! finished ) ;
246
247   gtk_widget_destroy (dialog);
248 }
249
250
251 /* Re initialise HANDLE, by interrogating the user for a new file name */
252 static void
253 recreate_save_handle(struct file_handle **handle)
254 {
255   GtkWidget *dialog;
256
257   GtkWidget *data_editor  = get_widget_assert(xml, "data_editor");
258
259   dialog = gtk_file_chooser_dialog_new (_("Save Data As"),
260                                         GTK_WINDOW(data_editor),
261                                         GTK_FILE_CHOOSER_ACTION_SAVE,
262                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
263                                         GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
264                                         NULL);
265
266   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
267     {
268       char *file_name = gtk_file_chooser_get_filename
269         (GTK_FILE_CHOOSER (dialog));
270
271 #if 0
272       if ( *handle ) 
273         destroy_file_handle(*handle, 0);
274 #endif
275       *handle = fh_create_file (handle_name, file_name, fh_default_properties());
276
277       psppire_set_window_title(basename(file_name));
278
279       g_free (file_name);
280     }
281
282   gtk_widget_destroy (dialog);
283 }
284
285 void
286 on_save1_activate                      (GtkMenuItem     *menuitem,
287                                         gpointer         user_data)
288 {
289   GtkSheet *data_sheet ;
290   PsppireDataStore *data_store ;
291
292   if ( ! psppire_handle ) 
293     recreate_save_handle(&psppire_handle);
294   
295   data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
296   data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
297   
298   if ( psppire_handle ) 
299     psppire_data_store_create_system_file(data_store,
300                                        psppire_handle);
301 }
302
303
304 void
305 on_save_as1_activate                   (GtkMenuItem     *menuitem,
306                                         gpointer         user_data)
307 {
308   GtkSheet *data_sheet ;
309   PsppireDataStore *data_store ;
310
311   recreate_save_handle(&psppire_handle);
312   if ( ! psppire_handle ) 
313     return ;
314
315   data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
316   data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
317
318   if ( psppire_handle ) 
319     psppire_data_store_create_system_file(data_store,
320                                        psppire_handle);
321 }
322
323
324 void
325 on_quit1_activate                      (GtkMenuItem     *menuitem,
326                                         gpointer         user_data)
327 {
328   gtk_main_quit();
329 }
330
331
332 void
333 on_cut1_activate                       (GtkMenuItem     *menuitem,
334                                         gpointer         user_data)
335 {
336
337 }
338
339
340 void
341 on_copy1_activate                      (GtkMenuItem     *menuitem,
342                                         gpointer         user_data)
343 {
344
345 }
346
347
348 void
349 on_paste1_activate                     (GtkMenuItem     *menuitem,
350                                         gpointer         user_data)
351 {
352
353 }
354
355 /* Fill a case with SYSMIS for numeric and whitespace for string
356    variables respectively */ 
357 static gboolean 
358 blank_case(struct ccase *cc, gpointer _dict)
359 {
360   gint i;
361   PsppireDict *dict = _dict;
362
363   for(i = 0 ; i < psppire_dict_get_var_cnt(dict); ++i ) 
364     {
365       union value *val ;
366
367       const struct PsppireVariable *var = psppire_dict_get_variable(dict, i);
368       
369       gint idx = psppire_variable_get_index(var);
370
371       val = case_data_rw(cc, idx) ;
372
373       if ( psppire_variable_get_type(var) == ALPHA ) 
374         memset(val->s, ' ', psppire_variable_get_width(var));
375       else
376         val->f = SYSMIS;
377
378       case_unshare(cc);
379     }
380
381   return TRUE;
382 }
383
384
385 void
386 on_insert1_activate                    (GtkMenuItem     *menuitem,
387                                         gpointer         user_data)
388 {
389   GtkNotebook *notebook = GTK_NOTEBOOK(get_widget_assert(xml, "notebook1"));
390   gint page = -1;
391
392   page = gtk_notebook_get_current_page(notebook);
393
394   switch (page) 
395     {
396     case PAGE_DATA_SHEET:
397       {
398         GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
399         PsppireDataStore *data_store = 
400           PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
401
402         psppire_case_array_insert_case(data_store->cases, 
403                                        data_sheet->range.row0, 
404                                        blank_case, the_dictionary);
405       }
406       break;
407     case PAGE_VAR_SHEET:
408       {
409         GtkSheet *var_sheet = 
410           GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
411
412         PsppireVarStore *var_store = 
413           PSPPIRE_VAR_STORE(gtk_sheet_get_model(var_sheet));
414
415         psppire_dict_insert_variable(var_store->dict, var_sheet->range.row0, 0);
416       }
417       break;
418     }
419 }
420
421 void
422 on_delete1_activate                    (GtkMenuItem     *menuitem,
423                                         gpointer         user_data)
424 {
425   gint page = -1;
426   GtkWidget *notebook = get_widget_assert(xml, "notebook1");
427
428   page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
429   switch ( page) 
430     {
431     case PAGE_DATA_SHEET:
432       {
433         GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
434         PsppireDataStore *data_store = 
435           PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
436
437         psppire_case_array_delete_cases(data_store->cases, 
438                                     data_sheet->range.row0, 
439                                     1 + data_sheet->range.rowi 
440                                     - data_sheet->range.row0  );
441       }
442       break;
443     case PAGE_VAR_SHEET:
444       {
445         GtkSheet *var_sheet = 
446           GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
447
448         PsppireVarStore *var_store = 
449           PSPPIRE_VAR_STORE(gtk_sheet_get_model(var_sheet));
450
451         psppire_dict_delete_variables(var_store->dict, 
452                                    var_sheet->range.row0,
453                                    1 + var_sheet->range.rowi 
454                                    - var_sheet->range.row0  );
455       }
456       break;
457     }
458 }
459
460
461 void
462 on_about1_activate(GtkMenuItem     *menuitem,
463                    gpointer         user_data)
464 {
465   GtkWidget *about =  get_widget_assert(xml, "aboutdialog1");
466   
467   
468   GdkPixbuf *pb  = gdk_pixbuf_new_from_file_at_size( "pspplogo.png", 64, 64, 0);
469
470   gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), pb);
471
472   gtk_widget_show(about);
473
474   gtk_window_set_transient_for(GTK_WINDOW(about), 
475                                GTK_WINDOW(get_widget_assert(xml, "data_editor")));
476 }
477
478
479
480 void
481 on_toolbars1_activate
482                      (GtkMenuItem     *menuitem,
483                                         gpointer         user_data)
484 {
485
486
487 }
488
489 void
490 on_value_labels1_activate(GtkCheckMenuItem     *menuitem,
491                           gpointer         user_data)
492 {
493   GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
494   PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
495                 
496   psppire_data_store_show_labels(ds, 
497                               gtk_check_menu_item_get_active(menuitem));
498 }
499
500 void
501 on_status_bar1_activate(GtkCheckMenuItem     *menuitem,
502  gpointer         user_data)
503 {
504
505   if ( gtk_check_menu_item_get_active(menuitem) ) 
506     gtk_widget_show(get_widget_assert(xml, "statusbar1"));
507   else
508     gtk_widget_hide(get_widget_assert(xml, "statusbar1"));
509 }
510
511 void
512 on_grid_lines1_activate(GtkCheckMenuItem     *menuitem,
513  gpointer         user_data)
514 {
515
516   const bool grid_visible = gtk_check_menu_item_get_active(menuitem); 
517
518   gtk_sheet_show_grid(GTK_SHEET(get_widget_assert(xml, "variable_sheet")),
519                       grid_visible);
520
521   gtk_sheet_show_grid(GTK_SHEET(get_widget_assert(xml, "data_sheet")),
522                       grid_visible);
523 }
524
525
526 void
527 on_fonts1_activate(GtkMenuItem     *menuitem,
528  gpointer         user_data)
529 {
530   static GtkWidget *dialog = 0 ; 
531   if ( !dialog ) 
532     dialog   = gtk_font_selection_dialog_new(_("Font Selection"));
533
534   gtk_window_set_transient_for(GTK_WINDOW(dialog), 
535                                GTK_WINDOW(get_widget_assert(xml, "data_editor")));
536
537
538   if ( GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)) ) 
539     {
540       GtkSheet *data_sheet = 
541         GTK_SHEET(get_widget_assert(xml, "data_sheet"));
542
543       GtkSheet *var_sheet = 
544         GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
545
546       PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
547       PsppireVarStore *vs = PSPPIRE_VAR_STORE(gtk_sheet_get_model(var_sheet));
548
549       const gchar *font = gtk_font_selection_dialog_get_font_name 
550         (GTK_FONT_SELECTION_DIALOG(dialog));
551
552       PangoFontDescription* font_desc = 
553         pango_font_description_from_string(font);
554
555       psppire_var_store_set_font(vs, font_desc);
556       psppire_data_store_set_font(ds, font_desc);
557     }
558   
559   gtk_widget_hide(dialog);
560
561 }
562
563
564 static GtkWidget *menuitems[2];
565 static GtkNotebook *notebook = 0;
566
567 static void
568 switch_menus(gint page)
569 {
570   switch (page) 
571     {
572     case PAGE_VAR_SHEET:
573       gtk_widget_hide(menuitems[PAGE_VAR_SHEET]);
574       gtk_widget_show(menuitems[PAGE_DATA_SHEET]);
575       break;
576     case PAGE_DATA_SHEET:
577       gtk_widget_show(menuitems[PAGE_VAR_SHEET]);
578       gtk_widget_hide(menuitems[PAGE_DATA_SHEET]);
579       break;
580     default:
581       g_assert_not_reached();
582       break;
583     }
584 }
585
586
587 void
588 select_sheet(gint page)
589 {
590   gtk_notebook_set_current_page(notebook, page);
591   switch_menus(page);
592 }
593
594
595
596 static void
597 data_var_select(GtkNotebook *notebook,
598                 GtkNotebookPage *page,
599                 guint page_num,
600                 gpointer user_data)
601 {
602   switch_menus(page_num);
603 }
604
605
606 /* Initialised things on the variable sheet */
607 void
608 var_data_selection_init(void)
609 {
610   notebook = GTK_NOTEBOOK(get_widget_assert(xml, "notebook1"));
611   menuitems[PAGE_DATA_SHEET] = get_widget_assert(xml, "data1");
612   menuitems[PAGE_VAR_SHEET] = get_widget_assert(xml, "variables1");
613
614   gtk_notebook_set_current_page(notebook, PAGE_DATA_SHEET);
615   gtk_widget_hide(menuitems[PAGE_DATA_SHEET]);
616   gtk_widget_show(menuitems[PAGE_VAR_SHEET]);
617
618
619   g_signal_connect(G_OBJECT(notebook), "switch-page",
620                    G_CALLBACK(data_var_select), 0);
621
622 }
623
624
625 void
626 on_data1_activate(GtkMenuItem     *menuitem,
627                   gpointer         user_data)
628 {
629   select_sheet(PAGE_DATA_SHEET);
630 }
631
632
633 void
634 on_variables1_activate(GtkMenuItem     *menuitem,
635                   gpointer         user_data)
636 {
637   select_sheet(PAGE_VAR_SHEET);
638 }
639