1 /*
2  *  Copyright (C) 2002 Derek Atkins
3  *
4  *  Authors: Derek Atkins <warlord@MIT.EDU>
5  *
6  * Copyright (c) 2006 David Hampton <hampton@employees.org>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this program; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 
31 #include "gnc-amount-edit.h"
32 #include "qof.h"
33 #include "gnc-gui-query.h"
34 
35 #include "search-numeric.h"
36 #include "search-core-utils.h"
37 
38 #define d(x)
39 
40 static void pass_parent (GNCSearchCoreType *fe, gpointer parent);
41 static void editable_enters (GNCSearchCoreType *fe);
42 static void grab_focus (GNCSearchCoreType *fe);
43 static GNCSearchCoreType *gncs_clone(GNCSearchCoreType *fe);
44 static gboolean gncs_validate (GNCSearchCoreType *fe);
45 static GtkWidget *gncs_get_widget(GNCSearchCoreType *fe);
46 static QofQueryPredData* gncs_get_predicate (GNCSearchCoreType *fe);
47 
48 static void gnc_search_numeric_class_init	(GNCSearchNumericClass *klass);
49 static void gnc_search_numeric_init	(GNCSearchNumeric *gspaper);
50 static void gnc_search_numeric_finalize	(GObject *obj);
51 
52 typedef struct _GNCSearchNumericPrivate GNCSearchNumericPrivate;
53 
54 struct _GNCSearchNumericPrivate
55 {
56     gboolean	is_debcred;
57     GtkWidget * 	entry;
58     GNCAmountEdit *gae;
59     GtkWindow *parent;
60 };
61 
G_DEFINE_TYPE_WITH_PRIVATE(GNCSearchNumeric,gnc_search_numeric,GNC_TYPE_SEARCH_CORE_TYPE)62 G_DEFINE_TYPE_WITH_PRIVATE(GNCSearchNumeric, gnc_search_numeric, GNC_TYPE_SEARCH_CORE_TYPE)
63 
64 #define _PRIVATE(o) \
65    ((GNCSearchNumericPrivate*)g_type_instance_get_private((GTypeInstance*)o, GNC_TYPE_SEARCH_NUMERIC))
66 
67 static GNCSearchCoreTypeClass *parent_class;
68 
69 static void
70 gnc_search_numeric_class_init (GNCSearchNumericClass *klass)
71 {
72     GObjectClass *object_class;
73     GNCSearchCoreTypeClass *gnc_search_core_type = (GNCSearchCoreTypeClass *)klass;
74 
75     object_class = G_OBJECT_CLASS (klass);
76     parent_class = g_type_class_peek_parent (klass);
77 
78     object_class->finalize = gnc_search_numeric_finalize;
79 
80     /* override methods */
81     gnc_search_core_type->pass_parent = pass_parent;
82     gnc_search_core_type->editable_enters = editable_enters;
83     gnc_search_core_type->grab_focus = grab_focus;
84     gnc_search_core_type->validate = gncs_validate;
85     gnc_search_core_type->get_widget = gncs_get_widget;
86     gnc_search_core_type->get_predicate = gncs_get_predicate;
87     gnc_search_core_type->clone = gncs_clone;
88 }
89 
90 static void
gnc_search_numeric_init(GNCSearchNumeric * o)91 gnc_search_numeric_init (GNCSearchNumeric *o)
92 {
93     o->value = gnc_numeric_zero ();
94     o->how = QOF_COMPARE_EQUAL;
95     o->option = QOF_NUMERIC_MATCH_ANY;
96 }
97 
98 static void
gnc_search_numeric_finalize(GObject * obj)99 gnc_search_numeric_finalize (GObject *obj)
100 {
101     GNCSearchNumeric *o = (GNCSearchNumeric *)obj;
102     g_assert (IS_GNCSEARCH_NUMERIC (o));
103 
104     G_OBJECT_CLASS (parent_class)->finalize(obj);
105 }
106 
107 /**
108  * gnc_search_numeric_new:
109  *
110  * Create a new GNCSearchNumeric object.
111  *
112  * Return value: A new #GNCSearchNumeric object.
113  **/
114 GNCSearchNumeric *
gnc_search_numeric_new(void)115 gnc_search_numeric_new (void)
116 {
117     GNCSearchNumeric *o = g_object_new(GNC_TYPE_SEARCH_NUMERIC, NULL);
118     return o;
119 }
120 
121 /**
122  * gnc_search_numeric_debcred_new:
123  *
124  * Create a new GNCSearchNumeric object, configured for DebCred.
125  *
126  * Return value: A new #GNCSearchNumeric object.
127  **/
128 GNCSearchNumeric *
gnc_search_numeric_debcred_new(void)129 gnc_search_numeric_debcred_new (void)
130 {
131     GNCSearchNumeric *o;
132     GNCSearchNumericPrivate *priv;
133 
134     o = g_object_new(GNC_TYPE_SEARCH_NUMERIC, NULL);
135     priv = _PRIVATE(o);
136     priv->is_debcred = TRUE;
137     return o;
138 }
139 
140 void
gnc_search_numeric_set_value(GNCSearchNumeric * fi,gnc_numeric value)141 gnc_search_numeric_set_value (GNCSearchNumeric *fi, gnc_numeric value)
142 {
143     g_return_if_fail (fi);
144     g_return_if_fail (IS_GNCSEARCH_NUMERIC (fi));
145 
146     fi->value = value;
147 }
148 
149 void
gnc_search_numeric_set_how(GNCSearchNumeric * fi,QofQueryCompare how)150 gnc_search_numeric_set_how (GNCSearchNumeric *fi, QofQueryCompare how)
151 {
152     g_return_if_fail (fi);
153     g_return_if_fail (IS_GNCSEARCH_NUMERIC (fi));
154     fi->how = how;
155 }
156 
157 void
gnc_search_numeric_set_option(GNCSearchNumeric * fi,QofNumericMatch option)158 gnc_search_numeric_set_option (GNCSearchNumeric *fi, QofNumericMatch option)
159 {
160     g_return_if_fail (fi);
161     g_return_if_fail (IS_GNCSEARCH_NUMERIC (fi));
162     fi->option = option;
163 }
164 
165 static void
pass_parent(GNCSearchCoreType * fe,gpointer parent)166 pass_parent (GNCSearchCoreType *fe, gpointer parent)
167 {
168     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
169     GNCSearchNumericPrivate *priv;
170 
171     g_return_if_fail (fi);
172     g_return_if_fail (IS_GNCSEARCH_NUMERIC (fi));
173 
174     priv = _PRIVATE(fi);
175     priv->parent = GTK_WINDOW(parent);
176 }
177 
178 static gboolean
gncs_validate(GNCSearchCoreType * fe)179 gncs_validate (GNCSearchCoreType *fe)
180 {
181     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
182     GNCSearchNumericPrivate *priv;
183     gboolean valid = TRUE;
184     GError *error = NULL;
185 
186     g_return_val_if_fail (fi, FALSE);
187     g_return_val_if_fail (IS_GNCSEARCH_NUMERIC (fi), FALSE);
188 
189     priv = _PRIVATE(fi);
190 
191     if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT(priv->gae), &error))
192     {
193         gnc_error_dialog (GTK_WINDOW(priv->parent), "%s", error->message);
194         valid = FALSE;
195         g_error_free (error);
196     }
197     return valid;
198 }
199 
200 static void
entry_changed(GNCAmountEdit * entry,GNCSearchNumeric * fe)201 entry_changed (GNCAmountEdit *entry, GNCSearchNumeric *fe)
202 {
203     fe->value = gnc_amount_edit_get_amount (entry);
204 }
205 
206 static GtkWidget *
make_how_menu(GNCSearchCoreType * fe)207 make_how_menu (GNCSearchCoreType *fe)
208 {
209     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
210     GNCSearchNumericPrivate *priv;
211     GtkComboBox *combo;
212 
213     priv = _PRIVATE(fi);
214 
215     combo = GTK_COMBO_BOX(gnc_combo_box_new_search());
216     gnc_combo_box_search_add(combo, (priv->is_debcred ?
217                                      _("less than") : _("is less than")),
218                              QOF_COMPARE_LT);
219     gnc_combo_box_search_add(combo, (priv->is_debcred ?
220                                      _("less than or equal to") :
221                                      _("is less than or equal to")),
222                              QOF_COMPARE_LTE);
223     gnc_combo_box_search_add(combo, (priv->is_debcred ?
224                                      _("equal to") : _("equals")),
225                              QOF_COMPARE_EQUAL);
226     gnc_combo_box_search_add(combo, (priv->is_debcred ?
227                                      _("not equal to") : _("does not equal")),
228                              QOF_COMPARE_NEQ);
229     gnc_combo_box_search_add(combo, (priv->is_debcred ?
230                                      _("greater than") : _("is greater than")),
231                              QOF_COMPARE_GT);
232     gnc_combo_box_search_add(combo, (priv->is_debcred ?
233                                      _("greater than or equal to") :
234                                      _("is greater than or equal to")),
235                              QOF_COMPARE_GTE);
236 
237     gnc_combo_box_search_changed(combo, &fi->how);
238     gnc_combo_box_search_set_active(combo, fi->how ? fi->how : QOF_COMPARE_LT);
239 
240     return GTK_WIDGET(combo);
241 }
242 
243 static GtkWidget *
make_option_menu(GNCSearchCoreType * fe)244 make_option_menu (GNCSearchCoreType *fe)
245 {
246     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
247     GtkComboBox *combo;
248 
249     combo = GTK_COMBO_BOX(gnc_combo_box_new_search());
250     gnc_combo_box_search_add(combo, _("has credits or debits"), QOF_NUMERIC_MATCH_ANY);
251     gnc_combo_box_search_add(combo, _("has debits"), QOF_NUMERIC_MATCH_DEBIT);
252     gnc_combo_box_search_add(combo, _("has credits"), QOF_NUMERIC_MATCH_CREDIT);
253     gnc_combo_box_search_changed(combo, &fi->option);
254     gnc_combo_box_search_set_active(combo, fi->option ? fi->option : QOF_NUMERIC_MATCH_ANY);
255 
256     return GTK_WIDGET(combo);
257 }
258 
259 static void
grab_focus(GNCSearchCoreType * fe)260 grab_focus (GNCSearchCoreType *fe)
261 {
262     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
263     GNCSearchNumericPrivate *priv;
264 
265     g_return_if_fail (fi);
266     g_return_if_fail (IS_GNCSEARCH_NUMERIC (fi));
267 
268     priv = _PRIVATE(fi);
269     if (priv->entry)
270         gtk_widget_grab_focus (priv->entry);
271 }
272 
273 static void
editable_enters(GNCSearchCoreType * fe)274 editable_enters (GNCSearchCoreType *fe)
275 {
276     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
277     GNCSearchNumericPrivate *priv;
278 
279     g_return_if_fail (fi);
280     g_return_if_fail (IS_GNCSEARCH_NUMERIC (fi));
281 
282     priv = _PRIVATE(fi);
283     if (priv->entry)
284         gtk_entry_set_activates_default(GTK_ENTRY (priv->entry), TRUE);
285 }
286 
287 static GtkWidget *
gncs_get_widget(GNCSearchCoreType * fe)288 gncs_get_widget (GNCSearchCoreType *fe)
289 {
290     GtkWidget *entry, *menu, *box;
291     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
292     GNCSearchNumericPrivate *priv;
293 
294     g_return_val_if_fail (fi, NULL);
295     g_return_val_if_fail (IS_GNCSEARCH_NUMERIC (fi), NULL);
296 
297     priv = _PRIVATE(fi);
298     box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
299     gtk_box_set_homogeneous (GTK_BOX (box), FALSE);
300 
301     /* Build and connect the option menu(s) */
302     if (priv->is_debcred)
303     {
304         menu = make_option_menu (fe);
305         gtk_box_pack_start (GTK_BOX (box), menu, FALSE, FALSE, 3);
306     }
307 
308     menu = make_how_menu (fe);
309     gtk_box_pack_start (GTK_BOX (box), menu, FALSE, FALSE, 3);
310 
311     /* Build and connect the entry window */
312     entry = gnc_amount_edit_new ();
313     gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (entry), fi->value);
314     g_signal_connect (G_OBJECT (entry), "amount_changed", G_CALLBACK (entry_changed), fe);
315     gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 3);
316     priv->gae = GNC_AMOUNT_EDIT (entry);
317     priv->entry = gnc_amount_edit_gtk_entry (GNC_AMOUNT_EDIT (entry));
318 
319     /* And return the box */
320     return box;
321 }
322 
gncs_get_predicate(GNCSearchCoreType * fe)323 static QofQueryPredData* gncs_get_predicate (GNCSearchCoreType *fe)
324 {
325     GNCSearchNumeric *fi = (GNCSearchNumeric *)fe;
326     GNCSearchNumericPrivate *priv;
327 
328     g_return_val_if_fail (fi, NULL);
329     g_return_val_if_fail (IS_GNCSEARCH_NUMERIC (fi), NULL);
330 
331     /* force the computation of the entry, because we may not get the signal */
332     priv = _PRIVATE(fi);
333     entry_changed (priv->gae, fi);
334 
335     return qof_query_numeric_predicate (fi->how, fi->option, fi->value);
336 }
337 
gncs_clone(GNCSearchCoreType * fe)338 static GNCSearchCoreType *gncs_clone(GNCSearchCoreType *fe)
339 {
340     GNCSearchNumeric *se, *fse = (GNCSearchNumeric *)fe;
341     GNCSearchNumericPrivate *se_priv, *fse_priv;
342 
343     g_return_val_if_fail (fse, NULL);
344     g_return_val_if_fail (IS_GNCSEARCH_NUMERIC (fse), NULL);
345     fse_priv = _PRIVATE(fse);
346 
347     se = gnc_search_numeric_new ();
348     gnc_search_numeric_set_value (se, fse->value);
349     gnc_search_numeric_set_how (se, fse->how);
350     se_priv = _PRIVATE(se);
351     gnc_search_numeric_set_option (se, fse->option);
352     se_priv->is_debcred = fse_priv->is_debcred;
353 
354     return (GNCSearchCoreType *)se;
355 }
356