X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fdata-editor.c;h=8fd9517db535ca94c6efe062bb59752c8880ebd4;hb=0085c7edf6d3b9c9ee2ce880893023c567886101;hp=36150579051ef45cb9f15b8dc662a3e414c5804f;hpb=1db52a18395f9b3b4e58b97379d2356f4857496e;p=pspp diff --git a/src/ui/gui/data-editor.c b/src/ui/gui/data-editor.c index 3615057905..8fd9517db5 100644 --- a/src/ui/gui/data-editor.c +++ b/src/ui/gui/data-editor.c @@ -26,12 +26,14 @@ #include "helper.h" #include "about.h" +#include #include "psppire-dialog.h" #include "psppire-selector.h" #include "weight-cases-dialog.h" #include "split-file-dialog.h" #include "transpose-dialog.h" #include "sort-cases-dialog.h" +#include "select-cases-dialog.h" #include "compute-dialog.h" #include "goto-case-dialog.h" #include "comments-dialog.h" @@ -51,6 +53,15 @@ #include "psppire-var-store.h" +static void create_data_sheet_variable_popup_menu (struct data_editor *); +static void create_data_sheet_cases_popup_menu (struct data_editor *); + +static void popup_variable_menu (GtkSheet *, gint, + GdkEventButton *, gpointer data); + +static void popup_cases_menu (GtkSheet *, gint, + GdkEventButton *, gpointer data); + /* Update the data_ref_entry with the reference of the active cell */ static gint update_data_ref_entry (const GtkSheet *sheet, gint row, gint col, gpointer data); @@ -58,21 +69,18 @@ static gint update_data_ref_entry (const GtkSheet *sheet, static void register_data_editor_actions (struct data_editor *de); static void insert_variable (GtkAction *, gpointer data); - static void insert_case (GtkAction *a, gpointer data); +static void delete_cases (GtkAction *a, gpointer data); +static void delete_variables (GtkAction *a, gpointer data); - +static void toggle_value_labels (GtkToggleAction *a, gpointer data); /* Switch between the VAR SHEET and the DATA SHEET */ static gboolean click2column (GtkWidget *w, gint col, gpointer data); - static gboolean click2row (GtkWidget *w, gint row, gpointer data); -static void select_sheet (struct data_editor *de, guint page_num); - - /* Callback for when the dictionary changes properties*/ static void on_weight_change (GObject *, gint, gpointer); static void on_filter_change (GObject *, gint, gpointer); @@ -93,36 +101,57 @@ static void variable_sheet_activate (GtkCheckMenuItem *, gpointer ); static void fonts_activate (GtkMenuItem *, gpointer); -static void value_labels_activate (GtkCheckMenuItem *, gpointer); -static void value_labels_toggled (GtkToggleToolButton *, gpointer); +static void file_quit (GtkCheckMenuItem *, gpointer ); +static void +enable_delete_cases (GtkWidget *w, gint var, gpointer data) +{ + struct data_editor *de = data; -static void file_quit (GtkCheckMenuItem *, gpointer ); + gtk_action_set_visible (de->delete_cases, var != -1); +} -static void on_clear_activate (GtkMenuItem *, gpointer); static void -enable_edit_clear (GtkWidget *w, gint row, gpointer data) +enable_delete_variables (GtkWidget *w, gint var, gpointer data) { struct data_editor *de = data; - GtkWidget *menuitem = get_widget_assert (de->xml, "edit_clear"); + gtk_action_set_visible (de->delete_variables, var != -1); +} + - gtk_widget_set_sensitive (menuitem, TRUE); + +/* Run the EXECUTE command. */ +static void +execute (GtkMenuItem *mi, gpointer data) +{ + struct getl_interface *sss = create_syntax_string_source ("EXECUTE."); + + execute_syntax (sss); } -static gboolean -disable_edit_clear (GtkWidget *w, gint x, gint y, gpointer data) +static void +transformation_change_callback (bool transformations_pending, + gpointer data) { struct data_editor *de = data; + GtkWidget *menuitem = + get_widget_assert (de->xml, "transform_run-pending"); + GtkWidget *status_label = + get_widget_assert (de->xml, "case-counter-area"); - GtkWidget *menuitem = get_widget_assert (de->xml, "edit_clear"); + gtk_widget_set_sensitive (menuitem, transformations_pending); - gtk_widget_set_sensitive (menuitem, FALSE); - return FALSE; + if ( transformations_pending) + gtk_label_set_text (GTK_LABEL (status_label), + _("Transformations Pending")); + else + gtk_label_set_text (GTK_LABEL (status_label), ""); } + static void open_data_file (const gchar *, struct data_editor *); @@ -188,6 +217,8 @@ datum_entry_activate (GtkEntry *entry, gpointer data) psppire_data_store_set_string (store, text, row, column); } +extern struct dataset *the_dataset; + /* Create a new data editor. */ @@ -207,6 +238,11 @@ new_data_editor (void) de->xml = XML_NEW ("data-editor.glade"); + + dataset_add_transform_change_callback (the_dataset, + transformation_change_callback, + de); + var_sheet = GTK_SHEET (get_widget_assert (de->xml, "variable_sheet")); data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet")); @@ -241,6 +277,55 @@ new_data_editor (void) register_data_editor_actions (de); + de->toggle_value_labels = + gtk_toggle_action_new ("toggle-value-labels", + _("Labels"), + _("Show (hide) value labels"), + "pspp-value-labels"); + + g_signal_connect (de->toggle_value_labels, "activate", + G_CALLBACK (toggle_value_labels), de); + + + gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels), + get_widget_assert (de->xml, + "togglebutton-value-labels")); + + + gtk_action_connect_proxy (GTK_ACTION (de->toggle_value_labels), + get_widget_assert (de->xml, + "view_value-labels")); + + de->delete_cases = + gtk_action_new ("clear-cases", + _("Clear"), + _("Delete the cases at the selected position(s)"), + "pspp-clear-cases"); + + g_signal_connect (de->delete_cases, "activate", + G_CALLBACK (delete_cases), de); + + gtk_action_connect_proxy (de->delete_cases, + get_widget_assert (de->xml, "edit_clear-cases")); + + + gtk_action_set_visible (de->delete_cases, FALSE); + + de->delete_variables = + gtk_action_new ("clear-variables", + _("Clear"), + _("Delete the variables at the selected position(s)"), + "pspp-clear-variables"); + + g_signal_connect (de->delete_variables, "activate", + G_CALLBACK (delete_variables), de); + + gtk_action_connect_proxy (de->delete_variables, + get_widget_assert (de->xml, "edit_clear-variables") + ); + + gtk_action_set_visible (de->delete_variables, FALSE); + de->insert_variable = gtk_action_new ("insert-variable", _("Insert Variable"), @@ -343,6 +428,15 @@ new_data_editor (void) g_signal_connect (de->invoke_sort_cases_dialog, "activate", G_CALLBACK (sort_cases_dialog), de); + de->invoke_select_cases_dialog = + gtk_action_new ("select-cases-dialog", + _("Select Cases"), + _("Select cases from the active file"), + "pspp-select-cases"); + + g_signal_connect (de->invoke_select_cases_dialog, "activate", + G_CALLBACK (select_cases_dialog), de); + de->invoke_compute_dialog = gtk_action_new ("compute-dialog", @@ -447,14 +541,6 @@ new_data_editor (void) G_CALLBACK (gtk_action_activate), de->action_data_save_as); - - g_signal_connect (get_widget_assert (de->xml,"edit_clear"), - "activate", - G_CALLBACK (on_clear_activate), - de); - - - gtk_action_connect_proxy (de->invoke_weight_cases_dialog, get_widget_assert (de->xml, "data_weight-cases") ); @@ -471,6 +557,10 @@ new_data_editor (void) get_widget_assert (de->xml, "data_sort-cases") ); + gtk_action_connect_proxy (de->invoke_select_cases_dialog, + get_widget_assert (de->xml, "data_select-cases") + ); + gtk_action_connect_proxy (de->invoke_compute_dialog, get_widget_assert (de->xml, "transform_compute") ); @@ -500,37 +590,31 @@ new_data_editor (void) de); g_signal_connect (data_sheet, - "select-row", - GTK_SIGNAL_FUNC (enable_edit_clear), + "select-column", + G_CALLBACK (enable_delete_variables), de); g_signal_connect (data_sheet, - "activate", - GTK_SIGNAL_FUNC (disable_edit_clear), + "select-row", + G_CALLBACK (enable_delete_cases), de); + g_signal_connect (var_sheet, "double-click-row", GTK_SIGNAL_FUNC (click2row), de); - g_signal_connect (var_sheet, + g_signal_connect_after (var_sheet, "select-row", - GTK_SIGNAL_FUNC (enable_edit_clear), + G_CALLBACK (enable_delete_variables), de); - g_signal_connect (get_widget_assert (de->xml, "variable_sheet"), - "activate", - GTK_SIGNAL_FUNC (disable_edit_clear), - de); - - g_signal_connect (get_widget_assert (de->xml, "notebook"), "switch-page", G_CALLBACK (data_var_select), de); - g_signal_connect (get_widget_assert (de->xml, "view_statusbar"), "activate", G_CALLBACK (status_bar_activate), de); @@ -558,14 +642,6 @@ new_data_editor (void) - g_signal_connect (get_widget_assert (de->xml, "view_valuelabels"), - "activate", - G_CALLBACK (value_labels_activate), de); - - - g_signal_connect (get_widget_assert (de->xml, "togglebutton-value-labels"), - "toggled", - G_CALLBACK (value_labels_toggled), de); gtk_action_connect_proxy (de->action_data_open, get_widget_assert (de->xml, "button-open") @@ -587,17 +663,39 @@ new_data_editor (void) get_widget_assert (de->xml, "button-split-file") ); + gtk_action_connect_proxy (de->invoke_select_cases_dialog, + get_widget_assert (de->xml, "button-select-cases") + ); + + g_signal_connect (get_widget_assert (de->xml, "file_quit"), "activate", G_CALLBACK (file_quit), de); + g_signal_connect (get_widget_assert (de->xml, "transform_run-pending"), + "activate", + G_CALLBACK (execute), de); + g_signal_connect (get_widget_assert (de->xml, "windows_minimise_all"), "activate", G_CALLBACK (minimise_all_windows), NULL); - select_sheet (de, PAGE_DATA_SHEET); + create_data_sheet_variable_popup_menu (de); + create_data_sheet_cases_popup_menu (de); + + g_signal_connect (G_OBJECT (data_sheet), "button-event-column", + G_CALLBACK (popup_variable_menu), de); + + g_signal_connect (G_OBJECT (data_sheet), "button-event-row", + G_CALLBACK (popup_cases_menu), de); + + /* The "switch-page" signal does get emitted unless the page actually + changes. But the state is indeterminate at startup. Therefore we + must explicitly change it to one state, then the other */ + data_editor_select_sheet (de, PAGE_VAR_SHEET); + data_editor_select_sheet (de, PAGE_DATA_SHEET); return de; } @@ -664,8 +762,13 @@ new_data_window (GtkMenuItem *menuitem, gpointer parent) static void -select_sheet (struct data_editor *de, guint page_num) +data_var_select (GtkNotebook *notebook, + GtkNotebookPage *page, + guint page_num, + gpointer user_data) { + struct data_editor *de = user_data; + GtkWidget *view_data = get_widget_assert (de->xml, "view_data"); GtkWidget *view_variables = get_widget_assert (de->xml, "view_variables"); @@ -691,20 +794,6 @@ select_sheet (struct data_editor *de, guint page_num) } -static void -data_var_select (GtkNotebook *notebook, - GtkNotebookPage *page, - guint page_num, - gpointer user_data) -{ - struct data_editor *de = user_data; - - select_sheet (de, page_num); -} - - - - void data_editor_select_sheet (struct data_editor *de, gint page) { @@ -715,6 +804,7 @@ data_editor_select_sheet (struct data_editor *de, gint page) } + static void status_bar_activate (GtkCheckMenuItem *menuitem, gpointer data) { @@ -797,84 +887,74 @@ fonts_activate (GtkMenuItem *menuitem, gpointer data) } -/* The next two callbacks are mutually co-operative */ -/* Callback for the value labels menu item */ +/* Callback for the value labels action */ static void -value_labels_activate (GtkCheckMenuItem *menuitem, gpointer data) +toggle_value_labels (GtkToggleAction *ta, gpointer data) { struct data_editor *de = data; GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet")); - GtkToggleToolButton *tb = - GTK_TOGGLE_TOOL_BUTTON (get_widget_assert (de->xml, - "togglebutton-value-labels")); - PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet)); - gboolean show_value_labels = gtk_check_menu_item_get_active (menuitem); - - gtk_toggle_tool_button_set_active (tb, show_value_labels); - psppire_data_store_show_labels (ds, show_value_labels); + psppire_data_store_show_labels (ds, + gtk_toggle_action_get_active (ta)); } -/* Callback for the value labels tooglebutton */ static void -value_labels_toggled (GtkToggleToolButton *toggle_tool_button, - gpointer data) +file_quit (GtkCheckMenuItem *menuitem, gpointer data) +{ + /* FIXME: Need to be more intelligent here. + Give the user the opportunity to save any unsaved data. + */ + gtk_main_quit (); +} + +static void +delete_cases (GtkAction *action, gpointer data) { struct data_editor *de = data; + GtkSheet *data_sheet = + GTK_SHEET (get_widget_assert (de->xml, "data_sheet")); - GtkSheet *data_sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet")); + GtkSheetRange range; - GtkCheckMenuItem *item = - GTK_CHECK_MENU_ITEM (get_widget_assert (de->xml, "view_valuelabels")); + PsppireDataStore *data_store = PSPPIRE_DATA_STORE + (gtk_sheet_get_model (data_sheet) ); - PsppireDataStore *ds = PSPPIRE_DATA_STORE (gtk_sheet_get_model (data_sheet)); - gboolean show_value_labels = - gtk_toggle_tool_button_get_active (toggle_tool_button); + /* This shouldn't be able to happen, because the action + should be disabled */ + g_return_if_fail (gtk_sheet_get_state (data_sheet) + == GTK_SHEET_ROW_SELECTED ); - gtk_check_menu_item_set_active (item, show_value_labels); + gtk_sheet_get_selected_range (data_sheet, &range); - psppire_data_store_show_labels (ds, show_value_labels); -} + gtk_sheet_unselect_range (data_sheet); + psppire_data_store_delete_cases (data_store, range.row0, + 1 + range.rowi - range.row0); -static void -file_quit (GtkCheckMenuItem *menuitem, gpointer data) -{ - /* FIXME: Need to be more intelligent here. - Give the user the opportunity to save any unsaved data. - */ - gtk_main_quit (); } - -/* Callback for when the Clear item in the edit menu is activated */ static void -on_clear_activate (GtkMenuItem *menuitem, gpointer data) +delete_variables (GtkAction *a, gpointer data) { struct data_editor *de = data; - - GtkSheet *sheet = NULL; - GtkSheetRange range ; + GtkSheetRange range; GtkNotebook *notebook = GTK_NOTEBOOK (get_widget_assert (de->xml, "notebook")); const gint page = gtk_notebook_get_current_page (notebook); - sheet = GTK_SHEET - (get_widget_assert (de->xml, - (page == PAGE_VAR_SHEET) ? "variable_sheet" : "data_sheet")); - - /* This shouldn't be able to happen, because the menuitem - should be disabled */ - g_return_if_fail (gtk_sheet_get_state (sheet) == GTK_SHEET_ROW_SELECTED ); + GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml, + (page == PAGE_VAR_SHEET) ? + "variable_sheet" : + "data_sheet")); gtk_sheet_get_selected_range (sheet, &range); @@ -883,9 +963,8 @@ on_clear_activate (GtkMenuItem *menuitem, gpointer data) { case PAGE_VAR_SHEET: { - PsppireVarStore *vs = PSPPIRE_VAR_STORE - (gtk_sheet_get_model (sheet) ); - + PsppireVarStore *vs = + PSPPIRE_VAR_STORE (gtk_sheet_get_model (sheet)); psppire_dict_delete_variables (vs->dict, range.row0, @@ -896,23 +975,17 @@ on_clear_activate (GtkMenuItem *menuitem, gpointer data) break; case PAGE_DATA_SHEET: { - PsppireDataStore *data_store = PSPPIRE_DATA_STORE - (gtk_sheet_get_model (sheet) ); - - - /* This shouldn't be able to happen, because the menuitem - should be disabled */ - g_return_if_fail (gtk_sheet_get_state (sheet) - == GTK_SHEET_ROW_SELECTED ); - + PsppireDataStore *ds = + PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet)); - psppire_data_store_delete_cases (data_store, range.row0, - 1 + range.rowi - range.row0); + psppire_dict_delete_variables (ds->dict, + range.col0, + 1 + + range.coli - + range.col0 ); } break; - default: - g_assert_not_reached (); - } + }; gtk_sheet_unselect_range (sheet); } @@ -997,7 +1070,8 @@ on_split_change (PsppireDict *dict, gpointer data) { gint i; GString *text; - const struct variable *const * split_vars = dict_get_split_vars (dict->dict); + const struct variable *const * split_vars = + dict_get_split_vars (dict->dict); text = g_string_new (_("Split by ")); @@ -1446,3 +1520,196 @@ update_data_ref_entry (const GtkSheet *sheet, gint row, gint col, gpointer data) return FALSE; } + + + + + +static void +do_sort (PsppireDataStore *ds, int var, gboolean descend) +{ + GString *string = g_string_new ("SORT CASES BY "); + + const struct variable *v = + psppire_dict_get_variable (ds->dict, var); + + g_string_append_printf (string, "%s", var_get_name (v)); + + if ( descend ) + g_string_append (string, " (D)"); + + g_string_append (string, "."); + + execute_syntax (create_syntax_string_source (string->str)); + + g_string_free (string, TRUE); +} + + +static void +sort_up (GtkMenuItem *item, gpointer data) +{ + GtkSheet *sheet = data; + GtkSheetRange range; + gtk_sheet_get_selected_range (sheet, &range); + + do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)), + range.col0, FALSE); + +} + +static void +sort_down (GtkMenuItem *item, gpointer data) +{ + GtkSheet *sheet = data; + GtkSheetRange range; + gtk_sheet_get_selected_range (sheet, &range); + + do_sort (PSPPIRE_DATA_STORE (gtk_sheet_get_model(sheet)), + range.col0, TRUE); +} + + + + +static void +create_data_sheet_variable_popup_menu (struct data_editor *de) +{ + GtkSheet *sheet = GTK_SHEET (get_widget_assert (de->xml, "data_sheet")); + GtkWidget *menu = gtk_menu_new (); + + GtkWidget *sort_ascending = + gtk_menu_item_new_with_label (_("Sort Ascending")); + + GtkWidget *sort_descending = + gtk_menu_item_new_with_label (_("Sort Descending")); + + + GtkWidget *insert_variable = + gtk_menu_item_new_with_label (_("Insert Variable")); + + GtkWidget *clear_variable = + gtk_menu_item_new_with_label (_("Clear")); + + + gtk_action_connect_proxy (de->insert_variable, + insert_variable ); + + + gtk_action_connect_proxy (de->delete_variables, + clear_variable ); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_variable); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + gtk_separator_menu_item_new ()); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), clear_variable); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + gtk_separator_menu_item_new ()); + + + g_signal_connect (G_OBJECT (sort_ascending), "activate", + G_CALLBACK (sort_up), sheet); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_ascending); + + + g_signal_connect (G_OBJECT (sort_descending), "activate", + G_CALLBACK (sort_down), sheet); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), sort_descending); + + gtk_widget_show_all (menu); + + + de->data_sheet_variable_popup_menu = GTK_MENU(menu); +} + + +static void +create_data_sheet_cases_popup_menu (struct data_editor *de) +{ + GtkWidget *menu = gtk_menu_new (); + + GtkWidget *insert_case = + gtk_menu_item_new_with_label (_("Insert Case")); + + GtkWidget *delete_case = + gtk_menu_item_new_with_label (_("Clear")); + + + gtk_action_connect_proxy (de->insert_case, + insert_case); + + + gtk_action_connect_proxy (de->delete_cases, + delete_case); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), insert_case); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), + gtk_separator_menu_item_new ()); + + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), delete_case); + + + gtk_widget_show_all (menu); + + + de->data_sheet_cases_popup_menu = GTK_MENU (menu); +} + + +static void +popup_variable_menu (GtkSheet *sheet, gint column, + GdkEventButton *event, gpointer data) +{ + struct data_editor *de = data; + + PsppireDataStore *data_store = + PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet)); + + const struct variable *v = + psppire_dict_get_variable (data_store->dict, column); + + if ( v && event->button == 3) + { + + gtk_sheet_select_column (sheet, column); + + gtk_menu_popup (GTK_MENU (de->data_sheet_variable_popup_menu), + NULL, NULL, NULL, NULL, + event->button, event->time); + } +} + + +static void +popup_cases_menu (GtkSheet *sheet, gint row, + GdkEventButton *event, gpointer data) +{ + struct data_editor *de = data; + + PsppireDataStore *data_store = + PSPPIRE_DATA_STORE (gtk_sheet_get_model (sheet)); + + if ( row <= psppire_data_store_get_case_count (data_store) && + event->button == 3) + { + gtk_sheet_select_row (sheet, row); + + gtk_menu_popup (GTK_MENU (de->data_sheet_cases_popup_menu), + NULL, NULL, NULL, NULL, + event->button, event->time); + } +}