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);
367 psppire_data_sheet_init (PsppireDataSheet *sheet)
369 sheet->data_sheet_cases_column_popup =
370 create_data_column_header_popup_menu (sheet);
372 sheet->data_sheet_cases_row_popup =
373 create_data_row_header_popup_menu (sheet);
375 g_signal_connect (sheet, "selection-changed",
376 G_CALLBACK (set_menu_items_sensitivity), sheet);
378 g_signal_connect (sheet, "column-header-pressed",
379 G_CALLBACK (show_cases_column_popup), sheet);
381 g_signal_connect (sheet, "row-header-pressed",
382 G_CALLBACK (show_cases_row_popup), sheet);
384 g_signal_connect (sheet, "value-changed",
385 G_CALLBACK (change_data_value), NULL);