GnuCash  5.6-150-g038405b370+
basiccell.c
1 /********************************************************************\
2  * basiccell.c -- base class for editable cell in a table *
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  * basiccell.c
26  *
27  * FUNCTION:
28  * Implements the base class for the cell handler object.
29  * See the header file for additional documentation.
30  *
31  * HISTORY:
32  * Copyright (c) 1998 Linas Vepstas
33  * Copyright (c) 2000 Dave Peticolas <dave@krondo.com>
34  */
35 
36 #include <config.h>
37 
38 #include <stdlib.h>
39 #include <locale.h>
40 #include <string.h>
41 
42 #include "gnc-locale-utils.h"
43 
44 #include "basiccell.h"
45 #include "gnc-engine.h"
46 
47 /* Debugging module */
48 static QofLogModule log_module = GNC_MOD_REGISTER;
49 
50 gboolean
51 gnc_cell_name_equal (const char * cell_name_1,
52  const char * cell_name_2)
53 {
54  return (g_strcmp0 (cell_name_1, cell_name_2) == 0);
55 }
56 
57 static void
58 gnc_basic_cell_gui_realize (BasicCell* bcell, gpointer data)
59 {
60  bcell->gui_private = data;
61  bcell->gui_realize = NULL;
62 }
63 
64 static void
65 gnc_basic_cell_gui_destroy (BasicCell* bcell)
66 {
67  if (bcell->gui_realize == NULL)
68  {
69  bcell->gui_realize = gnc_basic_cell_gui_realize;
70  }
71 }
72 
73 BasicCell *
74 gnc_basic_cell_new (void)
75 {
76  BasicCell * cell;
77 
78  cell = g_new0 (BasicCell, 1);
79 
80  gnc_basic_cell_init (cell);
81 
82  return cell;
83 }
84 
85 static void
86 gnc_basic_cell_clear (BasicCell *cell)
87 {
88  g_free (cell->cell_name);
89  cell->cell_name = NULL;
90  g_free (cell->cell_type_name);
91  cell->cell_type_name = NULL;
92  cell->changed = FALSE;
93  cell->conditionally_changed = FALSE;
94 
95  cell->value = NULL;
96  cell->value_chars = 0;
97 
98  cell->set_value = NULL;
99  cell->enter_cell = NULL;
100  cell->modify_verify = NULL;
101  cell->direct_update = NULL;
102  cell->leave_cell = NULL;
103  cell->gui_realize = NULL;
104  cell->gui_move = NULL;
105  cell->gui_destroy = NULL;
106 
107  cell->is_popup = FALSE;
108 
109  cell->gui_private = NULL;
110 
111  g_free (cell->sample_text);
112  cell->sample_text = NULL;
113 }
114 
115 void
116 gnc_basic_cell_init (BasicCell *cell)
117 {
118  gnc_basic_cell_clear (cell);
119 
120  cell->gui_realize = gnc_basic_cell_gui_realize;
121  cell->gui_destroy = gnc_basic_cell_gui_destroy;
122 
123  cell->value = g_strdup ("");
124 }
125 
126 void
127 gnc_basic_cell_destroy (BasicCell *cell)
128 {
129  ENTER(" ");
130  if (cell->destroy)
131  cell->destroy (cell);
132 
133  /* give any gui elements a chance to clean up */
134  if (cell->gui_destroy)
135  (*(cell->gui_destroy)) (cell);
136 
137  /* free up data strings */
138  g_free (cell->value);
139  cell->value = NULL;
140 
141  /* help prevent access to freed memory */
142  gnc_basic_cell_clear (cell);
143 
144  /* free the object itself */
145  g_free (cell);
146  LEAVE(" ");
147 }
148 
149 void
150 gnc_basic_cell_set_name (BasicCell *cell, const char *name)
151 {
152  if (!cell) return;
153  if (cell->cell_name == name) return;
154 
155  g_free (cell->cell_name);
156  cell->cell_name = g_strdup (name);
157 }
158 
159 gboolean
160 gnc_basic_cell_has_name (BasicCell *cell, const char *name)
161 {
162  if (!cell) return FALSE;
163  if (!name) return FALSE;
164  if (!cell->cell_name) return FALSE;
165 
166  return (strcmp (name, cell->cell_name) == 0);
167 }
168 
169 
170 void
171 gnc_basic_cell_set_type_name (BasicCell *cell, const gchar *type_name)
172 {
173  if (!cell) return;
174  if (cell->cell_type_name == type_name) return;
175 
176  g_free (cell->cell_type_name);
177  cell->cell_type_name = g_strdup(type_name);
178 }
179 
180 gboolean
181 gnc_basic_cell_has_type_name (BasicCell *cell, const gchar *type_name)
182 {
183  if (!cell) return FALSE;
184  if (!type_name) return FALSE;
185  if (!cell->cell_type_name) return FALSE;
186 
187  return (g_strcmp0 (type_name, cell->cell_type_name));
188 }
189 
190 void
191 gnc_basic_cell_set_sample_text (BasicCell *cell,
192  const char *sample_text)
193 {
194  if (!cell) return;
195  if (cell->sample_text == sample_text) return;
196 
197  g_free (cell->sample_text);
198  cell->sample_text = g_strdup (sample_text);
199 }
200 
201 void
202 gnc_basic_cell_set_alignment (BasicCell *cell,
203  CellAlignment alignment)
204 {
205  if (!cell) return;
206  cell->alignment = alignment;
207 }
208 
209 void
210 gnc_basic_cell_set_expandable (BasicCell *cell, gboolean expandable)
211 {
212  if (!cell) return;
213  cell->expandable = expandable;
214 }
215 
216 void
217 gnc_basic_cell_set_span (BasicCell *cell, gboolean span)
218 {
219  if (!cell) return;
220  cell->span = span;
221 }
222 
223 const char *
224 gnc_basic_cell_get_value (BasicCell *cell)
225 {
226  g_return_val_if_fail (cell != NULL, NULL);
227 
228  return cell->value;
229 }
230 
231 void
232 gnc_basic_cell_set_value (BasicCell *cell, const char *val)
233 {
234  CellSetValueFunc cb;
235 
236  cb = cell->set_value;
237  if (cb)
238  {
239  /* avoid recursion by disabling the
240  * callback while it's being called. */
241  cell->set_value = NULL;
242  cb (cell, val);
243  cell->set_value = cb;
244  }
245  else
246  gnc_basic_cell_set_value_internal (cell, val);
247 }
248 
249 gboolean
250 gnc_basic_cell_get_changed (BasicCell *cell)
251 {
252  if (!cell) return FALSE;
253 
254  return cell->changed;
255 }
256 
257 gboolean
258 gnc_basic_cell_get_conditionally_changed (BasicCell *cell)
259 {
260  if (!cell) return FALSE;
261 
262  return cell->conditionally_changed;
263 }
264 
265 void
266 gnc_basic_cell_set_changed (BasicCell *cell, gboolean changed)
267 {
268  if (!cell) return;
269 
270  cell->changed = changed;
271 }
272 
273 void
274 gnc_basic_cell_set_conditionally_changed (BasicCell *cell, gboolean changed)
275 {
276  if (!cell) return;
277 
278  cell->conditionally_changed = changed;
279 }
280 
281 void
282 gnc_basic_cell_set_value_internal (BasicCell *cell, const char *value)
283 {
284  if (value == NULL)
285  value = "";
286 
287  /* If the caller tries to set the value with our own value then do
288  * nothing because we have no work to do (or, at least, all the work
289  * will result in the status-quo, so why do anything?) See bug
290  * #103174 and the description in the changelog on 2003-09-04.
291  */
292  if (cell->value == value)
293  return;
294 
295  g_free (cell->value);
296  cell->value = g_strdup (value);
297  cell->value_chars = g_utf8_strlen(value, -1);
298 }
299 
300 char *
301 gnc_basic_cell_validate (BasicCell *cell, GNCPrintAmountInfo print_info,
302  const char *change, const char *newval,
303  const char *toks, gint *cursor_position)
304 {
305  struct lconv *lc = gnc_localeconv ();
306  gunichar decimal_point;
307  gunichar thousands_sep;
308  const char *symbol = NULL;
309  char *tokens;
310 
311  if (print_info.monetary)
312  {
313  const gnc_commodity *comm = print_info.commodity;
314 
315  decimal_point = g_utf8_get_char (lc->mon_decimal_point);
316  thousands_sep = g_utf8_get_char (lc->mon_thousands_sep);
317 
318  if (comm)
319  symbol = gnc_commodity_get_nice_symbol (comm);
320  else
322 
323  tokens = g_strconcat (toks, symbol, NULL);
324  }
325  else
326  {
327  decimal_point = g_utf8_get_char (lc->decimal_point);
328  thousands_sep = g_utf8_get_char (lc->thousands_sep);
329 
330  tokens = g_strdup (toks);
331  }
332 
333  for (const char *c = change; c && *c; c = g_utf8_next_char (c))
334  {
335  gunichar uc = g_utf8_get_char (c);
336  if (!g_unichar_isdigit (uc) &&
337  !g_unichar_isspace (uc) &&
338  !g_unichar_isalpha (uc) &&
339  (decimal_point != uc) &&
340  (thousands_sep != uc) &&
341  (g_utf8_strchr (tokens, -1, uc) == NULL))
342  {
343  g_free (tokens);
344  return NULL;
345  }
346  }
347  g_free (tokens);
348 
349  gnc_filter_text_set_cursor_position (newval, symbol, cursor_position);
350 
351  return gnc_filter_text_for_currency_symbol (newval, symbol);
352 }
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
void gnc_filter_text_set_cursor_position(const char *incoming_text, const char *symbol, int *zcursor_position)
Updates cursor_position after removal of currency symbols.
const char * gnc_commodity_get_nice_symbol(const gnc_commodity *cm)
Retrieve a symbol for the specified commodity, suitable for display to the user.
All type declarations for the whole Gnucash engine.
char * gnc_filter_text_for_currency_symbol(const char *incoming_text, const char *symbol)
Returns the incoming text removed of a currency symbol.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282