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>
33 #include <data/variable.h>
35 #include <glade/glade.h>
38 #include <libpspp/str.h>
40 #include <gtksheet/gtksheet.h>
42 #include "menu-actions.h"
44 #include "psppire-dict.h"
46 #include "var-sheet.h"
47 #include "data-sheet.h"
49 #include "psppire-var-store.h"
50 #include "psppire-data-store.h"
52 #include "sort-cases-dialog.h"
58 extern PsppireDict *the_dictionary ;
60 static struct file_handle *psppire_handle = 0;
62 static const gchar handle_name[] = "psppire_handle";
64 static const gchar untitled[] = N_("Untitled");
66 static const gchar window_title[] = N_("PSPP Data Editor");
69 /* Sets the title bar to TEXT */
71 psppire_set_window_title(const gchar *text)
73 GtkWidget *data_editor = get_widget_assert(xml, "data_editor");
75 gchar *title = g_strdup_printf("%s --- %s", text, gettext(window_title));
77 gtk_window_set_title(GTK_WINDOW(data_editor), title);
82 /* Clear the active file and set the data and var sheets to
88 PsppireDataStore *data_store ;
89 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
90 GtkSheet *var_sheet = GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
92 gtk_sheet_set_active_cell(data_sheet, -1, -1);
93 gtk_sheet_set_active_cell(var_sheet, 0, 0);
95 if ( GTK_WIDGET_REALIZED(GTK_WIDGET(data_sheet)))
96 gtk_sheet_unselect_range(data_sheet);
98 if ( GTK_WIDGET_REALIZED(GTK_WIDGET(var_sheet)))
99 gtk_sheet_unselect_range(var_sheet);
101 gtk_sheet_moveto(data_sheet, 0, 0, 0.0, 0.0);
102 gtk_sheet_moveto(var_sheet, 0, 0, 0.0, 0.0);
104 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
106 psppire_data_store_clear(data_store);
108 psppire_set_window_title(gettext(untitled));
111 fh_free(psppire_handle);
118 on_new1_activate (GtkMenuItem *menuitem,
126 /* Load a system file.
127 Return TRUE if successfull
130 load_system_file(const gchar *file_name)
134 PsppireVarStore *var_store ;
135 PsppireDataStore *data_store ;
136 struct dictionary *new_dict;
137 struct sfm_read_info ri;
138 struct sfm_reader *reader ;
140 GtkWidget *data_sheet = get_widget_assert(xml, "data_sheet");
141 GtkWidget *var_sheet = get_widget_assert(xml, "variable_sheet");
143 g_assert(data_sheet);
149 fh_create_file (handle_name, file_name, fh_default_properties());
151 if ( !psppire_handle )
153 g_warning("Cannot read handle for reading system file \"%s\"\n",
158 reader = sfm_open_reader (psppire_handle, &new_dict, &ri);
163 /* FIXME: We need a better way of updating a dictionary than this */
164 the_dictionary = psppire_dict_new_from_dict(new_dict);
167 PSPPIRE_VAR_STORE(gtk_sheet_get_model(GTK_SHEET(var_sheet)));
169 psppire_var_store_set_dictionary(var_store, the_dictionary);
173 PSPPIRE_DATA_STORE(gtk_sheet_get_model(GTK_SHEET(data_sheet)));
175 psppire_data_store_set_dictionary(data_store,
178 psppire_set_window_title(basename(file_name));
180 var_cnt = dict_get_next_value_idx(the_dictionary->dict);
188 case_create(&c, var_cnt);
189 if ( 0 == sfm_read_case (reader, &c) )
195 if ( !psppire_case_file_append_case(data_store->case_file, &c) )
197 g_warning("Cannot write case to casefile\n");
203 sfm_close_reader(reader);
205 psppire_case_file_get_case_count(data_store->case_file);
211 open_data (GtkMenuItem *menuitem,
214 bool finished = FALSE;
217 GtkWidget *data_editor = get_widget_assert(xml, "data_editor");
218 GtkFileFilter *filter ;
220 dialog = gtk_file_chooser_dialog_new (_("Open"),
221 GTK_WINDOW(data_editor),
222 GTK_FILE_CHOOSER_ACTION_OPEN,
223 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
224 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
227 filter = gtk_file_filter_new();
228 gtk_file_filter_set_name(filter, _("System Files (*.sav)"));
229 gtk_file_filter_add_pattern(filter, "*.sav");
230 gtk_file_filter_add_pattern(filter, "*.SAV");
231 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
233 filter = gtk_file_filter_new();
234 gtk_file_filter_set_name(filter, _("Portable Files (*.por) "));
235 gtk_file_filter_add_pattern(filter, "*.por");
236 gtk_file_filter_add_pattern(filter, "*.POR");
237 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
239 filter = gtk_file_filter_new();
240 gtk_file_filter_set_name(filter, _("All Files"));
241 gtk_file_filter_add_pattern(filter, "*");
242 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
246 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
249 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
251 finished = load_system_file(file_name) ;
258 } while ( ! finished ) ;
260 gtk_widget_destroy (dialog);
265 on_data3_activate (GtkMenuItem *menuitem,
268 open_data(menuitem, user_data);
272 on_data5_activate (GtkMenuItem *menuitem,
275 open_data(menuitem, user_data);
279 /* Re initialise HANDLE, by interrogating the user for a new file name */
281 recreate_save_handle(struct file_handle **handle)
286 GtkWidget *data_editor = get_widget_assert(xml, "data_editor");
288 dialog = gtk_file_chooser_dialog_new (_("Save Data As"),
289 GTK_WINDOW(data_editor),
290 GTK_FILE_CHOOSER_ACTION_SAVE,
291 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
292 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
295 response = gtk_dialog_run (GTK_DIALOG (dialog));
297 if (response == GTK_RESPONSE_ACCEPT)
299 char *file_name = gtk_file_chooser_get_filename
300 (GTK_FILE_CHOOSER (dialog));
306 *handle = fh_create_file (handle_name, file_name,
307 fh_default_properties());
309 psppire_set_window_title(basename(file_name));
314 gtk_widget_destroy (dialog);
316 return ( response == GTK_RESPONSE_ACCEPT ) ;
320 on_save1_activate (GtkMenuItem *menuitem,
323 GtkSheet *data_sheet ;
324 PsppireDataStore *data_store ;
326 if ( ! psppire_handle )
328 if ( ! recreate_save_handle(&psppire_handle) )
332 data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
333 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
335 if ( psppire_handle )
336 psppire_data_store_create_system_file(data_store,
342 on_save_as1_activate (GtkMenuItem *menuitem,
345 GtkSheet *data_sheet ;
346 PsppireDataStore *data_store ;
348 if ( ! recreate_save_handle(&psppire_handle) )
351 if ( ! psppire_handle )
354 data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
355 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
357 if ( psppire_handle )
358 psppire_data_store_create_system_file(data_store,
364 on_quit1_activate (GtkMenuItem *menuitem,
372 on_clear_activate (GtkMenuItem *menuitem,
375 GtkNotebook *notebook = GTK_NOTEBOOK(get_widget_assert(xml, "notebook1"));
378 page = gtk_notebook_get_current_page(notebook);
384 case PAGE_DATA_SHEET:
386 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
387 PsppireDataStore *data_store =
388 PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
391 switch ( data_sheet->state )
393 case GTK_SHEET_ROW_SELECTED:
394 psppire_case_file_delete_cases(data_store->case_file,
395 data_sheet->range.rowi
396 - data_sheet->range.row0 + 1,
397 data_sheet->range.row0);
399 case GTK_SHEET_COLUMN_SELECTED:
402 struct variable *pv =
403 psppire_dict_get_variable (the_dictionary,
404 data_sheet->range.col0);
406 fv = var_get_case_index (pv);
408 psppire_dict_delete_variables (the_dictionary,
409 data_sheet->range.col0,
412 psppire_case_file_insert_values (data_store->case_file,
417 gtk_sheet_cell_clear (data_sheet,
418 data_sheet->active_cell.row,
419 data_sheet->active_cell.col);
430 on_about1_activate(GtkMenuItem *menuitem,
433 GtkWidget *about = get_widget_assert(xml, "aboutdialog1");
436 GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_size( "pspplogo.png", 64, 64, 0);
438 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), pb);
440 gtk_widget_show(about);
442 gtk_window_set_transient_for(GTK_WINDOW(about),
443 GTK_WINDOW(get_widget_assert(xml, "data_editor")));
447 /* Set the value labels state from the toolbar's toggle button */
449 on_togglebutton_value_labels_toggled(GtkToggleToolButton *toggle_tool_button,
452 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
453 GtkCheckMenuItem *item =
454 GTK_CHECK_MENU_ITEM(get_widget_assert(xml, "menuitem-value-labels"));
456 PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
458 gboolean show_value_labels = gtk_toggle_tool_button_get_active(toggle_tool_button);
460 gtk_check_menu_item_set_active(item, show_value_labels);
462 psppire_data_store_show_labels(ds, show_value_labels);
465 /* Set the value labels state from the view menu */
467 on_value_labels_activate(GtkCheckMenuItem *menuitem,
470 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
471 GtkToggleToolButton *tb =
472 GTK_TOGGLE_TOOL_BUTTON(get_widget_assert(xml, "togglebutton-value-labels"));
474 PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
476 gboolean show_value_labels = gtk_check_menu_item_get_active(menuitem);
478 gtk_toggle_tool_button_set_active(tb, show_value_labels);
480 psppire_data_store_show_labels(ds, show_value_labels);
484 on_status_bar1_activate(GtkCheckMenuItem *menuitem,
488 if ( gtk_check_menu_item_get_active(menuitem) )
489 gtk_widget_show(get_widget_assert(xml, "statusbar1"));
491 gtk_widget_hide(get_widget_assert(xml, "statusbar1"));
495 on_grid_lines1_activate(GtkCheckMenuItem *menuitem,
499 const bool grid_visible = gtk_check_menu_item_get_active(menuitem);
501 gtk_sheet_show_grid(GTK_SHEET(get_widget_assert(xml, "variable_sheet")),
504 gtk_sheet_show_grid(GTK_SHEET(get_widget_assert(xml, "data_sheet")),
510 on_fonts1_activate(GtkMenuItem *menuitem,
513 static GtkWidget *dialog = 0 ;
515 dialog = gtk_font_selection_dialog_new(_("Font Selection"));
517 gtk_window_set_transient_for(GTK_WINDOW(dialog),
518 GTK_WINDOW(get_widget_assert(xml, "data_editor")));
521 if ( GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)) )
523 GtkSheet *data_sheet =
524 GTK_SHEET(get_widget_assert(xml, "data_sheet"));
526 GtkSheet *var_sheet =
527 GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
529 PsppireDataStore *ds = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
530 PsppireVarStore *vs = PSPPIRE_VAR_STORE(gtk_sheet_get_model(var_sheet));
532 const gchar *font = gtk_font_selection_dialog_get_font_name
533 (GTK_FONT_SELECTION_DIALOG(dialog));
535 PangoFontDescription* font_desc =
536 pango_font_description_from_string(font);
538 psppire_var_store_set_font(vs, font_desc);
539 psppire_data_store_set_font(ds, font_desc);
542 gtk_widget_hide(dialog);
547 static GtkWidget *menuitems[2];
548 static GtkNotebook *notebook = 0;
551 switch_menus(gint page)
553 GtkWidget *insert_variable = get_widget_assert(xml, "insert-variable");
554 GtkWidget *insert_cases = get_widget_assert(xml, "insert-cases");
559 gtk_widget_hide(menuitems[PAGE_VAR_SHEET]);
560 gtk_widget_show(menuitems[PAGE_DATA_SHEET]);
561 gtk_widget_set_sensitive(insert_variable, TRUE);
562 gtk_widget_set_sensitive(insert_cases, FALSE);
564 case PAGE_DATA_SHEET:
565 gtk_widget_show(menuitems[PAGE_VAR_SHEET]);
566 gtk_widget_hide(menuitems[PAGE_DATA_SHEET]);
567 gtk_widget_set_sensitive(insert_variable, FALSE);
568 gtk_widget_set_sensitive(insert_cases, TRUE);
571 g_assert_not_reached();
578 select_sheet(gint page)
580 gtk_notebook_set_current_page(notebook, page);
587 data_var_select(GtkNotebook *notebook,
588 GtkNotebookPage *page,
592 switch_menus(page_num);
596 /* Initialised things on the variable sheet */
598 var_data_selection_init(void)
600 notebook = GTK_NOTEBOOK(get_widget_assert(xml, "notebook1"));
601 menuitems[PAGE_DATA_SHEET] = get_widget_assert(xml, "data1");
602 menuitems[PAGE_VAR_SHEET] = get_widget_assert(xml, "variables1");
604 gtk_notebook_set_current_page(notebook, PAGE_DATA_SHEET);
605 gtk_widget_hide(menuitems[PAGE_DATA_SHEET]);
606 gtk_widget_show(menuitems[PAGE_VAR_SHEET]);
609 g_signal_connect(G_OBJECT(notebook), "switch-page",
610 G_CALLBACK(data_var_select), 0);
616 on_data1_activate(GtkMenuItem *menuitem,
619 select_sheet(PAGE_DATA_SHEET);
624 on_variables1_activate(GtkMenuItem *menuitem,
627 select_sheet(PAGE_VAR_SHEET);
633 on_go_to_case_activate(GtkMenuItem *menuitem,
636 GtkWidget *dialog = get_widget_assert(xml, "go_to_case_dialog");
637 GtkEntry *entry = GTK_ENTRY(get_widget_assert(xml, "entry_go_to_case"));
638 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
640 gint result = gtk_dialog_run(GTK_DIALOG(dialog));
646 case GTK_RESPONSE_OK:
649 const gchar *text = gtk_entry_get_text(entry);
650 gint casenum = g_strtod(text, NULL);
652 gtk_sheet_get_active_cell(data_sheet, &row, &column);
653 if ( column < 0 ) column = 0;
654 if ( row < 0 ) row = 0;
656 gtk_sheet_set_active_cell(data_sheet, casenum, column);
663 gtk_widget_hide(dialog);
664 gtk_entry_set_text(entry, "");
670 on_sort_cases_activate (GtkMenuItem *menuitem,
674 PsppireDataStore *data_store ;
676 struct sort_criteria criteria;
677 static struct sort_cases_dialog *dialog ;
679 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
681 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
684 dialog = sort_cases_dialog_create(xml);
686 response = sort_cases_dialog_run(dialog, the_dictionary, &criteria);
690 case GTK_RESPONSE_OK:
691 psppire_case_file_sort(data_store->case_file, &criteria);
701 PsppireDataStore *data_store ;
702 GtkSheet *data_sheet = GTK_SHEET(get_widget_assert(xml, "data_sheet"));
704 data_store = PSPPIRE_DATA_STORE(gtk_sheet_get_model(data_sheet));
706 gtk_sheet_get_active_cell(data_sheet, &row, &col);
708 psppire_data_store_insert_new_case(data_store, row);
712 on_insert_case_clicked (GtkButton *button, gpointer user_data)
718 on_insert_cases (GtkMenuItem *menuitem, gpointer user_data)
725 on_insert_variable (GtkMenuItem *menuitem, gpointer user_data)
728 GtkSheet *var_sheet = GTK_SHEET(get_widget_assert(xml, "variable_sheet"));
730 gtk_sheet_get_active_cell(var_sheet, &row, &col);
732 psppire_dict_insert_variable(the_dictionary, row, NULL);