1 /*
2 * gnc-general-select.c -- General Selection Widget
3 *
4 * Copyright (C) 2001 Free Software Foundation
5 * All rights reserved.
6 *
7 * Derek Atkins <warlord@MIT.EDU>
8 *
9 * Gnucash is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public License
11 * as published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * Gnucash is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, contact:
21 *
22 * Free Software Foundation Voice: +1-617-542-5942
23 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
24 * Boston, MA 02110-1301, USA gnu@gnu.org
25 *
26 */
27 /*
28 @NOTATION@
29 */
30
31 #include <config.h>
32
33 #include <gtk/gtk.h>
34 #include <glib/gi18n.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdio.h>
38
39 #include "gnc-general-select.h"
40 #include "dialog-utils.h"
41
42 /* Signal codes */
43 enum
44 {
45 SELECTION_CHANGED,
46 LAST_SIGNAL
47 };
48
49
50 static void gnc_general_select_init (GNCGeneralSelect *gsl);
51 static void gnc_general_select_class_init (GNCGeneralSelectClass *klass);
52 static void gnc_general_select_dispose (GObject *object);
53 static void gnc_general_select_finalize (GObject *object);
54
55 static GtkBoxClass *parent_class;
56 static guint general_select_signals[LAST_SIGNAL];
57
58
59 /**
60 * gnc_general_select_get_type:
61 *
62 * Returns the GType for the GNCGeneralSelect widget
63 */
64 GType
gnc_general_select_get_type(void)65 gnc_general_select_get_type (void)
66 {
67 static GType general_select_type = 0;
68
69 if (general_select_type == 0)
70 {
71 static const GTypeInfo general_select_info =
72 {
73 sizeof (GNCGeneralSelectClass),
74 NULL,
75 NULL,
76 (GClassInitFunc) gnc_general_select_class_init,
77 NULL,
78 NULL,
79 sizeof (GNCGeneralSelect),
80 0,
81 (GInstanceInitFunc) gnc_general_select_init,
82 NULL,
83 };
84
85 general_select_type = g_type_register_static(GTK_TYPE_BOX,
86 "GNCGeneralSelect",
87 &general_select_info, 0);
88 }
89
90 return general_select_type;
91 }
92
93 static void
gnc_general_select_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)94 gnc_general_select_forall (GtkContainer *container, gboolean include_internals,
95 GtkCallback callback, gpointer callback_data)
96 {
97 g_return_if_fail (container != NULL);
98 g_return_if_fail (GNC_IS_GENERAL_SELECT (container));
99 g_return_if_fail (callback != NULL);
100
101 /* Let GtkBox handle things only if the internal widgets need
102 * to be poked. */
103 if (!include_internals)
104 return;
105
106 if (!GTK_CONTAINER_CLASS (parent_class)->forall)
107 return;
108
109 GTK_CONTAINER_CLASS (parent_class)->forall (container,
110 include_internals,
111 callback,
112 callback_data);
113 }
114
115 static void
gnc_general_select_class_init(GNCGeneralSelectClass * klass)116 gnc_general_select_class_init (GNCGeneralSelectClass *klass)
117 {
118 GObjectClass *object_class = (GObjectClass *) klass;
119 GtkContainerClass *container_class = (GtkContainerClass *) klass;
120
121 object_class = (GObjectClass*) klass;
122
123 parent_class = g_type_class_ref(GTK_TYPE_BOX);
124
125 general_select_signals[SELECTION_CHANGED] =
126 g_signal_new("changed",
127 G_TYPE_FROM_CLASS(object_class),
128 G_SIGNAL_RUN_FIRST,
129 G_STRUCT_OFFSET(GNCGeneralSelectClass,
130 changed),
131 NULL, NULL,
132 g_cclosure_marshal_VOID__VOID,
133 G_TYPE_NONE, 0);
134
135 container_class->forall = gnc_general_select_forall;
136
137 object_class->dispose = gnc_general_select_dispose;
138 object_class->finalize = gnc_general_select_finalize;
139
140 klass->changed = NULL;
141 }
142
143 static void
gnc_general_select_init(GNCGeneralSelect * gsl)144 gnc_general_select_init (GNCGeneralSelect *gsl)
145 {
146 gtk_orientable_set_orientation (GTK_ORIENTABLE(gsl), GTK_ORIENTATION_HORIZONTAL);
147
148 // Set the name for this widget so it can be easily manipulated with css
149 gtk_widget_set_name (GTK_WIDGET(gsl), "gnc-id-general-select");
150
151 gsl->disposed = FALSE;
152 gsl->selected_item = NULL;
153 }
154
155 static void
gnc_general_select_finalize(GObject * object)156 gnc_general_select_finalize (GObject *object)
157 {
158 g_return_if_fail (object != NULL);
159 g_return_if_fail (GNC_IS_GENERAL_SELECT (object));
160
161 if (G_OBJECT_CLASS (parent_class)->finalize)
162 G_OBJECT_CLASS (parent_class)->finalize (object);
163 }
164
165 static void
gnc_general_select_dispose(GObject * object)166 gnc_general_select_dispose (GObject *object)
167 {
168 GNCGeneralSelect *gsl;
169
170 g_return_if_fail (object != NULL);
171 g_return_if_fail (GNC_IS_GENERAL_SELECT (object));
172
173 gsl = GNC_GENERAL_SELECT (object);
174
175 if (gsl->disposed)
176 return;
177
178 gsl->disposed = TRUE;
179
180
181 gtk_widget_destroy(GTK_WIDGET(gsl->entry));
182 gsl->entry = NULL;
183
184 gtk_widget_destroy(GTK_WIDGET(gsl->button));
185 gsl->button = NULL;
186
187
188 if (G_OBJECT_CLASS (parent_class)->dispose)
189 G_OBJECT_CLASS (parent_class)->dispose (object);
190 }
191
192 static void
select_cb(GtkButton * button,gpointer user_data)193 select_cb(GtkButton * button, gpointer user_data)
194 {
195 GNCGeneralSelect *gsl = user_data;
196 gpointer new_selection;
197 GtkWidget *toplevel;
198
199 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
200
201 new_selection = (gsl->new_select)(gsl->cb_arg, gsl->selected_item,
202 toplevel);
203
204 /* NULL return means cancel; no change */
205 if (new_selection == NULL)
206 return;
207
208 gnc_general_select_set_selected (gsl, new_selection);
209 }
210
211 static void
create_children(GNCGeneralSelect * gsl,GNCGeneralSelectType type)212 create_children (GNCGeneralSelect *gsl, GNCGeneralSelectType type)
213 {
214 gsl->entry = gtk_entry_new ();
215 gtk_editable_set_editable (GTK_EDITABLE (gsl->entry), FALSE);
216 gtk_box_pack_start (GTK_BOX (gsl), gsl->entry, TRUE, TRUE, 0);
217 gtk_widget_show (gsl->entry);
218
219 if (type == GNC_GENERAL_SELECT_TYPE_SELECT)
220 gsl->button = gtk_button_new_with_label (_("Select..."));
221 else if (type == GNC_GENERAL_SELECT_TYPE_EDIT)
222 gsl->button = gtk_button_new_with_label (_("Edit..."));
223 else if (type == GNC_GENERAL_SELECT_TYPE_VIEW)
224 gsl->button = gtk_button_new_with_label (_("View..."));
225
226 gtk_box_pack_start (GTK_BOX (gsl), gsl->button, FALSE, FALSE, 0);
227 g_signal_connect (G_OBJECT (gsl->button), "clicked",
228 G_CALLBACK (select_cb), gsl);
229 gtk_widget_show (gsl->button);
230 }
231
232 /**
233 * gnc_general_select_new:
234 *
235 * Creates a new GNCGeneralSelect widget which can be used to provide
236 * an easy way to choose selections
237 *
238 * Returns a GNCGeneralSelect widget.
239 */
240 GtkWidget *
gnc_general_select_new(GNCGeneralSelectType type,GNCGeneralSelectGetStringCB get_string,GNCGeneralSelectNewSelectCB new_select,gpointer cb_arg)241 gnc_general_select_new (GNCGeneralSelectType type,
242 GNCGeneralSelectGetStringCB get_string,
243 GNCGeneralSelectNewSelectCB new_select,
244 gpointer cb_arg)
245 {
246 GNCGeneralSelect *gsl;
247 g_return_val_if_fail (get_string != NULL, NULL);
248 g_return_val_if_fail (new_select != NULL, NULL);
249
250 gsl = g_object_new(GNC_TYPE_GENERAL_SELECT, NULL, NULL);
251
252 create_children (gsl, type);
253 gsl->get_string = get_string;
254 gsl->new_select = new_select;
255 gsl->cb_arg = cb_arg;
256
257 return GTK_WIDGET (gsl);
258 }
259
260 /*
261 * gnc_general_select_get_printname:
262 * @gsl: the general selection widget
263 * @selection: the selection to get the printname
264 *
265 * returns the printable name of the selection
266 */
267 const char *
gnc_general_select_get_printname(GNCGeneralSelect * gsl,gpointer selection)268 gnc_general_select_get_printname (GNCGeneralSelect *gsl, gpointer selection)
269 {
270 g_return_val_if_fail (gsl != NULL, NULL);
271 g_return_val_if_fail (selection != NULL, NULL);
272
273 return (gsl->get_string)(selection);
274 }
275
276 /**
277 * gnc_general_select_set_selected:
278 * @gsl: the general selection widget
279 * @selection: the selection to point to
280 *
281 * Sets the selection value of the widget to a particular pointer.
282 *
283 * Returns nothing.
284 */
285 void
gnc_general_select_set_selected(GNCGeneralSelect * gsl,gpointer selection)286 gnc_general_select_set_selected (GNCGeneralSelect *gsl, gpointer selection)
287 {
288 const char *text;
289
290 g_return_if_fail(gsl != NULL);
291 g_return_if_fail(GNC_IS_GENERAL_SELECT(gsl));
292
293 gsl->selected_item = selection;
294
295 if (selection == NULL)
296 text = "";
297 else
298 text = gnc_general_select_get_printname(gsl, selection);
299
300 gtk_entry_set_text(GTK_ENTRY(gsl->entry), text);
301
302 g_signal_emit(gsl, general_select_signals[SELECTION_CHANGED], 0);
303 }
304
305 /**
306 * gnc_general_select_get_commodity:
307 * @gsl: the general selection widget
308 *
309 * Returns the current selection by the widget.
310 */
311 gpointer
gnc_general_select_get_selected(GNCGeneralSelect * gsl)312 gnc_general_select_get_selected (GNCGeneralSelect *gsl)
313 {
314 g_return_val_if_fail(gsl != NULL, NULL);
315 g_return_val_if_fail(GNC_IS_GENERAL_SELECT(gsl), NULL);
316
317 return gsl->selected_item;
318 }
319
320 /** Sets the editable field from a general selection widget as the
321 * target for the specified label's access key.
322 *
323 * @param gde The date editor to set as the target.
324 *
325 *
326 * @param label The label whose access key should set focus to this
327 * widget. */
328 void
gnc_general_select_make_mnemonic_target(GNCGeneralSelect * gsl,GtkWidget * label)329 gnc_general_select_make_mnemonic_target (GNCGeneralSelect *gsl, GtkWidget *label)
330 {
331 g_return_if_fail(gsl);
332 g_return_if_fail(GNC_IS_GENERAL_SELECT(gsl));
333 g_return_if_fail(label);
334
335 gtk_label_set_mnemonic_widget (GTK_LABEL(label), gsl->entry);
336 }
337
338