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