-
-static void
-do_popup_menu (GtkWidget *widget, guint button, guint32 time)
-{
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (widget);
- GtkWidget *menu;
-
- menu = get_widget_assert (data_sheet->builder, "datasheet-cases-popup");
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
-}
-
-static void
-on_popup_menu (GtkWidget *widget, gpointer user_data UNUSED)
-{
- do_popup_menu (widget, 0, gtk_get_current_event_time ());
-}
-
-static gboolean
-on_button_pressed (GtkWidget *widget, GdkEventButton *event,
- gpointer user_data UNUSED)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (widget);
-
- if (event->type == GDK_BUTTON_PRESS && event->button == 3)
- {
- PsppSheetSelection *selection;
-
- selection = pspp_sheet_view_get_selection (sheet_view);
- if (pspp_sheet_selection_count_selected_rows (selection) <= 1)
- {
- GtkTreePath *path;
-
- if (pspp_sheet_view_get_path_at_pos (sheet_view, event->x, event->y,
- &path, NULL, NULL, NULL))
- {
- pspp_sheet_selection_unselect_all (selection);
- pspp_sheet_selection_select_path (selection, path);
- pspp_sheet_selection_select_all_columns (selection);
- gtk_tree_path_free (path);
- }
- }
-
- do_popup_menu (widget, event->button, event->time);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-on_edit_clear_cases (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- const struct range_set_node *node;
- struct range_set *selected;
-
- selected = pspp_sheet_selection_get_range_set (selection);
- for (node = range_set_last (selected); node != NULL;
- node = range_set_prev (selected, node))
- {
- unsigned long int start = range_set_node_get_start (node);
- unsigned long int count = range_set_node_get_width (node);
-
- psppire_data_store_delete_cases (data_sheet->data_store, start, count);
- }
- range_set_destroy (selected);
-}
-
-static void
-on_selection_changed (PsppSheetSelection *selection,
- gpointer user_data UNUSED)
-{
- PsppSheetView *sheet_view = pspp_sheet_selection_get_tree_view (selection);
- PsppireDataSheet *data_sheet = PSPPIRE_DATA_SHEET (sheet_view);
- gint n_selected_rows;
- gboolean may_delete_cases, may_delete_vars, may_insert_vars;
- GList *list, *iter;
- GtkTreePath *path;
- GtkAction *action;
-
- n_selected_rows = pspp_sheet_selection_count_selected_rows (selection);
-
- action = get_action_assert (data_sheet->builder, "edit_insert-case");
- gtk_action_set_sensitive (action, n_selected_rows > 0);
-
- switch (n_selected_rows)
- {
- case 0:
- may_delete_cases = FALSE;
- break;
-
- case 1:
- /* The row used for inserting new cases cannot be deleted. */
- path = gtk_tree_path_new_from_indices (
- psppire_data_store_get_case_count (data_sheet->data_store), -1);
- may_delete_cases = !pspp_sheet_selection_path_is_selected (selection,
- path);
- gtk_tree_path_free (path);
- break;
-
- default:
- may_delete_cases = TRUE;
- break;
- }
- action = get_action_assert (data_sheet->builder, "edit_clear-cases");
- gtk_action_set_sensitive (action, may_delete_cases);
-
- may_delete_vars = may_insert_vars = FALSE;
- list = pspp_sheet_selection_get_selected_columns (selection);
- for (iter = list; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
-
- if (var != NULL)
- {
- may_delete_vars = may_insert_vars = TRUE;
- break;
- }
- if (g_object_get_data (G_OBJECT (column), "new-var-column") != NULL)
- may_insert_vars = TRUE;
- }
- g_list_free (list);
-
- may_insert_vars = may_insert_vars && data_sheet->may_create_vars;
- may_delete_vars = may_delete_vars && data_sheet->may_delete_vars;
-
- action = get_action_assert (data_sheet->builder, "edit_insert-variable");
- gtk_action_set_sensitive (action, may_insert_vars);
-
- action = get_action_assert (data_sheet->builder, "edit_clear-variables");
- gtk_action_set_sensitive (action, may_delete_vars);
-
- action = get_action_assert (data_sheet->builder, "sort-up");
- gtk_action_set_sensitive (action, may_delete_vars);
-
- action = get_action_assert (data_sheet->builder, "sort-down");
- gtk_action_set_sensitive (action, may_delete_vars);
-
- psppire_data_sheet_update_clip_actions (data_sheet);
-}
-
-static gboolean
-psppire_data_sheet_get_selected_range (PsppireDataSheet *data_sheet,
- struct range_set **rowsp,
- struct range_set **colsp)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppireDataStore *data_store = data_sheet->data_store;
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- unsigned long n_cases;
- struct range_set *rows, *cols;
- GList *list, *iter;
-
- if (data_store == NULL)
- return FALSE;
- n_cases = psppire_data_store_get_case_count (data_store);
-
- rows = pspp_sheet_selection_get_range_set (selection);
- range_set_set0 (rows, n_cases, ULONG_MAX - n_cases);
- if (range_set_is_empty (rows))
- {
- range_set_destroy (rows);
- return FALSE;
- }
-
- cols = range_set_create ();
- list = pspp_sheet_selection_get_selected_columns (selection);
- for (iter = list; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var = g_object_get_data (G_OBJECT (column), "variable");
-
- if (var != NULL)
- range_set_set1 (cols, var_get_dict_index (var), 1);
- }
- g_list_free (list);
- if (range_set_is_empty (cols))
- {
- range_set_destroy (rows);
- range_set_destroy (cols);
- return FALSE;
- }
-
- *rowsp = rows;
- *colsp = cols;
- return TRUE;
-}
-
-static void
-on_edit_insert_case (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDataStore *data_store = data_sheet->data_store;
- struct range_set *selected;
- unsigned long row;
-
- selected = pspp_sheet_selection_get_range_set (selection);
- row = range_set_scan (selected, 0);
- range_set_destroy (selected);
-
- if (row <= psppire_data_store_get_case_count (data_store))
- psppire_data_store_insert_new_case (data_store, row);
-}
-
-static void
-on_edit_insert_variable (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDict *dict = data_sheet->data_store->dict;
- PsppSheetViewColumn *column;
- struct variable *var;
- gchar name[64];
- GList *list;
- gint index;
-
- list = pspp_sheet_selection_get_selected_columns (selection);
- if (list == NULL)
- return;
- column = list->data;
- g_list_free (list);
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- index = var ? var_get_dict_index (var) : psppire_dict_get_var_cnt (dict);
- if (psppire_dict_generate_name (dict, name, sizeof name))
- psppire_dict_insert_variable (dict, index, name);
-}
-
-static void
-on_edit_clear_variables (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDict *dict = data_sheet->data_store->dict;
- GList *list, *iter;
-
- list = pspp_sheet_selection_get_selected_columns (selection);
- if (list == NULL)
- return;
- list = g_list_reverse (list);
- for (iter = list; iter; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var;
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- if (var != NULL)
- psppire_dict_delete_variables (dict, var_get_dict_index (var), 1);
- }
- g_list_free (list);
-}
-
-enum sort_order
- {
- SORT_ASCEND,
- SORT_DESCEND
- };
-
-static void
-do_sort (PsppireDataSheet *data_sheet, enum sort_order order)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- PsppSheetSelection *selection = pspp_sheet_view_get_selection (sheet_view);
- PsppireDataWindow *pdw;
- GList *list, *iter;
- GString *syntax;
- int n_vars;
-
- pdw = psppire_data_window_for_data_store (data_sheet->data_store);
- g_return_if_fail (pdw != NULL);
-
- list = pspp_sheet_selection_get_selected_columns (selection);
-
- syntax = g_string_new ("SORT CASES BY");
- n_vars = 0;
- for (iter = list; iter; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- struct variable *var;
-
- var = g_object_get_data (G_OBJECT (column), "variable");
- if (var != NULL)
- {
- g_string_append_printf (syntax, " %s", var_get_name (var));
- n_vars++;
- }
- }
- if (n_vars > 0)
- {
- if (order == SORT_DESCEND)
- g_string_append (syntax, " (DOWN)");
- g_string_append_c (syntax, '.');
- execute_const_syntax_string (pdw, syntax->str);
- }
- g_string_free (syntax, TRUE);
-}
-
-void
-on_sort_up (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- do_sort (data_sheet, SORT_ASCEND);
-}
-
-void
-on_sort_down (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- do_sort (data_sheet, SORT_DESCEND);
-}
-
-void
-on_edit_goto_case (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- goto_case_dialog (data_sheet);
-}
-
-void
-on_edit_find (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- PsppireDataWindow *pdw;
-
- pdw = psppire_data_window_for_data_store (data_sheet->data_store);
- g_return_if_fail (pdw != NULL);
-
- find_dialog (pdw);
-}
-
-void
-on_edit_copy (GtkAction *action, PsppireDataSheet *data_sheet)
-{
- psppire_data_sheet_set_clip (data_sheet);
-}
-
-static void
-psppire_data_sheet_init (PsppireDataSheet *obj)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (obj);
- GtkAction *action;
-
- obj->show_value_labels = FALSE;
- obj->show_case_numbers = TRUE;
- obj->may_create_vars = TRUE;
- obj->may_delete_vars = TRUE;
-
- obj->scroll_to_bottom_signal = 0;
- obj->scroll_to_right_signal = 0;
- obj->new_variable_column = NULL;
- obj->container = NULL;
-
- obj->uim = NULL;
- obj->dispose_has_run = FALSE;
-
- pspp_sheet_view_set_special_cells (sheet_view, PSPP_SHEET_VIEW_SPECIAL_CELLS_YES);
-
- g_signal_connect (obj, "notify::model",
- G_CALLBACK (psppire_data_sheet_model_changed), NULL);
-
- pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
- pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
- PSPP_SHEET_SELECTION_RECTANGLE);
-
- g_object_set (G_OBJECT (obj), "has-tooltip", TRUE, (void *) NULL);
- g_signal_connect (obj, "query-tooltip",
- G_CALLBACK (on_query_tooltip), NULL);
- g_signal_connect (obj, "button-press-event",
- G_CALLBACK (on_button_pressed), NULL);
- g_signal_connect (obj, "popup-menu", G_CALLBACK (on_popup_menu), NULL);
-
- obj->builder = builder_new ("data-sheet.ui");
-
- action = get_action_assert (obj->builder, "edit_clear-cases");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_cases),
- obj);
- gtk_action_set_sensitive (action, FALSE);
- g_signal_connect (pspp_sheet_view_get_selection (sheet_view),
- "changed", G_CALLBACK (on_selection_changed), NULL);
-
- action = get_action_assert (obj->builder, "edit_insert-case");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_case),
- obj);
-
- action = get_action_assert (obj->builder, "edit_insert-variable");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_insert_variable),
- obj);
-
- action = get_action_assert (obj->builder, "edit_goto-case");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_goto_case),
- obj);
-
- action = get_action_assert (obj->builder, "edit_copy");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_copy), obj);
-
- action = get_action_assert (obj->builder, "edit_clear-variables");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_clear_variables),
- obj);
-
- action = get_action_assert (obj->builder, "edit_find");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_find), obj);
-
- action = get_action_assert (obj->builder, "sort-up");
- g_signal_connect (action, "activate", G_CALLBACK (on_sort_up), obj);
-
- action = get_action_assert (obj->builder, "sort-down");
- g_signal_connect (action, "activate", G_CALLBACK (on_sort_down), obj);
-
-}
-
-GtkWidget *
-psppire_data_sheet_new (void)
-{
- return g_object_new (PSPP_TYPE_DATA_SHEET, NULL);
-}
-
-PsppireDataStore *
-psppire_data_sheet_get_data_store (PsppireDataSheet *data_sheet)
-{
- return data_sheet->data_store;
-}
-
-static void
-refresh_model (PsppireDataSheet *data_sheet)
-{
- pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet), NULL);
-
- if (data_sheet->data_store != NULL)
- {
- PsppireEmptyListStore *model;
- GtkAction *action;
- int n_rows;
-
- n_rows = psppire_data_store_get_case_count (data_sheet->data_store) + 1;
- model = psppire_empty_list_store_new (n_rows);
- pspp_sheet_view_set_model (PSPP_SHEET_VIEW (data_sheet),
- GTK_TREE_MODEL (model));
- g_object_unref (model);
-
- action = get_action_assert (data_sheet->builder, "edit_copy");
- g_signal_connect (action, "activate", G_CALLBACK (on_edit_copy),
- data_sheet);
- }
-}
-
-static void
-on_case_inserted (PsppireDataStore *data_store, gint row,
- PsppireDataSheet *data_sheet)
-{
- PsppireEmptyListStore *empty_list_store;
- GtkTreeModel *tree_model;
- gint n_rows;
-
- g_return_if_fail (data_store == data_sheet->data_store);
-
- n_rows = psppire_data_store_get_case_count (data_store) + 1;
- if (row == n_rows - 1)
- row++;
-
- tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
- empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
- psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
- psppire_empty_list_store_row_inserted (empty_list_store, row);
-}
-
-static void
-on_cases_deleted (PsppireDataStore *data_store, gint first, gint n_cases,
- PsppireDataSheet *data_sheet)
-{
-
- g_return_if_fail (data_store == data_sheet->data_store);
-
- if (n_cases > 1)
- {
- /* This is a bit of a cop-out. We could do better, if it ever turns out
- that this performs too poorly. */
- refresh_model (data_sheet);
- }
- else
- {
- PsppireEmptyListStore *empty_list_store;
- GtkTreeModel *tree_model;
- gint n_rows = psppire_data_store_get_case_count (data_store) + 1;
-
- tree_model = pspp_sheet_view_get_model (PSPP_SHEET_VIEW (data_sheet));
- empty_list_store = PSPPIRE_EMPTY_LIST_STORE (tree_model);
- psppire_empty_list_store_set_n_rows (empty_list_store, n_rows);
- psppire_empty_list_store_row_deleted (empty_list_store, first);
- }
-}
-
-static void
-on_case_change (PsppireDataStore *data_store, gint row,
- PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
-
- pspp_sheet_view_stop_editing (sheet_view, TRUE);
- gtk_widget_queue_draw (GTK_WIDGET (data_sheet));
-}
-
-static void
-on_backend_changed (PsppireDataStore *data_store,
- PsppireDataSheet *data_sheet)
-{
- g_return_if_fail (data_store == data_sheet->data_store);
- refresh_model (data_sheet);
-}
-
-static void
-on_variable_display_width_changed (PsppireDict *dict, int dict_index,
- PsppireDataSheet *data_sheet)
-{
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- PsppSheetViewColumn *column;
- struct variable *var;
- int display_width;
- gint pixel_width;
-
- g_return_if_fail (data_sheet->data_store != NULL);
- g_return_if_fail (dict == data_sheet->data_store->dict);
-
- column = psppire_data_sheet_find_column_for_variable (data_sheet,
- dict_index);
- if (column == NULL)
- return;
-
- var = psppire_dict_get_variable (data_store->dict, dict_index);
- g_return_if_fail (var != NULL);
-
- pixel_width = pspp_sheet_view_column_get_fixed_width (column);
- display_width = display_width_from_pixel_width (data_sheet, pixel_width);
- if (display_width != var_get_display_width (var))
- {
- gint base_width, incr_width;
-
- display_width = var_get_display_width (var);
- calc_width_conversion (data_sheet, &base_width, &incr_width);
- pixel_width = display_width_to_pixel_width (data_sheet, display_width,
- base_width, incr_width);
- pspp_sheet_view_column_set_fixed_width (column, pixel_width);
- }
-}
-
-static void
-on_variable_changed (PsppireDict *dict, int dict_index,
- PsppireDataSheet *data_sheet)
-{
- PsppireDataStore *data_store = psppire_data_sheet_get_data_store (data_sheet);
- PsppSheetViewColumn *column;
- GtkCellRenderer *cell;
- struct variable *var;
- GList *cells;
- char *name;
-
- g_return_if_fail (data_sheet->data_store != NULL);
- g_return_if_fail (dict == data_sheet->data_store->dict);
-
- column = psppire_data_sheet_find_column_for_variable (data_sheet,
- dict_index);
- if (column == NULL)
- return;
-
- var = psppire_dict_get_variable (data_store->dict, dict_index);
- g_return_if_fail (var != NULL);
-
- name = escape_underscores (var_get_name (var));
- if (strcmp (name, pspp_sheet_view_column_get_title (column)))
- pspp_sheet_view_column_set_title (column, name);
- free (name);
-
- cells = pspp_sheet_view_column_get_cell_renderers (column);
- g_return_if_fail (cells);
- cell = cells->data;
- g_list_free (cells);
-
- if (var_has_value_labels (var) != GTK_IS_CELL_RENDERER_COMBO (cell))
- {
- /* Stop editing before we delete and replace the cell renderers.
- Otherwise if this column is currently being edited, an eventual call
- to pspp_sheet_view_stop_editing() will obtain a NULL cell and pass
- that to gtk_cell_renderer_stop_editing(), which causes a critical.
-
- It's possible that this is a bug in PsppSheetView, and it's possible
- that PsppSheetView inherits that from GtkTreeView, but I haven't
- investigated yet. */
- pspp_sheet_view_stop_editing (PSPP_SHEET_VIEW (data_sheet), TRUE);
-
- add_data_column_cell_renderer (data_sheet, column);
- }
-}
-
-static void
-on_variable_inserted (PsppireDict *dict, int var_index,
- PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- gint base_width, incr_width;
- PsppSheetViewColumn *column;
-
- calc_width_conversion (data_sheet, &base_width, &incr_width);
- column = make_data_column (data_sheet, var_index, base_width, incr_width);
- pspp_sheet_view_insert_column (sheet_view, column, var_index + 1);
-}
-
-static void
-on_variable_deleted (PsppireDict *dict,
- const struct variable *var, int case_idx, int width,
- PsppireDataSheet *data_sheet)
-{
- PsppSheetView *sheet_view = PSPP_SHEET_VIEW (data_sheet);
- GList *columns, *iter;
-
- columns = pspp_sheet_view_get_columns (sheet_view);
- for (iter = columns; iter != NULL; iter = iter->next)
- {
- PsppSheetViewColumn *column = iter->data;
- const struct variable *column_var;
-
- column_var = g_object_get_data (G_OBJECT (column), "variable");
- if (column_var == var)
- pspp_sheet_view_remove_column (sheet_view, column);
- }
- g_list_free (columns);
-}
-
-static void
-psppire_data_sheet_unset_data_store (PsppireDataSheet *data_sheet)
-{
- PsppireDataStore *store = data_sheet->data_store;
-
- if (store == NULL)
- return;
-
- data_sheet->data_store = NULL;
-
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_backend_changed), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_case_inserted), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_cases_deleted), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store, G_CALLBACK (on_case_change), data_sheet);
-
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_changed), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_display_width_changed), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_inserted), data_sheet);
- g_signal_handlers_disconnect_by_func (
- store->dict, G_CALLBACK (on_variable_deleted), data_sheet);
-
- g_object_unref (store);
-}
-
-void
-psppire_data_sheet_set_data_store (PsppireDataSheet *data_sheet,
- PsppireDataStore *data_store)
-{
- psppire_data_sheet_unset_data_store (data_sheet);
-
- data_sheet->data_store = data_store;
- if (data_store != NULL)
- {
- g_object_ref (data_store);
- g_signal_connect (data_store, "backend-changed",
- G_CALLBACK (on_backend_changed), data_sheet);
- g_signal_connect (data_store, "case-inserted",
- G_CALLBACK (on_case_inserted), data_sheet);
- g_signal_connect (data_store, "cases-deleted",
- G_CALLBACK (on_cases_deleted), data_sheet);
- g_signal_connect (data_store, "case-changed",
- G_CALLBACK (on_case_change), data_sheet);
-
- /* XXX it's unclean to hook into the dict this way--what if the dict
- changes? As of this writing, though, nothing ever changes the
- data_store's dict. */
- g_signal_connect (data_store->dict, "variable-changed",
- G_CALLBACK (on_variable_changed),
- data_sheet);
- g_signal_connect (data_store->dict, "variable-display-width-changed",
- G_CALLBACK (on_variable_display_width_changed),
- data_sheet);
- g_signal_connect (data_store->dict, "variable-inserted",
- G_CALLBACK (on_variable_inserted), data_sheet);
- g_signal_connect (data_store->dict, "variable-deleted",
- G_CALLBACK (on_variable_deleted), data_sheet);
- }
- refresh_model (data_sheet);
-}
-\f
-/* Clipboard stuff */
-
-/* A casereader and dictionary holding the data currently in the clip */
-static struct casereader *clip_datasheet = NULL;
-static struct dictionary *clip_dict = NULL;
-
-
-static void psppire_data_sheet_update_clipboard (PsppireDataSheet *);
-
-/* Set the clip according to the currently
- selected range in the data sheet */
-static void
-psppire_data_sheet_set_clip (PsppireDataSheet *data_sheet)
-{
- struct casewriter *writer ;
- PsppireDataStore *ds = psppire_data_sheet_get_data_store (data_sheet);
- struct case_map *map = NULL;
- struct range_set *rows, *cols;
- const struct range_set_node *node;
-
- if (!psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols))
- return;
-
-
- /* Destroy any existing clip */
- if ( clip_datasheet )
- {
- casereader_destroy (clip_datasheet);
- clip_datasheet = NULL;
- }
-
- if ( clip_dict )
- {
- dict_destroy (clip_dict);
- clip_dict = NULL;
- }
-
- /* Construct clip dictionary. */
- clip_dict = dict_create (dict_get_encoding (ds->dict->dict));
- RANGE_SET_FOR_EACH (node, cols)
- {
- int dict_index;
-
- for (dict_index = node->start; dict_index < node->end; dict_index++)
- {
- struct variable *var = dict_get_var (ds->dict->dict, dict_index);
- dict_clone_var_assert (clip_dict, var);
- }
- }
-
- /* Construct clip data. */
- map = case_map_by_name (ds->dict->dict, clip_dict);
- writer = autopaging_writer_create (dict_get_proto (clip_dict));
- RANGE_SET_FOR_EACH (node, rows)
- {
- unsigned long int row;
-
- for (row = node->start; row < node->end; row++)
- {
- struct ccase *old = psppire_data_store_get_case (ds, row);
- if (old != NULL)
- casewriter_write (writer, case_map_execute (map, old));
- else
- casewriter_force_error (writer);
- }
- }
- case_map_destroy (map);
-
- range_set_destroy (rows);
- range_set_destroy (cols);
-
- clip_datasheet = casewriter_make_reader (writer);
-
- psppire_data_sheet_update_clipboard (data_sheet);
-}
-
-enum {
- SELECT_FMT_NULL,
- SELECT_FMT_TEXT,
- SELECT_FMT_HTML
-};
-
-
-/* Perform data_out for case CC, variable V, appending to STRING */
-static void
-data_out_g_string (GString *string, const struct variable *v,
- const struct ccase *cc)
-{
- const struct fmt_spec *fs = var_get_print_format (v);
- const union value *val = case_data (cc, v);
-
- char *s = data_out (val, var_get_encoding (v), fs);
-
- g_string_append (string, s);
-
- g_free (s);
-}
-
-static GString *
-clip_to_text (void)
-{
- casenumber r;
- GString *string;
-
- const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (clip_datasheet));
- const casenumber case_cnt = casereader_get_case_cnt (clip_datasheet);
- const size_t var_cnt = dict_get_var_cnt (clip_dict);
-
- string = g_string_sized_new (10 * val_cnt * case_cnt);
-
- for (r = 0 ; r < case_cnt ; ++r )
- {
- int c;
- struct ccase *cc;
-
- cc = casereader_peek (clip_datasheet, r);
- if (cc == NULL)
- {
- g_warning ("Clipboard seems to have inexplicably shrunk");
- break;
- }
-
- for (c = 0 ; c < var_cnt ; ++c)
- {
- const struct variable *v = dict_get_var (clip_dict, c);
- data_out_g_string (string, v, cc);
- if ( c < val_cnt - 1 )
- g_string_append (string, "\t");
- }
-
- if ( r < case_cnt)
- g_string_append (string, "\n");
-
- case_unref (cc);
- }
-
- return string;
-}
-
-
-static GString *
-clip_to_html (void)
-{
- casenumber r;
- GString *string;
-
- const size_t val_cnt = caseproto_get_n_widths (casereader_get_proto (clip_datasheet));
- const casenumber case_cnt = casereader_get_case_cnt (clip_datasheet);
- const size_t var_cnt = dict_get_var_cnt (clip_dict);
-
- /* Guestimate the size needed */
- string = g_string_sized_new (80 + 20 * val_cnt * case_cnt);
-
- g_string_append (string,
- "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
-
- g_string_append (string, "<table>\n");
- for (r = 0 ; r < case_cnt ; ++r )
- {
- int c;
- struct ccase *cc = casereader_peek (clip_datasheet, r);
- if (cc == NULL)
- {
- g_warning ("Clipboard seems to have inexplicably shrunk");
- break;
- }
- g_string_append (string, "<tr>\n");
-
- for (c = 0 ; c < var_cnt ; ++c)
- {
- const struct variable *v = dict_get_var (clip_dict, c);
- g_string_append (string, "<td>");
- data_out_g_string (string, v, cc);
- g_string_append (string, "</td>\n");
- }
-
- g_string_append (string, "</tr>\n");
-
- case_unref (cc);
- }
- g_string_append (string, "</table>\n");
-
- return string;
-}
-
-
-
-static void
-psppire_data_sheet_clipboard_get_cb (GtkClipboard *clipboard,
- GtkSelectionData *selection_data,
- guint info,
- gpointer data)
-{
- GString *string = NULL;
-
- switch (info)
- {
- case SELECT_FMT_TEXT:
- string = clip_to_text ();
- break;
- case SELECT_FMT_HTML:
- string = clip_to_html ();
- break;
- default:
- g_assert_not_reached ();
- }
-
- gtk_selection_data_set (selection_data, selection_data->target,
- 8,
- (const guchar *) string->str, string->len);
-
- g_string_free (string, TRUE);
-}
-
-static void
-psppire_data_sheet_clipboard_clear_cb (GtkClipboard *clipboard,
- gpointer data)
-{
- dict_destroy (clip_dict);
- clip_dict = NULL;
-
- casereader_destroy (clip_datasheet);
- clip_datasheet = NULL;
-}
-
-
-static const GtkTargetEntry targets[] = {
- { "UTF8_STRING", 0, SELECT_FMT_TEXT },
- { "STRING", 0, SELECT_FMT_TEXT },
- { "TEXT", 0, SELECT_FMT_TEXT },
- { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
- { "text/plain;charset=utf-8", 0, SELECT_FMT_TEXT },
- { "text/plain", 0, SELECT_FMT_TEXT },
- { "text/html", 0, SELECT_FMT_HTML }
-};
-
-
-
-static void
-psppire_data_sheet_update_clipboard (PsppireDataSheet *sheet)
-{
- GtkClipboard *clipboard =
- gtk_widget_get_clipboard (GTK_WIDGET (sheet),
- GDK_SELECTION_CLIPBOARD);
-
- if (!gtk_clipboard_set_with_owner (clipboard, targets,
- G_N_ELEMENTS (targets),
- psppire_data_sheet_clipboard_get_cb,
- psppire_data_sheet_clipboard_clear_cb,
- G_OBJECT (sheet)))
- psppire_data_sheet_clipboard_clear_cb (clipboard, sheet);
-}
-
-static void
-psppire_data_sheet_update_clip_actions (PsppireDataSheet *data_sheet)
-{
- struct range_set *rows, *cols;
- GtkAction *action;
- gboolean enable;
-
- enable = psppire_data_sheet_get_selected_range (data_sheet, &rows, &cols);
- if (enable)
- {
- range_set_destroy (rows);
- range_set_destroy (cols);
- }
-
- action = get_action_assert (data_sheet->builder, "edit_copy");
- gtk_action_set_sensitive (action, enable);
-
- action = get_action_assert (data_sheet->builder, "edit_cut");
- gtk_action_set_sensitive (action, enable);
-}
-