1 /********************************************************************\
2 * pricecell.c -- price input/display cell *
3 * *
4 * This program is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU General Public License as *
6 * published by the Free Software Foundation; either version 2 of *
7 * the License, or (at your option) any later version. *
8 * *
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. *
13 * *
14 * You should have received a copy of the GNU General Public License*
15 * along with this program; if not, contact: *
16 * *
17 * Free Software Foundation Voice: +1-617-542-5942 *
18 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19 * Boston, MA 02110-1301, USA gnu@gnu.org *
20 * *
21 \********************************************************************/
22
23 /*
24 * FILE:
25 * pricecell.c
26 *
27 * FUNCTION:
28 * Implements the price cell
29 *
30 * HISTORY:
31 * Copyright (c) 1998, 1999, 2000 Linas Vepstas
32 * Copyright (c) 2000 Dave Peticolas
33 */
34
35 #include <config.h>
36
37 #include <glib.h>
38 #include <glib/gi18n.h>
39 #include <string.h>
40
41 #include "gnc-exp-parser.h"
42 #include "gnc-engine.h"
43 #include "gnc-ui-util.h"
44 #include "gnc-ui.h"
45
46 #include "basiccell.h"
47 #include "pricecell.h"
48 #include <qoflog.h>
49
50 static const QofLogModule log_module = G_LOG_DOMAIN;
51
52 static void gnc_price_cell_init (PriceCell *cell);
53 static void gnc_price_cell_set_value_internal (BasicCell *bcell,
54 const char *value);
55 static const char * gnc_price_cell_print_value (PriceCell *cell);
56
57
58 static gboolean
gnc_price_cell_enter(BasicCell * _cell,int * cursor_position,int * start_selection,int * end_selection)59 gnc_price_cell_enter (BasicCell *_cell,
60 int *cursor_position,
61 int *start_selection,
62 int *end_selection)
63 {
64 *cursor_position = -1;
65 *start_selection = 0;
66 *end_selection = -1;
67
68 return TRUE;
69 }
70
71 static void
gnc_price_cell_modify_verify(BasicCell * _cell,const char * change,int change_len,const char * newval,int newval_len,int * cursor_position,int * start_selection,int * end_selection)72 gnc_price_cell_modify_verify (BasicCell *_cell,
73 const char *change,
74 int change_len,
75 const char *newval,
76 int newval_len,
77 int *cursor_position,
78 int *start_selection,
79 int *end_selection)
80 {
81 PriceCell *cell = (PriceCell *) _cell;
82 const char *toks = "+-*/=()_";
83 char *validated_newval = NULL;
84
85 DEBUG("%s, %d, %s, %d, %d, %d, %d",
86 change ? (gchar *)change : "(null)", change_len,
87 newval ? (gchar *)newval : "(null)", newval_len,
88 *cursor_position, *start_selection, *end_selection);
89
90 validated_newval = gnc_basic_cell_validate (_cell, cell->print_info,
91 change, newval, toks,
92 cursor_position);
93
94 if (!validated_newval)
95 return;
96
97 gnc_basic_cell_set_value_internal (_cell, validated_newval);
98 g_free (validated_newval);
99
100 *end_selection = *start_selection = *cursor_position;
101 cell->need_to_parse = TRUE;
102 }
103
104 static gint
gnc_price_cell_parse(PriceCell * cell,gboolean update_value)105 gnc_price_cell_parse (PriceCell *cell, gboolean update_value)
106 {
107 const char *newval;
108 char *oldval;
109 gnc_numeric amount;
110
111 if (!cell->need_to_parse)
112 return -1;
113
114 oldval = cell->cell.value;
115 if (oldval == NULL)
116 oldval = "";
117
118 {
119 char *err_location = NULL;
120 if (strlen(g_strstrip(cell->cell.value)) == 0)
121 {
122 cell->amount = gnc_numeric_zero ();
123 }
124 else if (gnc_exp_parser_parse (cell->cell.value, &amount, &err_location))
125 {
126 if (cell->fraction > 0)
127 amount = gnc_numeric_convert (amount, cell->fraction, GNC_HOW_RND_ROUND_HALF_UP);
128
129 cell->amount = amount;
130 }
131 else
132 {
133 return (err_location - cell->cell.value);
134 }
135 }
136
137 if (!update_value)
138 return -1;
139
140 newval = gnc_price_cell_print_value (cell);
141
142 /* If they are identical do nothing */
143 if (strcmp(newval, oldval) == 0)
144 return -1;
145
146 /* Otherwise, change it */
147 gnc_basic_cell_set_value_internal (&cell->cell, newval);
148 return -1;
149 }
150
151 static void
gnc_price_cell_leave(BasicCell * _cell)152 gnc_price_cell_leave (BasicCell *_cell)
153 {
154 gint error_position = -1;
155 PriceCell *cell = (PriceCell *) _cell;
156
157 error_position = gnc_price_cell_parse (cell, TRUE);
158 if (error_position != -1)
159 {
160 gnc_warning_dialog (gnc_ui_get_main_window (NULL),
161 _("An error occurred while processing '%s' at position %d"),
162 cell->cell.value, error_position);
163 }
164
165 }
166
167 BasicCell *
gnc_price_cell_new(void)168 gnc_price_cell_new (void)
169 {
170 PriceCell *cell;
171
172 cell = g_new0 (PriceCell, 1);
173
174 gnc_price_cell_init (cell);
175
176 return &cell->cell;
177 }
178
179 void
gnc_price_cell_init(PriceCell * cell)180 gnc_price_cell_init (PriceCell *cell)
181 {
182 gnc_basic_cell_init (&(cell->cell));
183
184 cell->amount = gnc_numeric_zero ();
185 cell->fraction = 0;
186 cell->blank_zero = TRUE;
187
188 cell->print_info = gnc_default_print_info (FALSE);
189
190 cell->need_to_parse = FALSE;
191
192 cell->cell.enter_cell = gnc_price_cell_enter;
193 cell->cell.modify_verify = gnc_price_cell_modify_verify;
194 cell->cell.leave_cell = gnc_price_cell_leave;
195 cell->cell.set_value = gnc_price_cell_set_value_internal;
196 }
197
198 static const char *
gnc_price_cell_print_value(PriceCell * cell)199 gnc_price_cell_print_value (PriceCell *cell)
200 {
201 if (cell->blank_zero && gnc_numeric_zero_p (cell->amount))
202 return "";
203
204 return xaccPrintAmount (cell->amount, cell->print_info);
205 }
206
207 gnc_numeric
gnc_price_cell_get_value(PriceCell * cell)208 gnc_price_cell_get_value (PriceCell *cell)
209 {
210 if (cell == NULL)
211 return gnc_numeric_zero ();
212
213 gnc_price_cell_parse (cell, FALSE);
214
215 return cell->amount;
216 }
217
218 gboolean
gnc_price_cell_set_value(PriceCell * cell,gnc_numeric amount)219 gnc_price_cell_set_value (PriceCell * cell, gnc_numeric amount)
220 {
221 const char *buff;
222
223 if (cell == NULL)
224 return FALSE;
225
226 if (cell->fraction > 0)
227 amount = gnc_numeric_convert (amount, cell->fraction, GNC_HOW_RND_ROUND_HALF_UP);
228
229 cell->amount = amount;
230 buff = gnc_price_cell_print_value (cell);
231 cell->need_to_parse = FALSE;
232
233 if (g_strcmp0 (buff, cell->cell.value) == 0)
234 return FALSE;
235
236 gnc_basic_cell_set_value_internal (&cell->cell, buff);
237
238 return TRUE;
239 }
240
241 void
gnc_price_cell_set_fraction(PriceCell * cell,int fraction)242 gnc_price_cell_set_fraction (PriceCell *cell, int fraction)
243 {
244 if (cell == NULL)
245 return;
246
247 cell->fraction = ABS (fraction);
248 }
249
250 void
gnc_price_cell_blank(PriceCell * cell)251 gnc_price_cell_blank (PriceCell *cell)
252 {
253 if (cell == NULL)
254 return;
255
256 cell->amount = gnc_numeric_zero ();
257 cell->need_to_parse = FALSE;
258
259 gnc_basic_cell_set_value_internal (&cell->cell, "");
260 }
261
262 void
gnc_price_cell_set_blank_zero(PriceCell * cell,gboolean blank_zero)263 gnc_price_cell_set_blank_zero (PriceCell *cell, gboolean blank_zero)
264 {
265 if (cell == NULL)
266 return;
267
268 cell->blank_zero = blank_zero;
269 }
270
271 void
gnc_price_cell_set_print_info(PriceCell * cell,GNCPrintAmountInfo print_info)272 gnc_price_cell_set_print_info (PriceCell *cell, GNCPrintAmountInfo print_info)
273 {
274 if (cell == NULL)
275 return;
276
277 cell->print_info = print_info;
278 }
279
280 void
gnc_price_cell_set_debt_credit_value(PriceCell * debit,PriceCell * credit,gnc_numeric amount)281 gnc_price_cell_set_debt_credit_value (PriceCell * debit,
282 PriceCell * credit,
283 gnc_numeric amount)
284 {
285 /* debits are positive, credits are negative */
286 if (gnc_numeric_positive_p (amount))
287 {
288 gnc_price_cell_set_value (debit, amount);
289 gnc_price_cell_set_value (credit, gnc_numeric_zero ());
290 }
291 else
292 {
293 gnc_price_cell_set_value (debit, gnc_numeric_zero ());
294 gnc_price_cell_set_value (credit, gnc_numeric_neg (amount));
295 }
296 }
297
298 static void
gnc_price_cell_set_value_internal(BasicCell * _cell,const char * str)299 gnc_price_cell_set_value_internal (BasicCell *_cell, const char *str)
300 {
301 PriceCell *cell = (PriceCell *) _cell;
302 gnc_numeric amount;
303
304 if (str == NULL)
305 str = "";
306
307 if (*str == '\0')
308 gnc_price_cell_set_value (cell, gnc_numeric_zero ());
309 else if (gnc_exp_parser_parse (str, &amount, NULL))
310 gnc_price_cell_set_value (cell, amount);
311 }
312