GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pricecell.c
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 [email protected] *
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 <locale.h>
40 #include <string.h>
41 
42 #include "gnc-exp-parser.h"
43 #include "gnc-locale-utils.h"
44 #include "gnc-engine.h"
45 #include "gnc-ui-util.h"
46 #include "gnc-ui.h"
47 
48 #include "basiccell.h"
49 #include "pricecell.h"
50 
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
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
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  struct lconv *lc = gnc_localeconv ();
83  const char *toks = "+-*/=()_";
84  gunichar decimal_point;
85  gunichar thousands_sep;
86  const char *c;
87  gunichar uc;
88 
89  /* accept the newval string if user action was delete */
90  if (change == NULL)
91  {
92  gnc_basic_cell_set_value_internal (_cell, newval);
93  cell->need_to_parse = TRUE;
94  return;
95  }
96 
97  if (cell->print_info.monetary)
98  decimal_point = g_utf8_get_char(lc->mon_decimal_point);
99  else
100  decimal_point = g_utf8_get_char(lc->decimal_point);
101 
102  if (cell->print_info.monetary)
103  thousands_sep = g_utf8_get_char(lc->mon_thousands_sep);
104  else
105  thousands_sep = g_utf8_get_char(lc->thousands_sep);
106 
107  c = change;
108  while (*c)
109  {
110  uc = g_utf8_get_char (c);
111  if (!g_unichar_isdigit (uc) &&
112  !g_unichar_isspace (uc) &&
113  !g_unichar_isalpha (uc) &&
114  (decimal_point != uc) &&
115  (thousands_sep != uc) &&
116  (g_utf8_strchr (toks, -1, uc) == NULL))
117  return;
118  c = g_utf8_next_char (c);
119  }
120 
121  gnc_basic_cell_set_value_internal (_cell, newval);
122  cell->need_to_parse = TRUE;
123 }
124 
125 static gint
126 gnc_price_cell_parse (PriceCell *cell, gboolean update_value)
127 {
128  const char *newval;
129  char *oldval;
130  gnc_numeric amount;
131 
132  if (!cell->need_to_parse)
133  return -1;
134 
135  oldval = cell->cell.value;
136  if (oldval == NULL)
137  oldval = "";
138 
139  {
140  char *err_location = NULL;
141  if (strlen(g_strstrip(cell->cell.value)) == 0)
142  {
143  cell->amount = gnc_numeric_zero ();
144  }
145  else if (gnc_exp_parser_parse (cell->cell.value, &amount, &err_location))
146  {
147  if (cell->fraction > 0)
148  amount = gnc_numeric_convert (amount, cell->fraction, GNC_HOW_RND_ROUND_HALF_UP);
149 
150  cell->amount = amount;
151  }
152  else
153  {
154  return (err_location - cell->cell.value);
155  }
156  }
157 
158  if (!update_value)
159  return -1;
160 
161  newval = gnc_price_cell_print_value (cell);
162 
163  /* If they are identical do nothing */
164  if (strcmp(newval, oldval) == 0)
165  return -1;
166 
167  /* Otherwise, change it */
168  gnc_basic_cell_set_value_internal (&cell->cell, newval);
169  return -1;
170 }
171 
172 static void
173 gnc_price_cell_leave (BasicCell *_cell)
174 {
175  gint error_position = -1;
176  PriceCell *cell = (PriceCell *) _cell;
177 
178  error_position = gnc_price_cell_parse (cell, TRUE);
179  if (error_position != -1)
180  {
181  gnc_warning_dialog(NULL, _("An error occurred while processing %s."),
182  cell->cell.value);
183  }
184 
185 }
186 
187 BasicCell *
188 gnc_price_cell_new (void)
189 {
190  PriceCell *cell;
191 
192  cell = g_new0 (PriceCell, 1);
193 
194  gnc_price_cell_init (cell);
195 
196  return &cell->cell;
197 }
198 
199 void
200 gnc_price_cell_init (PriceCell *cell)
201 {
202  gnc_basic_cell_init (&(cell->cell));
203 
204  cell->amount = gnc_numeric_zero ();
205  cell->fraction = 0;
206  cell->blank_zero = TRUE;
207 
208  cell->print_info = gnc_default_print_info (FALSE);
209 
210  cell->need_to_parse = FALSE;
211 
212  cell->cell.enter_cell = gnc_price_cell_enter;
213  cell->cell.modify_verify = gnc_price_cell_modify_verify;
214  cell->cell.leave_cell = gnc_price_cell_leave;
215  cell->cell.set_value = gnc_price_cell_set_value_internal;
216 }
217 
218 static const char *
219 gnc_price_cell_print_value (PriceCell *cell)
220 {
221  if (cell->blank_zero && gnc_numeric_zero_p (cell->amount))
222  return "";
223 
224  return xaccPrintAmount (cell->amount, cell->print_info);
225 }
226 
228 gnc_price_cell_get_value (PriceCell *cell)
229 {
230  if (cell == NULL)
231  return gnc_numeric_zero ();
232 
233  gnc_price_cell_parse (cell, FALSE);
234 
235  return cell->amount;
236 }
237 
238 gboolean
239 gnc_price_cell_set_value (PriceCell * cell, gnc_numeric amount)
240 {
241  const char *buff;
242 
243  if (cell == NULL)
244  return FALSE;
245 
246  if (cell->fraction > 0)
247  amount = gnc_numeric_convert (amount, cell->fraction, GNC_HOW_RND_ROUND_HALF_UP);
248 
249  cell->amount = amount;
250  buff = gnc_price_cell_print_value (cell);
251  cell->need_to_parse = FALSE;
252 
253  if (g_strcmp0 (buff, cell->cell.value) == 0)
254  return FALSE;
255 
256  gnc_basic_cell_set_value_internal (&cell->cell, buff);
257 
258  return TRUE;
259 }
260 
261 void
262 gnc_price_cell_set_fraction (PriceCell *cell, int fraction)
263 {
264  if (cell == NULL)
265  return;
266 
267  cell->fraction = ABS (fraction);
268 }
269 
270 void
271 gnc_price_cell_blank (PriceCell *cell)
272 {
273  if (cell == NULL)
274  return;
275 
276  cell->amount = gnc_numeric_zero ();
277  cell->need_to_parse = FALSE;
278 
279  gnc_basic_cell_set_value_internal (&cell->cell, "");
280 }
281 
282 void
283 gnc_price_cell_set_blank_zero (PriceCell *cell, gboolean blank_zero)
284 {
285  if (cell == NULL)
286  return;
287 
288  cell->blank_zero = blank_zero;
289 }
290 
291 void
292 gnc_price_cell_set_print_info (PriceCell *cell, GNCPrintAmountInfo print_info)
293 {
294  if (cell == NULL)
295  return;
296 
297  cell->print_info = print_info;
298 }
299 
300 void
301 gnc_price_cell_set_debt_credit_value (PriceCell * debit,
302  PriceCell * credit,
303  gnc_numeric amount)
304 {
305  /* debits are positive, credits are negative */
306  if (gnc_numeric_positive_p (amount))
307  {
308  gnc_price_cell_set_value (debit, amount);
309  gnc_price_cell_set_value (credit, gnc_numeric_zero ());
310  }
311  else
312  {
313  gnc_price_cell_set_value (debit, gnc_numeric_zero ());
314  gnc_price_cell_set_value (credit, gnc_numeric_neg (amount));
315  }
316 }
317 
318 static void
319 gnc_price_cell_set_value_internal (BasicCell *_cell, const char *str)
320 {
321  PriceCell *cell = (PriceCell *) _cell;
322  gnc_numeric amount;
323 
324  if (str == NULL)
325  str = "";
326 
327  if (*str == '\0')
328  gnc_price_cell_set_value (cell, gnc_numeric_zero ());
329  else if (gnc_exp_parser_parse (str, &amount, NULL))
330  gnc_price_cell_set_value (cell, amount);
331 }
utility functions for the GnuCash UI
gnc_numeric gnc_numeric_neg(gnc_numeric a)
gboolean gnc_numeric_zero_p(gnc_numeric a)
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)