X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpsppire-data-editor.c;h=0efd8ce835186de958d58e28f704b1ff9c38e83d;hb=4ad4fcab6c886b1a6f29769a374b67b2f60173a9;hp=7838e5f810d206bc7cb5fabe5ba41dd13f013f4d;hpb=978053dda1b3dd918e0a814cb5bd282cd2d3774c;p=pspp diff --git a/src/ui/gui/psppire-data-editor.c b/src/ui/gui/psppire-data-editor.c index 7838e5f810..0efd8ce835 100644 --- a/src/ui/gui/psppire-data-editor.c +++ b/src/ui/gui/psppire-data-editor.c @@ -1,5 +1,6 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. + Copyright (C) 2008, 2009, 2010, 2011, 2012, 2016, + 2017 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,32 +20,35 @@ #include "ui/gui/psppire-data-editor.h" #include -#include #include "data/datasheet.h" #include "data/value-labels.h" #include "libpspp/range-set.h" #include "libpspp/str.h" + #include "ui/gui/helper.h" -#include "ui/gui/pspp-sheet-selection.h" +#include "ui/gui/var-display.h" +#include "ui/gui/val-labs-dialog.h" +#include "ui/gui/missing-val-dialog.h" +#include "ui/gui/var-type-dialog.h" +#include "ui/gui/psppire-dict.h" #include "ui/gui/psppire-data-store.h" +#include "ui/gui/psppire-data-window.h" #include "ui/gui/psppire-value-entry.h" -#include "ui/gui/psppire-var-sheet.h" #include "ui/gui/psppire-conf.h" -#include "ui/gui/psppire-var-sheet-header.h" +#include "ui/gui/psppire-variable-sheet.h" +#include "ui/gui/psppire-data-sheet.h" + -#include "ui/gui/efficient-sheet/jmd-sheet.h" +#include #include #define _(msgid) gettext (msgid) - static void psppire_data_editor_class_init (PsppireDataEditorClass *klass); static void psppire_data_editor_init (PsppireDataEditor *de); -static void disconnect_data_sheets (PsppireDataEditor *); static void refresh_entry (PsppireDataEditor *); -static void psppire_data_editor_update_ui_manager (PsppireDataEditor *); GType psppire_data_editor_get_type (void) @@ -80,8 +84,6 @@ psppire_data_editor_dispose (GObject *obj) { PsppireDataEditor *de = (PsppireDataEditor *) obj; - disconnect_data_sheets (de); - if (de->data_store) { g_object_unref (de->data_store); @@ -100,12 +102,6 @@ psppire_data_editor_dispose (GObject *obj) de->font = NULL; } - if (de->ui_manager) - { - g_object_unref (de->ui_manager); - de->ui_manager = NULL; - } - /* Chain up to the parent class */ G_OBJECT_CLASS (parent_class)->dispose (obj); } @@ -116,8 +112,7 @@ enum PROP_DATA_STORE, PROP_DICTIONARY, PROP_VALUE_LABELS, - PROP_SPLIT_WINDOW, - PROP_UI_MANAGER + PROP_SPLIT_WINDOW }; static void @@ -125,6 +120,7 @@ psppire_data_editor_refresh_model (PsppireDataEditor *de) { } + static void psppire_data_editor_set_property (GObject *object, guint prop_id, @@ -136,7 +132,9 @@ psppire_data_editor_set_property (GObject *object, switch (prop_id) { case PROP_SPLIT_WINDOW: - psppire_data_editor_split_window (de, g_value_get_boolean (value)); + de->split = g_value_get_boolean (value); + g_object_set (de->data_sheet, "split", de->split, NULL); + g_object_set (de->var_sheet, "split", de->split, NULL); break; case PROP_DATA_STORE: if ( de->data_store) @@ -149,11 +147,14 @@ psppire_data_editor_set_property (GObject *object, de->data_store = g_value_get_pointer (value); g_object_ref (de->data_store); - g_print ("NEW STORE\n"); g_object_set (de->data_sheet, "data-model", de->data_store, NULL); psppire_data_editor_refresh_model (de); + g_signal_connect_swapped (de->data_sheet, "selection-changed", + G_CALLBACK (refresh_entry), + de); + g_signal_connect_swapped (de->data_store, "case-changed", G_CALLBACK (refresh_entry), de); @@ -164,13 +165,20 @@ psppire_data_editor_set_property (GObject *object, de->dict = g_value_get_pointer (value); g_object_ref (de->dict); - g_object_set (de->data_sheet, "hmodel", de->dict, NULL); g_object_set (de->var_sheet, "data-model", de->dict, NULL); - break; + case PROP_VALUE_LABELS: + { + gboolean l = g_value_get_boolean (value); + g_object_set (de->data_sheet, "forward-conversion", + l ? + psppire_data_store_value_to_string_with_labels : + psppire_data_store_value_to_string, + NULL); + } break; - case PROP_UI_MANAGER: + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -198,9 +206,6 @@ psppire_data_editor_get_property (GObject *object, break; case PROP_VALUE_LABELS: break; - case PROP_UI_MANAGER: - g_value_set_object (value, psppire_data_editor_get_ui_manager (de)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -213,7 +218,6 @@ psppire_data_editor_switch_page (GtkNotebook *notebook, guint page_num) { GTK_NOTEBOOK_CLASS (parent_class)->switch_page (notebook, w, page_num); - psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (notebook)); } static void @@ -221,7 +225,6 @@ psppire_data_editor_set_focus_child (GtkContainer *container, GtkWidget *widget) { GTK_CONTAINER_CLASS (parent_class)->set_focus_child (container, widget); - psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (container)); } static void @@ -231,7 +234,7 @@ psppire_data_editor_class_init (PsppireDataEditorClass *klass) GParamSpec *dict_spec ; GParamSpec *value_labels_spec; GParamSpec *split_window_spec; - GParamSpec *ui_manager_spec; + GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass); @@ -288,70 +291,178 @@ psppire_data_editor_class_init (PsppireDataEditorClass *klass) g_object_class_install_property (object_class, PROP_SPLIT_WINDOW, split_window_spec); - - ui_manager_spec = - g_param_spec_object ("ui-manager", - "UI Manager", - "UI manager for the active notebook tab. The client should merge this UI manager with the active UI manager to obtain menu items and tool bar items specific to the active notebook tab.", - GTK_TYPE_UI_MANAGER, - G_PARAM_READABLE); - g_object_class_install_property (object_class, - PROP_UI_MANAGER, - ui_manager_spec); } static void -on_var_sheet_var_double_clicked (PsppireVarSheet *var_sheet, gint dict_index, +on_var_sheet_var_double_clicked (void *var_sheet, gint dict_index, PsppireDataEditor *de) { gtk_notebook_set_current_page (GTK_NOTEBOOK (de), PSPPIRE_DATA_EDITOR_DATA_VIEW); - jmd_sheet_scroll_to (de->data_sheet, dict_index, -1); + ssw_sheet_scroll_to (SSW_SHEET (de->data_sheet), dict_index, -1); } + static void -on_data_sheet_var_double_clicked (JmdSheet *data_sheet, gint dict_index, +on_data_sheet_var_double_clicked (SswSheet *data_sheet, gint dict_index, PsppireDataEditor *de) { + gtk_notebook_set_current_page (GTK_NOTEBOOK (de), PSPPIRE_DATA_EDITOR_VARIABLE_VIEW); - jmd_sheet_scroll_to (de->var_sheet, -1, dict_index); + ssw_sheet_scroll_to (SSW_SHEET (de->var_sheet), -1, dict_index); } + /* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently active cell or cells. */ static void refresh_entry (PsppireDataEditor *de) { + gint row, col; + if (ssw_sheet_get_active_cell (SSW_SHEET (de->data_sheet), &col, &row)) + { + union value val; + const struct variable *var = psppire_dict_get_variable (de->dict, col); + if (var == NULL) + return; + + psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (de->datum_entry), var); + + int width = var_get_width (var); + if (! psppire_data_store_get_value (PSPPIRE_DATA_STORE (de->data_store), + row, var, &val)) + return; + + psppire_value_entry_set_value (PSPPIRE_VALUE_ENTRY (de->datum_entry), + &val, width); + value_destroy (&val, width); + } } static void -on_datum_entry_activate (PsppireValueEntry *entry, PsppireDataEditor *de) +on_datum_entry_activate (GtkEntry *entry, PsppireDataEditor *de) { + gint row, col; + if (ssw_sheet_get_active_cell (SSW_SHEET (de->data_sheet), &col, &row)) + { + union value val; + const struct variable *var = psppire_dict_get_variable (de->dict, col); + if (var == NULL) + return; + + value_init (&val, var_get_width (var)); + + if (psppire_value_entry_get_value (de->datum_entry, &val, var_get_width (var))) + { + psppire_data_store_set_value (de->data_store, row, var, &val); + } + } } +/* Called when the active cell or the selection in the data sheet changes */ static void -disconnect_data_sheets (PsppireDataEditor *de) +on_data_selection_change (PsppireDataEditor *de, SswRange *sel) { + gchar *ref_cell_text = NULL; + + gint n_cases = abs (sel->end_y - sel->start_y) + 1; + gint n_vars = abs (sel->end_x - sel->start_x) + 1; + + if (n_cases == 1 && n_vars == 1) + { + /* A single cell is selected */ + const struct variable *var = psppire_dict_get_variable (de->dict, sel->start_x); + + if (var) + ref_cell_text = g_strdup_printf (_("%d : %s"), + sel->start_y + 1, var_get_name (var)); + } + else + { + struct string s; + + /* The glib string library does not understand the ' printf modifier + on all platforms, but the "struct string" library does (because + Gnulib fixes that problem), so use the latter. */ + ds_init_empty (&s); + ds_put_format (&s, ngettext ("%'d case", "%'d cases", n_cases), + n_cases); + ds_put_byte (&s, ' '); + ds_put_unichar (&s, 0xd7); /* U+00D7 MULTIPLICATION SIGN */ + ds_put_byte (&s, ' '); + ds_put_format (&s, ngettext ("%'d variable", "%'d variables", + n_vars), + n_vars); + ref_cell_text = ds_steal_cstr (&s); + } + + gtk_label_set_label (GTK_LABEL (de->cell_ref_label), + ref_cell_text ? ref_cell_text : ""); + + g_free (ref_cell_text); } static void set_font_recursively (GtkWidget *w, gpointer data); + + +void +psppire_data_editor_data_delete_variables (PsppireDataEditor *de) +{ + SswRange *range = SSW_SHEET(de->data_sheet)->selection; + + psppire_dict_delete_variables (de->dict, range->start_x, + (range->end_x - range->start_x + 1)); + + gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet)); +} + +void +psppire_data_editor_var_delete_variables (PsppireDataEditor *de) +{ + SswRange *range = SSW_SHEET(de->var_sheet)->selection; + + psppire_dict_delete_variables (de->dict, range->start_y, + (range->end_y - range->start_y + 1)); + + gtk_widget_queue_draw (GTK_WIDGET (de->var_sheet)); +} + +void +psppire_data_editor_insert_new_case_at_posn (PsppireDataEditor *de, gint posn) +{ + psppire_data_store_insert_new_case (de->data_store, posn); + + gtk_widget_queue_draw (GTK_WIDGET (de->data_sheet)); +} + +void +psppire_data_editor_insert_new_variable_at_posn (PsppireDataEditor *de, gint posn) +{ + const struct variable *v = psppire_dict_insert_variable (de->dict, posn, NULL); + psppire_data_store_insert_value (de->data_store, var_get_width(v), + var_get_case_index (v)); + + gtk_widget_queue_draw (GTK_WIDGET (de)); +} + static void psppire_data_editor_init (PsppireDataEditor *de) { GtkWidget *hbox; gchar *fontname = NULL; + GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (de)); + gtk_style_context_add_class (context, "psppire-data-editor"); + de->font = NULL; - de->ui_manager = NULL; - de->old_vbox_widget = NULL; g_object_set (de, "tab-pos", GTK_POS_BOTTOM, NULL); @@ -368,33 +479,33 @@ psppire_data_editor_init (PsppireDataEditor *de) gtk_box_pack_start (GTK_BOX (hbox), de->datum_entry, TRUE, TRUE, 0); de->split = FALSE; - de->data_sheet = g_object_new (JMD_TYPE_SHEET, NULL); - GtkWidget *data_button = jmd_sheet_get_button (JMD_SHEET (de->data_sheet)); + de->data_sheet = psppire_data_sheet_new (); + + GtkWidget *data_button = ssw_sheet_get_button (SSW_SHEET (de->data_sheet)); gtk_button_set_label (GTK_BUTTON (data_button), _("Case")); de->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (de->vbox), hbox, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (de->vbox), de->data_sheet, TRUE, TRUE, 0); + + g_signal_connect_swapped (de->data_sheet, "selection-changed", + G_CALLBACK (on_data_selection_change), de); + gtk_notebook_append_page (GTK_NOTEBOOK (de), de->vbox, gtk_label_new_with_mnemonic (_("Data View"))); gtk_widget_show_all (de->vbox); - de->var_sheet = g_object_new (JMD_TYPE_SHEET, NULL); + de->var_sheet = psppire_variable_sheet_new (); - PsppireVarSheetHeader *vsh = g_object_new (PSPPIRE_TYPE_VAR_SHEET_HEADER, NULL); - - g_object_set (de->var_sheet, "hmodel", vsh, NULL); - - - GtkWidget *var_button = jmd_sheet_get_button (JMD_SHEET (de->var_sheet)); + GtkWidget *var_button = ssw_sheet_get_button (SSW_SHEET (de->var_sheet)); gtk_button_set_label (GTK_BUTTON (var_button), _("Variable")); - + gtk_notebook_append_page (GTK_NOTEBOOK (de), de->var_sheet, gtk_label_new_with_mnemonic (_("Variable View"))); gtk_widget_show_all (de->var_sheet); - + g_signal_connect (de->var_sheet, "row-header-double-clicked", G_CALLBACK (on_var_sheet_var_double_clicked), de); @@ -411,8 +522,6 @@ psppire_data_editor_init (PsppireDataEditor *de) g_free (fontname); set_font_recursively (GTK_WIDGET (de), de->font); } - - psppire_data_editor_update_ui_manager (de); } GtkWidget* @@ -430,13 +539,8 @@ psppire_data_editor_new (PsppireDict *dict, void psppire_data_editor_show_grid (PsppireDataEditor *de, gboolean grid_visible) { - GtkTreeViewGridLines grid; - - grid = (grid_visible - ? GTK_TREE_VIEW_GRID_LINES_BOTH - : GTK_TREE_VIEW_GRID_LINES_NONE); - - pspp_sheet_view_set_grid_lines (PSPP_SHEET_VIEW (de->var_sheet), grid); + g_object_set (SSW_SHEET (de->var_sheet), "gridlines", grid_visible, NULL); + g_object_set (SSW_SHEET (de->data_sheet), "gridlines", grid_visible, NULL); } @@ -445,7 +549,28 @@ set_font_recursively (GtkWidget *w, gpointer data) { PangoFontDescription *font_desc = data; - gtk_widget_override_font (w, font_desc); + GtkStyleContext *style = gtk_widget_get_style_context (w); + GtkCssProvider *cssp = gtk_css_provider_new (); + + gchar *str = pango_font_description_to_string (font_desc); + gchar *css = + g_strdup_printf ("* {font: %s}", str); + g_free (str); + + GError *err = NULL; + gtk_css_provider_load_from_data (cssp, css, -1, &err); + if (err) + { + g_warning ("Failed to load font css \"%s\": %s", css, err->message); + g_error_free (err); + } + g_free (css); + + gtk_style_context_add_provider (style, + GTK_STYLE_PROVIDER (cssp), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref (cssp); + if ( GTK_IS_CONTAINER (w)) gtk_container_foreach (GTK_CONTAINER (w), set_font_recursively, font_desc); @@ -466,7 +591,7 @@ psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_ psppire_conf_set_string (psppire_conf_new (), "Data Editor", "font", font_name); - + g_free (font_name); } /* If SPLIT is TRUE, splits DE's data sheet into four panes. @@ -474,21 +599,7 @@ psppire_data_editor_set_font (PsppireDataEditor *de, PangoFontDescription *font_ void psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split) { - if (split == de->split) - return; - - disconnect_data_sheets (de); - - psppire_data_editor_refresh_model (de); - - gtk_widget_show_all (de->vbox); - - if (de->font) - set_font_recursively (GTK_WIDGET (de), de->font); - - de->split = split; - g_object_notify (G_OBJECT (de), "split"); - psppire_data_editor_update_ui_manager (de); + g_object_set (de, "split", split, NULL); } /* Makes the variable with dictionary index DICT_INDEX in DE's dictionary @@ -496,52 +607,43 @@ psppire_data_editor_split_window (PsppireDataEditor *de, gboolean split) void psppire_data_editor_goto_variable (PsppireDataEditor *de, gint dict_index) { -} - - -/* Returns the UI manager that should be merged into DE's toplevel widget's UI - manager to display menu items and toolbar items specific to DE's current - page and data sheet. + gint page = gtk_notebook_get_current_page (GTK_NOTEBOOK (de)); - DE's toplevel widget can watch for changes by connecting to DE's - notify::ui-manager signal. */ -GtkUIManager * -psppire_data_editor_get_ui_manager (PsppireDataEditor *de) -{ - psppire_data_editor_update_ui_manager (de); - return de->ui_manager; + switch (page) + { + case PSPPIRE_DATA_EDITOR_DATA_VIEW: + ssw_sheet_scroll_to (SSW_SHEET (de->data_sheet), dict_index, -1); + ssw_sheet_set_active_cell (SSW_SHEET (de->data_sheet), dict_index, -1, NULL); + break; + case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW: + ssw_sheet_scroll_to (SSW_SHEET (de->var_sheet), -1, dict_index); + ssw_sheet_set_active_cell (SSW_SHEET (de->var_sheet), -1, dict_index, NULL); + break; + } } +/* Set the datum at COL, ROW, to that contained in VALUE. + */ static void -psppire_data_editor_update_ui_manager (PsppireDataEditor *de) +store_set_datum (GtkTreeModel *model, gint col, gint row, + const GValue *value) { - GtkUIManager *ui_manager; - - ui_manager = NULL; - - switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (de))) - { - case PSPPIRE_DATA_EDITOR_DATA_VIEW: - break; - - case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW: - break; - - default: - /* This happens transiently in psppire_data_editor_init(). */ - break; - } - - if (ui_manager != de->ui_manager) - { - if (de->ui_manager) - g_object_unref (de->ui_manager); - if (ui_manager) - g_object_ref (ui_manager); - de->ui_manager = ui_manager; - - g_object_notify (G_OBJECT (de), "ui-manager"); - } + PsppireDataStore *store = PSPPIRE_DATA_STORE (model); + GVariant *v = g_value_get_variant (value); + union value uv; + value_variant_get (&uv, v); + const struct variable *var = psppire_dict_get_variable (store->dict, col); + psppire_data_store_set_value (store, row, var, &uv); + value_destroy_from_variant (&uv, v); } +void +psppire_data_editor_paste (PsppireDataEditor *de) +{ + SswSheet *sheet = SSW_SHEET (de->data_sheet); + GtkClipboard *clip = + gtk_clipboard_get_for_display (gtk_widget_get_display (GTK_WIDGET (sheet)), + GDK_SELECTION_CLIPBOARD); + ssw_sheet_paste (sheet, clip, store_set_datum); +}