1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2012 Free Software Foundation, Inc.
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 This widget is a GtkBox which looks roughly like:
21 +-----------------------------+
22 |+------------+ +----------+ |
32 |+------------+ +----------+ |
33 +-----------------------------+
40 #include "psppire-acr.h"
44 #define _(msgid) gettext (msgid)
45 #define N_(msgid) msgid
47 G_DEFINE_TYPE (PsppireAcr, psppire_acr, GTK_TYPE_BOX);
50 psppire_acr_dispose (GObject *obj)
52 PsppireAcr *acr = PSPPIRE_ACR (obj);
53 psppire_acr_set_model (acr, NULL);
55 G_OBJECT_CLASS (psppire_acr_parent_class)->dispose (obj);
59 psppire_acr_class_init (PsppireAcrClass *class)
61 G_OBJECT_CLASS (class)->dispose = psppire_acr_dispose;
64 static gboolean row_is_selected (const PsppireAcr *acr);
68 value_from_entry (gint col, GValue *val, gpointer data)
70 GtkEntry *entry = data;
71 const gchar *text = gtk_entry_get_text (entry);
72 gdouble x = g_strtod (text, 0);
74 g_value_init (val, G_TYPE_DOUBLE);
75 g_value_set_double (val, x);
81 /* Returns true, if there's text in the entry */
83 entry_not_empty (gpointer data)
85 GtkEntry *entry = data;
87 const char *text = gtk_entry_get_text (entry);
89 return !g_str_equal (text, "");
94 clear_entry (gpointer data)
96 GtkEntry *entry = data;
97 gtk_entry_set_text (entry, "");
102 on_entry_change (GtkEntry *entry, PsppireAcr *acr)
104 gtk_widget_set_sensitive (acr->add_button, acr->enabled (entry));
106 gtk_widget_set_sensitive (acr->change_button, acr->enabled (entry)
107 && row_is_selected (acr));
111 psppire_acr_set_entry (PsppireAcr *acr, GtkEntry *entry)
113 acr->get_value = value_from_entry;
114 acr->get_value_data = entry;
115 acr->enabled = entry_not_empty;
116 acr->enabled_data = entry;
117 acr->update = clear_entry;
118 acr->update_data = entry;
120 g_signal_connect (entry, "changed", G_CALLBACK (on_entry_change), acr);
124 /* Callback for when the Add button is clicked.
125 It appends an item to the list. */
127 on_add_button_clicked (PsppireAcr *acr)
131 gtk_list_store_append (acr->list_store, &iter);
134 i < gtk_tree_model_get_n_columns (GTK_TREE_MODEL (acr->list_store));
138 if ( ! acr->get_value (i, &value, acr->get_value_data) )
141 gtk_list_store_set_value (acr->list_store, &iter,
143 g_value_unset (&value);
146 if (acr->update) acr->update (acr->update_data);
150 /* Callback for when the Changed button is clicked.
151 It replaces the currently selected entry. */
153 on_change_button_clicked (PsppireAcr *acr)
156 GtkTreeModel *model = GTK_TREE_MODEL (acr->list_store);
159 gtk_tree_selection_get_selected_rows (acr->selection,
162 GtkTreePath *path = l->data;
166 gtk_tree_model_get_iter (model, &iter, path);
169 i < gtk_tree_model_get_n_columns (GTK_TREE_MODEL (acr->list_store));
173 if ( ! acr->get_value (i, &value, acr->get_value_data) )
176 gtk_list_store_set_value (acr->list_store, &iter,
178 g_value_unset (&value);
181 g_list_foreach (l, (GFunc) gtk_tree_path_free, NULL);
184 if ( acr->update) acr->update (acr->update_data);
188 /* Callback for when the remove button is clicked.
189 It deletes the currently selected entry. */
191 on_remove_button_clicked (PsppireAcr *acr)
193 GtkTreeModel *model = GTK_TREE_MODEL (acr->list_store);
196 gtk_tree_selection_get_selected_rows (acr->selection,
199 GtkTreePath *path = l->data;
203 gtk_tree_model_get_iter (model, &iter, path);
205 gtk_list_store_remove (acr->list_store, &iter);
207 g_list_foreach (l, (GFunc) gtk_tree_path_free, NULL);
211 /* Returns true if there is a row currently selected.
214 row_is_selected (const PsppireAcr *acr)
217 GtkTreeModel *model = GTK_TREE_MODEL (acr->list_store);
218 GList *l = gtk_tree_selection_get_selected_rows (acr->selection,
221 result = (l != NULL);
223 g_list_foreach (l, (GFunc) gtk_tree_path_free, NULL);
230 /* Callback which occurs when an item in the treeview
233 on_select (GtkTreeSelection *selection, gpointer data)
235 PsppireAcr *acr = data;
237 gtk_widget_set_sensitive (acr->remove_button, row_is_selected (acr));
239 gtk_widget_set_sensitive (acr->change_button,
240 row_is_selected (acr)
246 psppire_acr_set_enabled (PsppireAcr *acr, gboolean status)
249 gtk_widget_set_sensitive (acr->add_button, status);
251 gtk_widget_set_sensitive (acr->change_button, status
252 && row_is_selected (acr));
256 psppire_acr_init (PsppireAcr *acr)
258 GtkWidget *bb = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
260 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
262 gtk_orientable_set_orientation (GTK_ORIENTABLE (acr), GTK_ORIENTATION_HORIZONTAL);
264 acr->tv = GTK_TREE_VIEW (gtk_tree_view_new ());
266 acr->add_button = gtk_button_new_with_label (_("Add"));
267 acr->change_button = gtk_button_new_with_label (_("Edit"));
268 acr->remove_button = gtk_button_new_with_label (_("Remove"));
270 acr->get_value = NULL;
271 acr->get_value_data = NULL;
275 gtk_widget_set_sensitive (acr->change_button, FALSE);
276 gtk_widget_set_sensitive (acr->remove_button, FALSE);
277 gtk_widget_set_sensitive (acr->add_button, FALSE);
279 psppire_box_pack_start_defaults (GTK_BOX (bb), acr->add_button);
280 psppire_box_pack_start_defaults (GTK_BOX (bb), acr->change_button);
281 psppire_box_pack_start_defaults (GTK_BOX (bb), acr->remove_button);
283 gtk_box_pack_start (GTK_BOX (acr), bb, FALSE, TRUE, 5);
286 "hscrollbar-policy", GTK_POLICY_NEVER,
287 "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
288 "shadow-type", GTK_SHADOW_ETCHED_IN,
291 gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (acr->tv));
293 gtk_box_pack_start (GTK_BOX (acr), sw, TRUE, TRUE, 5);
296 g_signal_connect_swapped (acr->add_button, "clicked",
297 G_CALLBACK (on_add_button_clicked), acr);
298 g_signal_connect_swapped (acr->change_button, "clicked",
299 G_CALLBACK (on_change_button_clicked), acr);
300 g_signal_connect_swapped (acr->remove_button, "clicked",
301 G_CALLBACK (on_remove_button_clicked), acr);
303 gtk_widget_show_all (bb);
306 g_object_set (acr->tv, "headers-visible", FALSE, NULL);
308 acr->list_store = NULL;
310 psppire_acr_set_model (acr, acr->list_store);
312 acr->selection = gtk_tree_view_get_selection (acr->tv);
314 g_signal_connect (acr->selection, "changed", G_CALLBACK (on_select), acr);
316 gtk_widget_set_sensitive (GTK_WIDGET (acr), FALSE);
318 gtk_widget_show_all (sw);
321 GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
322 GtkTreeViewColumn *column =
323 gtk_tree_view_column_new_with_attributes ("value",
328 gtk_tree_view_append_column (acr->tv, column);
335 psppire_acr_new (void)
337 return GTK_WIDGET (g_object_new (psppire_acr_get_type (), NULL));
342 /* Set the widget's treemodel to LISTSTORE. LISTSTORE ownership is not
345 psppire_acr_set_model (PsppireAcr *acr, GtkListStore *liststore)
348 g_object_unref (acr->list_store);
350 g_object_ref (liststore);
352 acr->list_store = liststore;
354 gtk_tree_view_set_model (GTK_TREE_VIEW (acr->tv),
355 GTK_TREE_MODEL (liststore));
357 gtk_widget_set_sensitive (GTK_WIDGET (acr), liststore != NULL);
362 psppire_acr_set_enable_func (PsppireAcr *acr, EnabledFunc func, gpointer p)
365 acr->enabled_data = p;
369 psppire_acr_set_get_value_func (PsppireAcr *acr,
370 GetValueFunc getvalue, gpointer data)
372 acr->get_value_data = data;
373 acr->get_value = getvalue;