GnuCash  5.6-150-g038405b370+
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 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
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  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
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
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 *
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
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 *
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
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
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
243 {
244  if (cell == NULL)
245  return;
246 
247  cell->fraction = ABS (fraction);
248 }
249 
250 void
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
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
273 {
274  if (cell == NULL)
275  return;
276 
277  cell->print_info = print_info;
278 }
279 
280 void
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
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 }
gboolean blank_zero
fraction used for rounding, if 0 no rounding
Definition: pricecell.h:59
int fraction
the amount associated with this cell
Definition: pricecell.h:58
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
utility functions for the GnuCash UI
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void gnc_price_cell_blank(PriceCell *cell)
Sets the cell as blank, regardless of the blank_zero value.
Definition: pricecell.c:251
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
The PriceCell object implements a cell handler that stores a single double-precision value...
Definition: pricecell.h:54
GNCPrintAmountInfo print_info
controls printing of zero values
Definition: pricecell.h:60
All type declarations for the whole Gnucash engine.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
void gnc_price_cell_set_fraction(PriceCell *cell, int fraction)
Sets the fraction used for rounding.
Definition: pricecell.c:242
void gnc_price_cell_set_print_info(PriceCell *cell, GNCPrintAmountInfo print_info)
set the printing context of the price cell
Definition: pricecell.c:272
gboolean need_to_parse
amount printing context
Definition: pricecell.h:61
void gnc_price_cell_set_blank_zero(PriceCell *cell, gboolean blank_zero)
determines whether 0 values are left blank or printed.
Definition: pricecell.c:263
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
gboolean gnc_price_cell_set_value(PriceCell *cell, gnc_numeric amount)
updates amount, returns TRUE if string representation actually changed
Definition: pricecell.c:219
BasicCell * gnc_price_cell_new(void)
installs a callback to handle price recording
Definition: pricecell.c:168
void gnc_price_cell_set_debt_credit_value(PriceCell *debit, PriceCell *credit, gnc_numeric amount)
updates two cells; the deb cell if amt is negative, the credit cell if amount is positive, and makes the other cell blank.
Definition: pricecell.c:281
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
Definition: pricecell.c:208