2 PSPPIRE --- A Graphical User Interface for PSPP
3 Copyright (C) 2004, 2005, 2006 Free Software Foundation
4 Written by John Darrington
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.
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.
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
24 #define _(msgid) gettext (msgid)
25 #define N_(msgid) msgid
27 #include <math/sort.h>
29 #include <data/casefile.h>
30 #include <data/file-handle-def.h>
31 #include <data/sys-file-reader.h>
32 #include <data/case.h>
34 #include <glade/glade.h>
37 #include <libpspp/str.h>
39 #include <gtksheet/gtksheet.h>
41 #include "menu-actions.h"
42 #include "psppire-variable.h"
43 #include "psppire-dict.h"
45 #include "var-sheet.h"
46 #include "data-sheet.h"
48 #include "psppire-var-store.h"
49 #include "psppire-data-store.h"
51 #include "sort-cases-dialog.h"
57 extern PsppireDict *the_dictionary ;
59 static struct file_handle *psppire_handle = 0;
61 static const gchar handle_name[] = "psppire_handle";
63 static const gchar untitled[] = N_("Untitled");
65 static const gchar window_title[] = N_("PSPP Data Editor");
68 /* Sets the title bar to TEXT */
70 psppire_set_window_title(const gchar *text)
72 GtkWidget *data_editor = get_widget_assert(xml, "data_editor");
74 gchar *title = g_strdup_printf("%s --- %s", text, gettext(window_title));
76 gtk_window_set_title(GTK_WINDOW(data_editor), title);
81 /* Clear the active file and set the data and var sheets to
87 PsppireDataStore *data_store ;
88 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
89 GtkSheet *var_sheet = GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
91 gtk_sheet_set_active_cell(data_sheet, -1, -1);
92 gtk_sheet_set_active_cell(var_sheet, 0, 0);
94 if ( GTK_WIDGET_REALIZED(GTK_WIDGET(data_sheet)))
95 gtk_sheet_unselect_range(data_sheet);
97 if ( GTK_WIDGET_REALIZED(GTK_WIDGET(var_sheet)))
98 gtk_sheet_unselect_range(var_sheet);
100 gtk_sheet_moveto(data_sheet, 0, 0, 0.0, 0.0);
101 gtk_sheet_moveto(var_sheet, 0, 0, 0.0, 0.0);
103 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
105 psppire_data_store_clear(data_store);
107 psppire_set_window_title(gettext(untitled));
110 fh_free(psppire_handle);
117 on_new1_activate (GtkMenuItem *menuitem,
125 /* Load a system file.
126 Return TRUE if successfull
129 load_system_file(const gchar *file_name)
133 PsppireVarStore *var_store ;
134 PsppireDataStore *data_store ;
135 struct dictionary *new_dict;
136 struct sfm_read_info ri;
137 struct sfm_reader *reader ;
139 GtkWidget *data_sheet = get_widget_assert(xml, "data_sheet");
140 GtkWidget *var_sheet = get_widget_assert(xml, "variable_sheet");
142 g_assert(data_sheet);
148 fh_create_file (handle_name, file_name, fh_default_properties());
150 if ( !psppire_handle )
152 g_warning("Cannot read handle for reading system file \"%s\"\n",
157 reader = sfm_open_reader (psppire_handle, &new_dict, &ri);
162 /* FIXME: We need a better way of updating a dictionary than this */
163 the_dictionary = psppire_dict_new_from_dict(new_dict);
166 PSPPIRE_VAR_STORE(gtk_sheet_get_model(GTK_SHEET(var_sheet)));
168 psppire_var_store_set_dictionary(var_store, the_dictionary);
172 PSPPIRE_DATA_STORE(gtk_sheet_get_model(GTK_SHEET(data_sheet)));
174 psppire_data_store_set_dictionary(data_store,
177 psppire_set_window_title(basename(file_name));
179 var_cnt = dict_get_next_value_idx(the_dictionary->dict);
187 case_create(&c, var_cnt);
188 if ( 0 == sfm_read_case (reader, &c) )
194 if ( !psppire_case_file_append_case(data_store->case_file, &c) )
196 g_warning("Cannot write case to casefile\n");
204 sfm_close_reader(reader);
206 psppire_case_file_get_case_count(data_store->case_file);
213 on_open1_activate (GtkMenuItem *menuitem,
216 bool finished = FALSE;
219 GtkWidget *data_editor = get_widget_assert(xml, "data_editor");
220 GtkFileFilter *filter ;
222 dialog = gtk_file_chooser_dialog_new (_("Open"),
223 GTK_WINDOW(data_editor),
224 GTK_FILE_CHOOSER_ACTION_OPEN,
225 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
226 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
229 filter = gtk_file_filter_new();
230 gtk_file_filter_set_name(filter, _("System Files (*.sav)"));
231 gtk_file_filter_add_pattern(filter, "*.sav");
232 gtk_file_filter_add_pattern(filter, "*.SAV");
233 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
235 filter = gtk_file_filter_new();
236 gtk_file_filter_set_name(filter, _("Portable Files (*.por) "));
237 gtk_file_filter_add_pattern(filter, "*.por");
238 gtk_file_filter_add_pattern(filter, "*.POR");
239 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
241 filter = gtk_file_filter_new();
242 gtk_file_filter_set_name(filter, _("All Files"));
243 gtk_file_filter_add_pattern(filter, "*");
244 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
248 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
251 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
253 finished = load_system_file(file_name) ;
260 } while ( ! finished ) ;
262 gtk_widget_destroy (dialog);
266 /* Re initialise HANDLE, by interrogating the user for a new file name */
268 recreate_save_handle(struct file_handle **handle)
272 GtkWidget *data_editor = get_widget_assert(xml, "data_editor");
274 dialog = gtk_file_chooser_dialog_new (_("Save Data As"),
275 GTK_WINDOW(data_editor),
276 GTK_FILE_CHOOSER_ACTION_SAVE,
277 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
278 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
281 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
283 char *file_name = gtk_file_chooser_get_filename
284 (GTK_FILE_CHOOSER (dialog));
288 destroy_file_handle(*handle, 0);
290 *handle = fh_create_file (handle_name, file_name, fh_default_properties());
292 psppire_set_window_title(basename(file_name));
297 gtk_widget_destroy (dialog);
301 on_save1_activate (GtkMenuItem *menuitem,
304 GtkSheet *data_sheet ;
305 PsppireDataStore *data_store ;
307 if ( ! psppire_handle )
308 recreate_save_handle(&psppire_handle);
310 data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
311 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
313 if ( psppire_handle )
314 psppire_data_store_create_system_file(data_store,
320 on_save_as1_activate (GtkMenuItem *menuitem,
323 GtkSheet *data_sheet ;
324 PsppireDataStore *data_store ;
326 recreate_save_handle(&psppire_handle);
327 if ( ! psppire_handle )
330 data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
331 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
333 if ( psppire_handle )
334 psppire_data_store_create_system_file(data_store,
340 on_quit1_activate (GtkMenuItem *menuitem,
348 on_cut1_activate (GtkMenuItem *menuitem,
356 on_copy1_activate (GtkMenuItem *menuitem,
364 on_paste1_activate (GtkMenuItem *menuitem,
370 /* Fill a case with SYSMIS for numeric and whitespace for string
371 variables respectively */
373 blank_case(struct ccase *cc, gpointer _dict)
376 PsppireDict *dict = _dict;
378 for(i = 0 ; i < psppire_dict_get_var_cnt(dict); ++i )
382 const struct PsppireVariable *var = psppire_dict_get_variable(dict, i);
384 gint idx = psppire_variable_get_fv(var);
386 val = case_data_rw(cc, idx) ;
388 if ( psppire_variable_get_type(var) == ALPHA )
389 memset(val->s, ' ', psppire_variable_get_width(var));
401 on_insert1_activate (GtkMenuItem *menuitem,
404 GtkNotebook *notebook = GTK_NOTEBOOK(get_widget_assert(xml, "notebook1"));
407 page = gtk_notebook_get_current_page(notebook);
411 case PAGE_DATA_SHEET:
414 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
415 PsppireDataStore *data_store =
416 PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
418 psppire_case_array_insert_case(data_store->cases,
419 data_sheet->range.row0,
420 blank_case, the_dictionary);
426 GtkSheet *var_sheet =
427 GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
429 PsppireVarStore *var_store =
430 PSPPIRE_VAR_STORE(gtk_sheet_get_model(var_sheet));
432 psppire_dict_insert_variable(var_store->dict, var_sheet->range.row0, 0);
439 on_delete1_activate (GtkMenuItem *menuitem,
443 GtkWidget *notebook = get_widget_assert(xml, "notebook1");
445 page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
449 case PAGE_DATA_SHEET:
451 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
452 PsppireDataStore *data_store =
453 PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
455 psppire_case_array_delete_cases(data_store->cases,
456 data_sheet->range.row0,
457 1 + data_sheet->range.rowi
458 - data_sheet->range.row0 );
464 GtkSheet *var_sheet =
465 GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
467 PsppireVarStore *var_store =
468 PSPPIRE_VAR_STORE(gtk_sheet_get_model(var_sheet));
470 psppire_dict_delete_variables(var_store->dict,
471 var_sheet->range.row0,
472 1 + var_sheet->range.rowi
473 - var_sheet->range.row0 );
481 on_about1_activate(GtkMenuItem *menuitem,
484 GtkWidget *about = get_widget_assert(xml, "aboutdialog1");
487 GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_size( "pspplogo.png", 64, 64, 0);
489 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), pb);
491 gtk_widget_show(about);
493 gtk_window_set_transient_for(GTK_WINDOW(about),
494 GTK_WINDOW(get_widget_assert(xml, "data_editor")));
498 /* Set the value labels state from the toolbar's toggle button */
500 on_togglebutton_value_labels_toggled(GtkToggleToolButton *toggle_tool_button,
503 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
504 GtkCheckMenuItem *item =
505 GTK_CHECK_MENU_ITEM(get_widget_assert(xml, "menuitem-value-labels"));
507 PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
509 gboolean show_value_labels = gtk_toggle_tool_button_get_active(toggle_tool_button);
511 gtk_check_menu_item_set_active(item, show_value_labels);
513 psppire_data_store_show_labels(ds, show_value_labels);
516 /* Set the value labels state from the view menu */
518 on_value_labels_activate(GtkCheckMenuItem *menuitem,
521 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
522 GtkToggleToolButton *tb =
523 GTK_TOGGLE_TOOL_BUTTON(get_widget_assert(xml, "togglebutton-value-labels"));
525 PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
527 gboolean show_value_labels = gtk_check_menu_item_get_active(menuitem);
529 gtk_toggle_tool_button_set_active(tb, show_value_labels);
531 psppire_data_store_show_labels(ds, show_value_labels);
535 on_status_bar1_activate(GtkCheckMenuItem *menuitem,
539 if ( gtk_check_menu_item_get_active(menuitem) )
540 gtk_widget_show(get_widget_assert(xml, "statusbar1"));
542 gtk_widget_hide(get_widget_assert(xml, "statusbar1"));
546 on_grid_lines1_activate(GtkCheckMenuItem *menuitem,
550 const bool grid_visible = gtk_check_menu_item_get_active(menuitem);
552 gtk_sheet_show_grid(GTK_SHEET(get_widget_assert(xml, "variable_sheet")),
555 gtk_sheet_show_grid(GTK_SHEET(get_widget_assert(xml, "data_sheet")),
561 on_fonts1_activate(GtkMenuItem *menuitem,
564 static GtkWidget *dialog = 0 ;
566 dialog = gtk_font_selection_dialog_new(_("Font Selection"));
568 gtk_window_set_transient_for(GTK_WINDOW(dialog),
569 GTK_WINDOW(get_widget_assert(xml, "data_editor")));
572 if ( GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)) )
574 GtkSheet *data_sheet =
575 GTK_SHEET(get_widget_assert(xml, "data_sheet"));
577 GtkSheet *var_sheet =
578 GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
580 PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
581 PsppireVarStore *vs = PSPPIRE_VAR_STORE(gtk_sheet_get_model(var_sheet));
583 const gchar *font = gtk_font_selection_dialog_get_font_name
584 (GTK_FONT_SELECTION_DIALOG(dialog));
586 PangoFontDescription* font_desc =
587 pango_font_description_from_string(font);
589 psppire_var_store_set_font(vs, font_desc);
590 psppire_data_store_set_font(ds, font_desc);
593 gtk_widget_hide(dialog);
598 static GtkWidget *menuitems[2];
599 static GtkNotebook *notebook = 0;
602 switch_menus(gint page)
607 gtk_widget_hide(menuitems[PAGE_VAR_SHEET]);
608 gtk_widget_show(menuitems[PAGE_DATA_SHEET]);
610 case PAGE_DATA_SHEET:
611 gtk_widget_show(menuitems[PAGE_VAR_SHEET]);
612 gtk_widget_hide(menuitems[PAGE_DATA_SHEET]);
615 g_assert_not_reached();
622 select_sheet(gint page)
624 gtk_notebook_set_current_page(notebook, page);
631 data_var_select(GtkNotebook *notebook,
632 GtkNotebookPage *page,
636 switch_menus(page_num);
640 /* Initialised things on the variable sheet */
642 var_data_selection_init(void)
644 notebook = GTK_NOTEBOOK(get_widget_assert(xml, "notebook1"));
645 menuitems[PAGE_DATA_SHEET] = get_widget_assert(xml, "data1");
646 menuitems[PAGE_VAR_SHEET] = get_widget_assert(xml, "variables1");
648 gtk_notebook_set_current_page(notebook, PAGE_DATA_SHEET);
649 gtk_widget_hide(menuitems[PAGE_DATA_SHEET]);
650 gtk_widget_show(menuitems[PAGE_VAR_SHEET]);
653 g_signal_connect(G_OBJECT(notebook), "switch-page",
654 G_CALLBACK(data_var_select), 0);
660 on_data1_activate(GtkMenuItem *menuitem,
663 select_sheet(PAGE_DATA_SHEET);
668 on_variables1_activate(GtkMenuItem *menuitem,
671 select_sheet(PAGE_VAR_SHEET);
677 on_go_to_case_activate(GtkMenuItem *menuitem,
680 GtkWidget *dialog = get_widget_assert(xml, "go_to_case_dialog");
681 GtkEntry *entry = GTK_ENTRY(get_widget_assert(xml, "entry_go_to_case"));
682 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
684 gint result = gtk_dialog_run(GTK_DIALOG(dialog));
690 case GTK_RESPONSE_OK:
693 const gchar *text = gtk_entry_get_text(entry);
694 gint casenum = g_strtod(text, NULL);
696 gtk_sheet_get_active_cell(data_sheet, &row, &column);
697 if ( column < 0 ) column = 0;
698 if ( row < 0 ) row = 0;
700 gtk_sheet_set_active_cell(data_sheet, casenum, column);
707 gtk_widget_hide(dialog);
708 gtk_entry_set_text(entry, "");
714 on_sort_cases_activate (GtkMenuItem *menuitem,
718 PsppireDataStore *data_store ;
720 struct sort_criteria criteria;
721 static struct sort_cases_dialog *dialog ;
723 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
725 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
728 dialog = sort_cases_dialog_create(xml);
730 response = sort_cases_dialog_run(dialog, the_dictionary, &criteria);
734 case GTK_RESPONSE_OK:
735 psppire_case_file_sort(data_store->case_file, &criteria);