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 JmdRange *range = JMD_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);
106 data_store_value_to_string (JmdSheet *data_sheet, PsppireDataStore *store, gint col, gint row, const GValue *v)
108 return psppire_data_store_value_to_string (store, col, row, v);
111 gboolean myreversefunc (GtkTreeModel *model, gint col, gint row, const gchar *in,
118 show_cases_row_popup (PsppireDataSheet *sheet, int row,
119 uint button, uint state, gpointer p)
121 GListModel *vmodel = NULL;
122 g_object_get (sheet, "vmodel", &vmodel, NULL);
126 guint n_items = g_list_model_get_n_items (vmodel);
134 g_object_set_data (G_OBJECT (sheet->data_sheet_cases_row_popup), "item",
135 GINT_TO_POINTER (row));
137 gtk_menu_popup_at_pointer (GTK_MENU (sheet->data_sheet_cases_row_popup), NULL);
142 insert_new_case (PsppireDataSheet *sheet)
144 PsppireDataStore *data_store = NULL;
145 g_object_get (sheet, "data-model", &data_store, NULL);
147 gint posn = GPOINTER_TO_INT (g_object_get_data
148 (G_OBJECT (sheet->data_sheet_cases_row_popup), "item"));
150 psppire_data_store_insert_new_case (data_store, posn);
152 gtk_widget_queue_draw (GTK_WIDGET (sheet));
156 delete_cases (PsppireDataSheet *sheet)
158 JmdRange *range = JMD_SHEET(sheet)->selection;
160 PsppireDataStore *data_store = NULL;
161 g_object_get (sheet, "data-model", &data_store, NULL);
163 psppire_data_store_delete_cases (data_store, range->start_y,
164 range->end_y - range->start_y + 1);
166 gtk_widget_queue_draw (GTK_WIDGET (sheet));
170 create_data_row_header_popup_menu (PsppireDataSheet *sheet)
172 GtkWidget *menu = gtk_menu_new ();
175 gtk_menu_item_new_with_mnemonic (_("_Insert Case"));
177 g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_case), sheet);
178 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
180 item = gtk_separator_menu_item_new ();
181 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
183 sheet->data_clear_cases_menu_item = gtk_menu_item_new_with_mnemonic (_("Cl_ear Cases"));
184 gtk_widget_set_sensitive (sheet->data_clear_cases_menu_item, FALSE);
185 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_clear_cases_menu_item);
186 g_signal_connect_swapped (sheet->data_clear_cases_menu_item, "activate",
187 G_CALLBACK (delete_cases), sheet);
189 gtk_widget_show_all (menu);
195 show_cases_column_popup (PsppireDataSheet *sheet, int column, uint button, uint state,
198 GListModel *hmodel = NULL;
199 g_object_get (sheet, "hmodel", &hmodel, NULL);
203 guint n_items = g_list_model_get_n_items (hmodel);
205 if (column >= n_items)
211 g_object_set_data (G_OBJECT (sheet->data_sheet_cases_column_popup), "item",
212 GINT_TO_POINTER (column));
214 gtk_menu_popup_at_pointer (GTK_MENU (sheet->data_sheet_cases_column_popup), NULL);
218 insert_new_variable (PsppireDataSheet *sheet)
220 PsppireDataStore *data_store = NULL;
221 g_object_get (sheet, "data-model", &data_store, NULL);
223 gint posn = GPOINTER_TO_INT (g_object_get_data
224 (G_OBJECT (sheet->data_sheet_cases_column_popup),
227 const struct variable *v = psppire_dict_insert_variable (data_store->dict,
230 psppire_data_store_insert_value (data_store, var_get_width(v),
231 var_get_case_index (v));
233 gtk_widget_queue_draw (GTK_WIDGET (sheet));
237 set_menu_items_sensitivity (PsppireDataSheet *sheet, gpointer selection, gpointer p)
239 JmdRange *range = selection;
241 PsppireDataStore *data_store = NULL;
242 g_object_get (sheet, "data-model", &data_store, NULL);
245 gint width = gtk_tree_model_get_n_columns (GTK_TREE_MODEL (data_store));
246 gint length = psppire_data_store_get_case_count (data_store);
249 gboolean whole_row_selected = (range->start_x == 0 && range->end_x == width - 1);
250 gtk_widget_set_sensitive (sheet->data_clear_cases_menu_item, whole_row_selected);
252 gboolean whole_column_selected =
253 (range->start_y == 0 && range->end_y == length - 1);
254 gtk_widget_set_sensitive (sheet->data_clear_variables_menu_item,
255 whole_column_selected);
256 gtk_widget_set_sensitive (sheet->data_sort_ascending_menu_item,
257 whole_column_selected);
258 gtk_widget_set_sensitive (sheet->data_sort_descending_menu_item,
259 whole_column_selected);
263 delete_variables (PsppireDataSheet *sheet)
265 JmdRange *range = JMD_SHEET(sheet)->selection;
267 PsppireDataStore *data_store = NULL;
268 g_object_get (sheet, "data-model", &data_store, NULL);
270 psppire_dict_delete_variables (data_store->dict, range->start_x,
271 (range->end_x - range->start_x + 1));
273 gtk_widget_queue_draw (GTK_WIDGET (sheet));
279 create_data_column_header_popup_menu (PsppireDataSheet *sheet)
281 GtkWidget *menu = gtk_menu_new ();
284 gtk_menu_item_new_with_mnemonic (_("_Insert Variable"));
285 g_signal_connect_swapped (item, "activate", G_CALLBACK (insert_new_variable),
287 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
289 item = gtk_separator_menu_item_new ();
290 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
292 sheet->data_clear_variables_menu_item =
293 gtk_menu_item_new_with_mnemonic (_("Cl_ear Variables"));
294 g_signal_connect_swapped (sheet->data_clear_variables_menu_item, "activate",
295 G_CALLBACK (delete_variables),
297 gtk_widget_set_sensitive (sheet->data_clear_variables_menu_item, FALSE);
298 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_clear_variables_menu_item);
300 item = gtk_separator_menu_item_new ();
301 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
304 sheet->data_sort_ascending_menu_item =
305 gtk_menu_item_new_with_mnemonic (_("Sort _Ascending"));
306 g_signal_connect_swapped (sheet->data_sort_ascending_menu_item, "activate",
307 G_CALLBACK (sort_ascending), sheet);
308 gtk_widget_set_sensitive (sheet->data_sort_ascending_menu_item, FALSE);
309 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_sort_ascending_menu_item);
311 sheet->data_sort_descending_menu_item =
312 gtk_menu_item_new_with_mnemonic (_("Sort _Descending"));
313 g_signal_connect_swapped (sheet->data_sort_descending_menu_item, "activate",
314 G_CALLBACK (sort_descending), sheet);
315 gtk_widget_set_sensitive (sheet->data_sort_descending_menu_item, FALSE);
316 gtk_menu_shell_append (GTK_MENU_SHELL (menu), sheet->data_sort_descending_menu_item);
318 gtk_widget_show_all (menu);
325 G_DEFINE_TYPE (PsppireDataSheet, psppire_data_sheet, JMD_TYPE_SHEET)
327 static GObjectClass * parent_class = NULL;
328 static gboolean dispose_has_run = FALSE;
331 psppire_data_sheet_dispose (GObject *obj)
333 // PsppireDataSheet *sheet = PSPPIRE_DATA_SHEET (obj);
338 dispose_has_run = TRUE;
340 /* Chain up to the parent class */
341 G_OBJECT_CLASS (parent_class)->dispose (obj);
345 psppire_data_sheet_class_init (PsppireDataSheetClass *class)
347 GObjectClass *object_class = G_OBJECT_CLASS (class);
348 object_class->dispose = psppire_data_sheet_dispose;
350 parent_class = g_type_class_peek_parent (class);
354 psppire_data_sheet_new (void)
357 g_object_new (PSPPIRE_TYPE_DATA_SHEET,
358 "forward-conversion", data_store_value_to_string,
359 "reverse-conversion", myreversefunc,
362 return GTK_WIDGET (obj);
366 set_dictionary (PsppireDataSheet *sheet)
368 GtkTreeModel *data_model = NULL;
369 g_object_get (sheet, "data-model", &data_model, NULL);
371 PsppireDataStore *store = PSPPIRE_DATA_STORE (data_model);
372 g_object_set (sheet, "hmodel", store->dict, NULL);
376 move_variable (PsppireDataSheet *sheet, gint from, gint to, gpointer ud)
378 PsppireDataStore *data_store = NULL;
379 g_object_get (sheet, "data-model", &data_store, NULL);
381 if (data_store == NULL)
384 PsppireDict *dict = data_store->dict;
385 struct variable *var = psppire_dict_get_variable (dict, from);
390 /* The index refers to the final position, so if the source
391 is less than the destination, then we must subtract 1, to
392 account for the position vacated by the source */
395 dict_reorder_var (dict->dict, var, new_pos);
399 psppire_data_sheet_init (PsppireDataSheet *sheet)
401 sheet->data_sheet_cases_column_popup =
402 create_data_column_header_popup_menu (sheet);
404 sheet->data_sheet_cases_row_popup =
405 create_data_row_header_popup_menu (sheet);
407 g_signal_connect (sheet, "selection-changed",
408 G_CALLBACK (set_menu_items_sensitivity), sheet);
410 g_signal_connect (sheet, "column-header-pressed",
411 G_CALLBACK (show_cases_column_popup), sheet);
413 g_signal_connect (sheet, "row-header-pressed",
414 G_CALLBACK (show_cases_row_popup), sheet);
416 g_signal_connect (sheet, "value-changed",
417 G_CALLBACK (change_data_value), NULL);
419 g_signal_connect (sheet, "notify::data-model",
420 G_CALLBACK (set_dictionary), NULL);
422 g_signal_connect (sheet, "column-moved", G_CALLBACK (move_variable), NULL);