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
gnc_cell_name_equal(const char * cell_name_1,const char * cell_name_2)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 BasicCell *
gnc_basic_cell_new(void)58 gnc_basic_cell_new (void)
59 {
60 BasicCell * cell;
61
62 cell = g_new0 (BasicCell, 1);
63
64 gnc_basic_cell_init (cell);
65
66 return cell;
67 }
68
69 static void
gnc_basic_cell_clear(BasicCell * cell)70 gnc_basic_cell_clear (BasicCell *cell)
71 {
72 g_free (cell->cell_name);
73 cell->cell_name = NULL;
74 g_free (cell->cell_type_name);
75 cell->cell_type_name = NULL;
76 cell->changed = FALSE;
77 cell->conditionally_changed = FALSE;
78
79 cell->value = NULL;
80 cell->value_chars = 0;
81
82 cell->set_value = NULL;
83 cell->enter_cell = NULL;
84 cell->modify_verify = NULL;
85 cell->direct_update = NULL;
86 cell->leave_cell = NULL;
87 cell->gui_realize = NULL;
88 cell->gui_move = NULL;
89 cell->gui_destroy = NULL;
90
91 cell->is_popup = FALSE;
92
93 cell->gui_private = NULL;
94
95 g_free (cell->sample_text);
96 cell->sample_text = NULL;
97 }
98
99 void
gnc_basic_cell_init(BasicCell * cell)100 gnc_basic_cell_init (BasicCell *cell)
101 {
102 gnc_basic_cell_clear (cell);
103
104 cell->value = g_strdup ("");
105 }
106
107 void
gnc_basic_cell_destroy(BasicCell * cell)108 gnc_basic_cell_destroy (BasicCell *cell)
109 {
110 ENTER(" ");
111 if (cell->destroy)
112 cell->destroy (cell);
113
114 /* give any gui elements a chance to clean up */
115 if (cell->gui_destroy)
116 (*(cell->gui_destroy)) (cell);
117
118 /* free up data strings */
119 g_free (cell->value);
120 cell->value = NULL;
121
122 /* help prevent access to freed memory */
123 gnc_basic_cell_clear (cell);
124
125 /* free the object itself */
126 g_free (cell);
127 LEAVE(" ");
128 }
129
130 void
gnc_basic_cell_set_name(BasicCell * cell,const char * name)131 gnc_basic_cell_set_name (BasicCell *cell, const char *name)
132 {
133 if (!cell) return;
134 if (cell->cell_name == name) return;
135
136 g_free (cell->cell_name);
137 cell->cell_name = g_strdup (name);
138 }
139
140 gboolean
gnc_basic_cell_has_name(BasicCell * cell,const char * name)141 gnc_basic_cell_has_name (BasicCell *cell, const char *name)
142 {
143 if (!cell) return FALSE;
144 if (!name) return FALSE;
145 if (!cell->cell_name) return FALSE;
146
147 return (strcmp (name, cell->cell_name) == 0);
148 }
149
150
151 void
gnc_basic_cell_set_type_name(BasicCell * cell,const gchar * type_name)152 gnc_basic_cell_set_type_name (BasicCell *cell, const gchar *type_name)
153 {
154 if (!cell) return;
155 if (cell->cell_type_name == type_name) return;
156
157 g_free (cell->cell_type_name);
158 cell->cell_type_name = g_strdup(type_name);
159 }
160
161 gboolean
gnc_basic_cell_has_type_name(BasicCell * cell,const gchar * type_name)162 gnc_basic_cell_has_type_name (BasicCell *cell, const gchar *type_name)
163 {
164 if (!cell) return FALSE;
165 if (!type_name) return FALSE;
166 if (!cell->cell_type_name) return FALSE;
167
168 return (g_strcmp0 (type_name, cell->cell_type_name));
169 }
170
171 void
gnc_basic_cell_set_sample_text(BasicCell * cell,const char * sample_text)172 gnc_basic_cell_set_sample_text (BasicCell *cell,
173 const char *sample_text)
174 {
175 if (!cell) return;
176 if (cell->sample_text == sample_text) return;
177
178 g_free (cell->sample_text);
179 cell->sample_text = g_strdup (sample_text);
180 }
181
182 void
gnc_basic_cell_set_alignment(BasicCell * cell,CellAlignment alignment)183 gnc_basic_cell_set_alignment (BasicCell *cell,
184 CellAlignment alignment)
185 {
186 if (!cell) return;
187 cell->alignment = alignment;
188 }
189
190 void
gnc_basic_cell_set_expandable(BasicCell * cell,gboolean expandable)191 gnc_basic_cell_set_expandable (BasicCell *cell, gboolean expandable)
192 {
193 if (!cell) return;
194 cell->expandable = expandable;
195 }
196
197 void
gnc_basic_cell_set_span(BasicCell * cell,gboolean span)198 gnc_basic_cell_set_span (BasicCell *cell, gboolean span)
199 {
200 if (!cell) return;
201 cell->span = span;
202 }
203
204 const char *
gnc_basic_cell_get_value(BasicCell * cell)205 gnc_basic_cell_get_value (BasicCell *cell)
206 {
207 g_return_val_if_fail (cell != NULL, NULL);
208
209 return cell->value;
210 }
211
212 void
gnc_basic_cell_set_value(BasicCell * cell,const char * val)213 gnc_basic_cell_set_value (BasicCell *cell, const char *val)
214 {
215 CellSetValueFunc cb;
216
217 cb = cell->set_value;
218 if (cb)
219 {
220 /* avoid recursion by disabling the
221 * callback while it's being called. */
222 cell->set_value = NULL;
223 cb (cell, val);
224 cell->set_value = cb;
225 }
226 else
227 gnc_basic_cell_set_value_internal (cell, val);
228 }
229
230 gboolean
gnc_basic_cell_get_changed(BasicCell * cell)231 gnc_basic_cell_get_changed (BasicCell *cell)
232 {
233 if (!cell) return FALSE;
234
235 return cell->changed;
236 }
237
238 gboolean
gnc_basic_cell_get_conditionally_changed(BasicCell * cell)239 gnc_basic_cell_get_conditionally_changed (BasicCell *cell)
240 {
241 if (!cell) return FALSE;
242
243 return cell->conditionally_changed;
244 }
245
246 void
gnc_basic_cell_set_changed(BasicCell * cell,gboolean changed)247 gnc_basic_cell_set_changed (BasicCell *cell, gboolean changed)
248 {
249 if (!cell) return;
250
251 cell->changed = changed;
252 }
253
254 void
gnc_basic_cell_set_conditionally_changed(BasicCell * cell,gboolean changed)255 gnc_basic_cell_set_conditionally_changed (BasicCell *cell, gboolean changed)
256 {
257 if (!cell) return;
258
259 cell->conditionally_changed = changed;
260 }
261
262 void
gnc_basic_cell_set_value_internal(BasicCell * cell,const char * value)263 gnc_basic_cell_set_value_internal (BasicCell *cell, const char *value)
264 {
265 if (value == NULL)
266 value = "";
267
268 /* If the caller tries to set the value with our own value then do
269 * nothing because we have no work to do (or, at least, all the work
270 * will result in the status-quo, so why do anything?) See bug
271 * #103174 and the description in the changelog on 2003-09-04.
272 */
273 if (cell->value == value)
274 return;
275
276 g_free (cell->value);
277 cell->value = g_strdup (value);
278 cell->value_chars = g_utf8_strlen(value, -1);
279 }
280
281 char *
gnc_basic_cell_validate(BasicCell * cell,GNCPrintAmountInfo print_info,const char * change,const char * newval,const char * toks,gint * cursor_position)282 gnc_basic_cell_validate (BasicCell *cell, GNCPrintAmountInfo print_info,
283 const char *change, const char *newval,
284 const char *toks, gint *cursor_position)
285 {
286 struct lconv *lc = gnc_localeconv ();
287 gunichar decimal_point;
288 gunichar thousands_sep;
289 const char *symbol = NULL;
290 char *tokens;
291
292 if (print_info.monetary)
293 {
294 const gnc_commodity *comm = print_info.commodity;
295
296 decimal_point = g_utf8_get_char (lc->mon_decimal_point);
297 thousands_sep = g_utf8_get_char (lc->mon_thousands_sep);
298
299 if (comm)
300 symbol = gnc_commodity_get_nice_symbol (comm);
301 else
302 symbol = gnc_commodity_get_nice_symbol (gnc_default_currency ());
303
304 tokens = g_strconcat (toks, symbol, NULL);
305 }
306 else
307 {
308 decimal_point = g_utf8_get_char (lc->decimal_point);
309 thousands_sep = g_utf8_get_char (lc->thousands_sep);
310
311 tokens = g_strdup (toks);
312 }
313
314 for (const char *c = change; c && *c; c = g_utf8_next_char (c))
315 {
316 gunichar uc = g_utf8_get_char (c);
317 if (!g_unichar_isdigit (uc) &&
318 !g_unichar_isspace (uc) &&
319 !g_unichar_isalpha (uc) &&
320 (decimal_point != uc) &&
321 (thousands_sep != uc) &&
322 (g_utf8_strchr (tokens, -1, uc) == NULL))
323 {
324 g_free (tokens);
325 return NULL;
326 }
327 }
328 g_free (tokens);
329
330 gnc_filter_text_set_cursor_position (newval, symbol, cursor_position);
331
332 return gnc_filter_text_for_currency_symbol (newval, symbol);
333 }
334