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