1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2017 John Darrington
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "psppire-data-sheet.h"
22 #define _(msgid) gettext (msgid)
25 #include "value-variant.h"
27 #include "ui/gui/executor.h"
28 #include "psppire-data-window.h"
31 do_sort (PsppireDataSheet *sheet, GtkSortType order)
33 SswRange *range = SSW_SHEET(sheet)->selection;
35 PsppireDataStore *data_store = NULL;
36 g_object_get (sheet, "data-model", &data_store, NULL);
41 PsppireDataWindow *pdw =
42 psppire_data_window_for_data_store (data_store);
44 GString *syntax = g_string_new ("SORT CASES BY");
45 for (i = range->start_x ; i <= range->end_x; ++i)
47 const struct variable *var = psppire_dict_get_variable (data_store->dict, i);
50 g_string_append_printf (syntax, " %s", var_get_name (var));
56 if (order == GTK_SORT_DESCENDING)
57 g_string_append (syntax, " (DOWN)");
58 g_string_append_c (syntax, '.');
59 execute_const_syntax_string (pdw, syntax->str);
61 g_string_free (syntax, TRUE);
66 sort_ascending (PsppireDataSheet *sheet)
68 do_sort (sheet, GTK_SORT_ASCENDING);
70 gtk_widget_queue_draw (GTK_WIDGET (sheet));
74 sort_descending (PsppireDataSheet *sheet)
76 do_sort (sheet, GTK_SORT_DESCENDING);
78 gtk_widget_queue_draw (GTK_WIDGET (sheet));
84 change_data_value (PsppireDataSheet *sheet, gint col, gint row, GValue *value)
86 PsppireDataStore *store = NULL;
87 g_object_get (sheet, "data-model", &store, NULL);
89 const struct variable *var = psppire_dict_get_variable (store->dict, col);
96 GVariant *vrnt = g_value_get_variant (value);
98 value_variant_get (&v, vrnt);
100 psppire_data_store_set_value (store, row, var, &v);
102 value_destroy_from_variant (&v, vrnt);
105 gboolean myreversefunc (GtkTreeModel *model, gint col, gint row, const gchar *in,
111 show_cases_row_popup (PsppireDataSheet *sheet, int row,
112 uint button, uint state, gpointer p)
114 GListModel *vmodel = NULL;
115 g_object_get (sheet, "vmodel", &vmodel, NULL);
119 guint n_items = g_list_model_get_n_items (vmodel);
127 g_object_set_data (G_OBJECT (sheet->data_sheet_cases_row_popup), "item",
128 GINT_TO_POINTER (row));
130 gtk_menu_popup_at_pointer (GTK_MENU (sheet->data_sheet_cases_row_popup), NULL);
135 insert_new_case (PsppireDataSheet *sheet)
137 PsppireDataStore *data_store = NULL;
138 g_object_get (sheet, "data-model", &data_store, NULL);
140 gint posn = GPOINTER_TO_INT (g_object_get_data
141 (G_OBJECT (sheet->data_sheet_cases_row_popup), "item"));
143 psppire_data_store_insert_new_case (data_store, posn);
145 gtk_widget_queue_draw (GTK_WIDGET (sheet));
149 delete_cases (PsppireDataSheet *sheet)
151 SswRange *range = SSW_SHEET(sheet)->selection;
153 PsppireDataStore *data_store = NULL;
154 g_object_get (sheet, "data-model", &data_store, NULL);
156 psppire_data_store_delete_cases (data_store, range->start_y,
157 range->end_y - range->start_y + 1);
159 gtk_widget_queue_draw (GTK_WIDGET (sheet));
163 create_data_row_header_popup_menu (PsppireDataSheet *sheet)
165 GtkWidget *menu = gtk_menu_new ();
168 gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
170 g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_case), sheet);
171 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
173 item = gtk_separator_menu_item_new ();
174 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
176 sheet->data_clear_cases_menu_item = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
177 gtk_widget_set_sensitive (sheet->data_clear_cases_menu_item, FALSE);
178 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_clear_cases_menu_item);
179 g_signal_connect_swapped (sheet->data_clear_cases_menu_item, "activate",
180 G_CALLBACK (delete_cases), sheet);
182 gtk_widget_show_all (menu);
188 show_cases_column_popup (PsppireDataSheet *sheet, int column, uint button, uint state,
191 GListModel *hmodel = NULL;
192 g_object_get (sheet, "hmodel", &hmodel, NULL);
196 guint n_items = g_list_model_get_n_items (hmodel);
198 if (column >= n_items)
204 g_object_set_data (G_OBJECT (sheet->data_sheet_cases_column_popup), "item",
205 GINT_TO_POINTER (column));
207 gtk_menu_popup_at_pointer (GTK_MENU (sheet->data_sheet_cases_column_popup), NULL);
211 insert_new_variable (PsppireDataSheet *sheet)
213 PsppireDataStore *data_store = NULL;
214 g_object_get (sheet, "data-model", &data_store, NULL);
216 gint posn = GPOINTER_TO_INT (g_object_get_data
217 (G_OBJECT (sheet->data_sheet_cases_column_popup),
220 const struct variable *v = psppire_dict_insert_variable (data_store->dict,
223 psppire_data_store_insert_value (data_store, var_get_width(v),
224 var_get_case_index (v));
226 gtk_widget_queue_draw (GTK_WIDGET (sheet));
230 set_menu_items_sensitivity (PsppireDataSheet *sheet, gpointer selection, gpointer p)
232 SswRange *range = selection;
234 PsppireDataStore *data_store = NULL;
235 g_object_get (sheet, "data-model", &data_store, NULL);
238 gint width = gtk_tree_model_get_n_columns (GTK_TREE_MODEL (data_store));
239 gint length = psppire_data_store_get_case_count (data_store);
242 gboolean whole_row_selected = (range->start_x == 0 && range->end_x == width - 1);
243 gtk_widget_set_sensitive (sheet->data_clear_cases_menu_item, whole_row_selected);
245 gboolean whole_column_selected =
246 (range->start_y == 0 && range->end_y == length - 1);
247 gtk_widget_set_sensitive (sheet->data_clear_variables_menu_item,
248 whole_column_selected);
249 gtk_widget_set_sensitive (sheet->data_sort_ascending_menu_item,
250 whole_column_selected);
251 gtk_widget_set_sensitive (sheet->data_sort_descending_menu_item,
252 whole_column_selected);
256 delete_variables (PsppireDataSheet *sheet)
258 SswRange *range = SSW_SHEET(sheet)->selection;
260 PsppireDataStore *data_store = NULL;
261 g_object_get (sheet, "data-model", &data_store, NULL);
263 psppire_dict_delete_variables (data_store->dict, range->start_x,
264 (range->end_x - range->start_x + 1));
266 gtk_widget_queue_draw (GTK_WIDGET (sheet));
272 create_data_column_header_popup_menu (PsppireDataSheet *sheet)
274 GtkWidget *menu = gtk_menu_new ();
277 gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
278 g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_variable),
280 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
282 item = gtk_separator_menu_item_new ();
283 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
285 sheet->data_clear_variables_menu_item =
286 gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
287 g_signal_connect_swapped (sheet->data_clear_variables_menu_item, "activate",
288 G_CALLBACK (delete_variables),
290 gtk_widget_set_sensitive (sheet->data_clear_variables_menu_item, FALSE);
291 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_clear_variables_menu_item);
293 item = gtk_separator_menu_item_new ();
294 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
297 sheet->data_sort_ascending_menu_item =
298 gtk_menu_item_new_with_mnemonic (_("Sort _Ascending"));
299 g_signal_connect_swapped (sheet->data_sort_ascending_menu_item, "activate",
300 G_CALLBACK (sort_ascending), sheet);
301 gtk_widget_set_sensitive (sheet->data_sort_ascending_menu_item, FALSE);
302 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_sort_ascending_menu_item);
304 sheet->data_sort_descending_menu_item =
305 gtk_menu_item_new_with_mnemonic (_("Sort _Descending"));
306 g_signal_connect_swapped (sheet->data_sort_descending_menu_item, "activate",
307 G_CALLBACK (sort_descending), sheet);
308 gtk_widget_set_sensitive (sheet->data_sort_descending_menu_item, FALSE);
309 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_sort_descending_menu_item);
311 gtk_widget_show_all (menu);
318 G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, SSW_TYPE_SHEET)
320 static GObjectClass * parent_class = NULL;
321 static gboolean dispose_has_run = FALSE;
324 psppire_data_sheet_dispose (GObject *obj)
326 // PsppireDataSheet *sheet = PSPPIRE_DATA_SHEET (obj);
331 dispose_has_run = TRUE;
333 /* Chain up to the parent class */
334 G_OBJECT_CLASS (parent_class)->dispose (obj);
338 psppire_data_sheet_class_init (PsppireDataSheetClass *class)
340 GObjectClass *object_class = G_OBJECT_CLASS (class);
341 object_class->dispose = psppire_data_sheet_dispose;
343 parent_class = g_type_class_peek_parent (class);
347 psppire_data_sheet_new (void)
350 g_object_new (PSPPIRE_TYPE_DATA_SHEET,
351 "forward-conversion", psppire_data_store_value_to_string,
352 "reverse-conversion", myreversefunc,
355 return GTK_WIDGET (obj);
359 set_dictionary (PsppireDataSheet *sheet)
361 GtkTreeModel *data_model = NULL;
362 g_object_get (sheet, "data-model", &data_model, NULL);
364 PsppireDataStore *store = PSPPIRE_DATA_STORE (data_model);
365 g_object_set (sheet, "hmodel", store->dict, NULL);
369 move_variable (PsppireDataSheet *sheet, gint from, gint to, gpointer ud)
371 PsppireDataStore *data_store = NULL;
372 g_object_get (sheet, "data-model", &data_store, NULL);
374 if (data_store == NULL)
377 PsppireDict *dict = data_store->dict;
378 struct variable *var = psppire_dict_get_variable (dict, from);
383 /* The index refers to the final position, so if the source
384 is less than the destination, then we must subtract 1, to
385 account for the position vacated by the source */
388 dict_reorder_var (dict->dict, var, new_pos);
392 psppire_data_sheet_init (PsppireDataSheet *sheet)
394 sheet->data_sheet_cases_column_popup =
395 create_data_column_header_popup_menu (sheet);
397 sheet->data_sheet_cases_row_popup =
398 create_data_row_header_popup_menu (sheet);
400 g_signal_connect (sheet, "selection-changed",
401 G_CALLBACK (set_menu_items_sensitivity), sheet);
403 g_signal_connect (sheet, "column-header-pressed",
404 G_CALLBACK (show_cases_column_popup), sheet);
406 g_signal_connect (sheet, "row-header-pressed",
407 G_CALLBACK (show_cases_row_popup), sheet);
409 g_signal_connect (sheet, "value-changed",
410 G_CALLBACK (change_data_value), NULL);
412 g_signal_connect (sheet, "notify::data-model",
413 G_CALLBACK (set_dictionary), NULL);
415 g_signal_connect (sheet, "column-moved", G_CALLBACK (move_variable), NULL);