1 /********************************************************************\
2 * numcell.c -- number handling cell incl. accelerator key support *
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 * numcell.c
26 *
27 * FUNCTION:
28 * implements a gui-independent number handling cell.
29 *
30 * HISTORY:
31 * Copyright (C) 2000 Dave Peticolas <peticola@cs.ucdavis.edu>
32 */
33
34 #include <config.h>
35
36 #include <limits.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "numcell.h"
41 #include "gnc-engine.h"
42
43
44 /* This static indicates the debugging module that this .o belongs to. */
45 /* static short module = MOD_REGISTER; */
46
47 static void gnc_num_cell_init (NumCell *cell);
48
49
50 /* Parses the string value and returns true if it is a
51 * number. In that case, *num is set to the value parsed. */
52 static gboolean
gnc_parse_num(const char * string,long int * num)53 gnc_parse_num (const char *string, long int *num)
54 {
55 long int number;
56
57 if (string == NULL)
58 return FALSE;
59
60 if (!gnc_strisnum (string))
61 return FALSE;
62
63 number = strtol (string, NULL, 10);
64
65 if ((number == LONG_MIN) || (number == LONG_MAX))
66 return FALSE;
67
68 if (num != NULL)
69 *num = number;
70
71 return TRUE;
72 }
73
74 static void
gnc_num_cell_modify_verify(BasicCell * _cell,const char * change,int change_len,const char * newval,int new_val_len,int * cursor_position,int * start_selection,int * end_selection)75 gnc_num_cell_modify_verify (BasicCell *_cell,
76 const char *change,
77 int change_len,
78 const char *newval,
79 int new_val_len,
80 int *cursor_position,
81 int *start_selection,
82 int *end_selection)
83 {
84 NumCell *cell = (NumCell *) _cell;
85 gboolean accel = FALSE;
86 gboolean is_num;
87 long int number = 0;
88 gunichar uc;
89 glong change_chars;
90
91 if (change == NULL) /* if we are deleting */
92 /* then just accept the proposed change */
93 {
94 gnc_basic_cell_set_value_internal (&cell->cell, newval);
95 // Remove any selection.
96 *end_selection = *start_selection = *cursor_position;
97 return;
98 }
99
100 change_chars = g_utf8_strlen (change, -1);
101
102 if ((change_chars == 0) || /* if we are deleting */
103 (change_chars > 1)) /* or entering > 1 char */
104 /* then just accept the proposed change */
105 {
106 gnc_basic_cell_set_value_internal (&cell->cell, newval);
107 return;
108 }
109
110 /* otherwise, it may be an accelerator key. */
111
112 is_num = gnc_parse_num (_cell->value, &number);
113
114 if (is_num && (number < 0))
115 is_num = FALSE;
116
117 uc = g_utf8_get_char (change);
118 switch (uc)
119 {
120 case '+':
121 case '=':
122 number++;
123 accel = TRUE;
124 break;
125
126 case '_':
127 case '-':
128 number--;
129 accel = TRUE;
130 break;
131
132 case '}':
133 case ']':
134 number += 10;
135 accel = TRUE;
136 break;
137
138 case '{':
139 case '[':
140 number -= 10;
141 accel = TRUE;
142 break;
143 }
144
145 if (number < 0)
146 number = 0;
147
148 /* If there is already a non-number there, don't accelerate. */
149 if (accel && !is_num && (g_strcmp0(_cell->value, "") != 0))
150 accel = FALSE;
151
152 if (accel)
153 {
154 char buff[128];
155
156 if (!is_num)
157 number = cell->next_num;
158
159 strcpy (buff, "");
160 snprintf (buff, sizeof(buff), "%ld", number);
161
162 if (g_strcmp0 (buff, "") == 0)
163 return;
164
165 gnc_basic_cell_set_value_internal (&cell->cell, buff);
166
167 *cursor_position = -1;
168
169 return;
170 }
171
172 gnc_basic_cell_set_value_internal (&cell->cell, newval);
173 }
174
175 BasicCell *
gnc_num_cell_new(void)176 gnc_num_cell_new (void)
177 {
178 NumCell *cell;
179
180 cell = g_new0 (NumCell, 1);
181
182 gnc_num_cell_init (cell);
183
184 return &cell->cell;
185 }
186
187 static void
gnc_num_cell_set_value_internal(BasicCell * _cell,const char * str)188 gnc_num_cell_set_value_internal (BasicCell *_cell, const char *str)
189 {
190 NumCell *cell = (NumCell *) _cell;
191
192 if (!cell->next_num_set)
193 {
194 long int number;
195
196 if (gnc_parse_num (str, &number))
197 cell->next_num = number + 1;
198 }
199
200 gnc_basic_cell_set_value_internal (_cell, str);
201 }
202
203 void
gnc_num_cell_set_value(NumCell * cell,const char * str)204 gnc_num_cell_set_value (NumCell *cell, const char *str)
205 {
206 if (!cell)
207 return;
208
209 gnc_num_cell_set_value_internal (&cell->cell, str);
210 }
211
212 gboolean
gnc_num_cell_set_last_num(NumCell * cell,const char * str)213 gnc_num_cell_set_last_num (NumCell *cell, const char *str)
214 {
215 long int number;
216
217 if (!cell)
218 return FALSE;
219
220 if (gnc_parse_num (str, &number))
221 {
222 cell->next_num = number + 1;
223 cell->next_num_set = TRUE;
224 return TRUE;
225 }
226
227 return FALSE;
228 }
229
230 static void
gnc_num_cell_init(NumCell * cell)231 gnc_num_cell_init (NumCell *cell)
232 {
233 gnc_basic_cell_init (&(cell->cell));
234
235 cell->next_num = 0;
236 cell->next_num_set = FALSE;
237
238 cell->cell.modify_verify = gnc_num_cell_modify_verify;
239 cell->cell.set_value = gnc_num_cell_set_value_internal;
240 }
241