/* 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
#include "libpspp/range-set.h"
#include "libpspp/str.h"
#include "ui/gui/helper.h"
-#include "ui/gui/pspp-sheet-selection.h"
#include "ui/gui/psppire-data-store.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 "value-variant.h"
+
+
#include "ui/gui/efficient-sheet/jmd-sheet.h"
+#include "ui/gui/efficient-sheet/jmd-sheet-body.h"
#include <gettext.h>
#define _(msgid) gettext (msgid)
create_spin_renderer (GType type)
{
GtkCellRenderer *r = gtk_cell_renderer_spin_new ();
-
+
GtkAdjustment *adj = gtk_adjustment_new (0,
0, G_MAXDOUBLE,
1, 1,
g_object_set (r,
"adjustment", adj,
NULL);
-
+
return r;
}
create_combo_renderer (GType type)
{
GtkListStore *list_store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
-
+
GEnumClass *ec = g_type_class_ref (type);
-
+
const GEnumValue *ev ;
for (ev = ec->values; ev->value_name; ++ev)
{
case DICT_TVM_COL_DECIMAL:
case DICT_TVM_COL_COLUMNS:
return xx;
-
+
case DICT_TVM_COL_ALIGNMENT:
return alignment_renderer;
case DICT_TVM_COL_MEASURE:
return measure_renderer;
-
+
case DICT_TVM_COL_ROLE:
return column_width_renderer;
}
-
+
return NULL;
}
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)
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);
}
PROP_DATA_STORE,
PROP_DICTIONARY,
PROP_VALUE_LABELS,
- PROP_SPLIT_WINDOW,
- PROP_UI_MANAGER
+ PROP_SPLIT_WINDOW
};
static void
{
const struct variable *var = psppire_dict_get_variable (store->dict, col);
+ if (NULL == var)
+ return;
+
union value v;
- value_init (&v, var_get_width (var));
- v.f = g_value_get_double (value);
-
+
+ GVariant *vrnt = g_value_get_variant (value);
+
+ value_variant_get (&v, vrnt);
+
psppire_data_store_set_value (store, row, var, &v);
- value_destroy (&v, var_get_width (var));
+ value_destroy_from_variant (&v, vrnt);
}
static void
g_signal_connect_swapped (de->data_sheet, "value-changed",
G_CALLBACK (change_data_value), de->data_store);
-
+
g_signal_connect_swapped (de->data_store, "case-changed",
G_CALLBACK (refresh_entry), de);
break;
case PROP_VALUE_LABELS:
break;
- case PROP_UI_MANAGER:
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
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;
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
GtkWidget *widget)
{
GTK_CONTAINER_CLASS (parent_class)->set_focus_child (container, widget);
- psppire_data_editor_update_ui_manager (PSPPIRE_DATA_EDITOR (container));
+
}
static void
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);
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),
jmd_sheet_scroll_to (JMD_SHEET (de->data_sheet), dict_index, -1);
}
+
static void
on_data_sheet_var_double_clicked (JmdSheet *data_sheet, gint dict_index,
PsppireDataEditor *de)
{
+
gtk_notebook_set_current_page (GTK_NOTEBOOK (de),
PSPPIRE_DATA_EDITOR_VARIABLE_VIEW);
}
+
/* Refreshes 'de->cell_ref_label' and 'de->datum_entry' from the currently
active cell or cells. */
static void
refresh_entry (PsppireDataEditor *de)
{
- g_print ("%s\n", __FUNCTION__);
+ union value val;
+ gint row, col;
+ jmd_sheet_get_active_cell (JMD_SHEET (de->data_sheet), &col, &row);
+
+ const struct variable *var = psppire_dict_get_variable (de->dict, col);
+ 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
{
/* A single cell is selected */
const struct variable *var = psppire_dict_get_variable (de->dict, sel->start_x);
-
- ref_cell_text = g_strdup_printf (_("%d : %s"),
- sel->start_y + 1, var_get_name (var));
+
+ if (var)
+ ref_cell_text = g_strdup_printf (_("%d : %s"),
+ sel->start_y + 1, var_get_name (var));
}
else
{
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);
+gchar *myconvfunc (GtkTreeModel *m, gint col, gint row, const GValue *v);
+void myreversefunc (GtkTreeModel *model, gint col, gint row, const gchar *in, GValue *out);
+
+
+static void
+delete_cases (PsppireDataEditor *de)
+{
+ JmdRange *range = JMD_SHEET(de->data_sheet)->selection;
+
+ psppire_data_store_delete_cases (de->data_store, range->start_y,
+ range->end_y - range->start_y + 1);
+
+ gtk_widget_queue_draw (GTK_WIDGET (de));
+}
+
+static void
+insert_new_case (PsppireDataEditor *de)
+{
+ gint item = GPOINTER_TO_INT (g_object_get_data
+ (G_OBJECT (de->data_sheet_cases_row_popup), "item"));
+
+ psppire_data_store_insert_new_case (de->data_store, item);
+
+ gtk_widget_queue_draw (GTK_WIDGET (de));
+}
+
+static GtkWidget *
+create_row_header_popup_menu (PsppireDataEditor *de)
+{
+ GtkWidget *menu = gtk_menu_new ();
+
+ GtkWidget *item =
+ gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
+
+ g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_case), de);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ de->clear_cases_menu_item = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
+ gtk_widget_set_sensitive (de->clear_cases_menu_item, FALSE);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), de->clear_cases_menu_item);
+ g_signal_connect_swapped (de->clear_cases_menu_item, "activate",
+ G_CALLBACK (delete_cases), de);
+
+ gtk_widget_show_all (menu);
+ return menu;
+}
+
+static GtkWidget *
+create_column_header_popup_menu (PsppireDataEditor *de)
+{
+ GtkWidget *menu = gtk_menu_new ();
+
+ GtkWidget *item =
+ gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item =
+ gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+
+ item =
+ gtk_menu_item_new_with_mnemonic (_("Sort _Ascending"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item =
+ gtk_menu_item_new_with_mnemonic (_("Sort _Descending"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ gtk_widget_show_all (menu);
+ return menu;
+}
+
+
+static void
+set_clear_cases_sensitivity (JmdSheet *sheet, gpointer selection, gpointer p)
+{
+ JmdRange *range = selection;
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (p);
+ gint width = gtk_tree_model_get_n_columns (sheet->data_model);
+
+ gboolean whole_row_selected = (range->start_x == 0 && range->end_x == width - 1);
+ gtk_widget_set_sensitive (de->clear_cases_menu_item, whole_row_selected);
+}
+
+static void
+show_cases_row_popup (JmdSheet *sheet, int row, uint button, uint state, gpointer p)
+{
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (p);
+ GListModel *vmodel = NULL;
+ g_object_get (sheet, "vmodel", &vmodel, NULL);
+ if (vmodel == NULL)
+ return;
+
+ guint n_items = g_list_model_get_n_items (vmodel);
+
+ if (row >= n_items)
+ return;
+
+ if (button != 3)
+ return;
+
+ g_object_set_data (G_OBJECT (de->data_sheet_cases_row_popup), "item",
+ GINT_TO_POINTER (row));
+
+ gtk_menu_popup_at_pointer (GTK_MENU (de->data_sheet_cases_row_popup), NULL);
+}
+
+static void
+show_cases_column_popup (JmdSheet *sheet, int column, uint button, uint state,
+ gpointer p)
+{
+ PsppireDataEditor *de = PSPPIRE_DATA_EDITOR (p);
+ GListModel *hmodel = NULL;
+ g_object_get (sheet, "hmodel", &hmodel, NULL);
+ if (hmodel == NULL)
+ return;
+
+ guint n_items = g_list_model_get_n_items (hmodel);
+
+ if (column >= n_items)
+ return;
+
+ if (button != 3)
+ return;
+
+ g_object_set_data (G_OBJECT (de->data_sheet_cases_column_popup), "item",
+ GINT_TO_POINTER (column));
+
+ gtk_menu_popup_at_pointer (GTK_MENU (de->data_sheet_cases_column_popup), NULL);
+}
+
+
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);
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);
+ de->data_sheet = jmd_sheet_new ();
+
+ de->data_sheet_cases_column_popup = create_column_header_popup_menu (de);
+ de->data_sheet_cases_row_popup = create_row_header_popup_menu (de);
+ g_signal_connect (de->data_sheet, "row-header-pressed",
+ G_CALLBACK (show_cases_row_popup), de);
+
+ g_signal_connect (de->data_sheet, "column-header-pressed",
+ G_CALLBACK (show_cases_column_popup), de);
+
+ g_signal_connect (de->data_sheet, "selection-changed",
+ G_CALLBACK (set_clear_cases_sensitivity), de);
+
+ jmd_sheet_body_set_conversion_func
+ (JMD_SHEET_BODY (JMD_SHEET(de->data_sheet)->selected_body),
+ myconvfunc, myreversefunc);
+
GtkWidget *data_button = jmd_sheet_get_button (JMD_SHEET (de->data_sheet));
gtk_button_set_label (GTK_BUTTON (data_button), _("Case"));
de->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 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")));
de->var_sheet = g_object_new (JMD_TYPE_SHEET, NULL);
PsppireVarSheetHeader *vsh = g_object_new (PSPPIRE_TYPE_VAR_SHEET_HEADER, NULL);
-
+
g_object_set (de->var_sheet,
"hmodel", vsh,
"select-renderer-func", select_renderer_func,
NULL);
-
+
GtkWidget *var_button = jmd_sheet_get_button (JMD_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);
set_font_recursively (GTK_WIDGET (de), de->font);
}
- psppire_data_editor_update_ui_manager (de);
}
GtkWidget*
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 (JMD_SHEET (de->var_sheet), "gridlines", grid_visible, NULL);
+ g_object_set (JMD_SHEET (de->data_sheet), "gridlines", grid_visible, NULL);
}
{
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);
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.
de->split = split;
g_object_notify (G_OBJECT (de), "split");
- psppire_data_editor_update_ui_manager (de);
}
/* Makes the variable with dictionary index DICT_INDEX in DE's dictionary
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.
-
- 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;
-}
-
-static void
-psppire_data_editor_update_ui_manager (PsppireDataEditor *de)
-{
- 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");
- }
-}