GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
numcell.c
1 /********************************************************************\
2  * numcell.c -- number handling cell incl. accelarator 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 [email protected] *
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 <[email protected]>
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
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
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  return;
96  }
97 
98  change_chars = g_utf8_strlen (change, -1);
99 
100  if ((change_chars == 0) || /* if we are deleting */
101  (change_chars > 1)) /* or entering > 1 char */
102  /* then just accept the proposed change */
103  {
104  gnc_basic_cell_set_value_internal (&cell->cell, newval);
105  return;
106  }
107 
108  /* otherwise, it may be an accelerator key. */
109 
110  is_num = gnc_parse_num (_cell->value, &number);
111 
112  if (is_num && (number < 0))
113  is_num = FALSE;
114 
115  uc = g_utf8_get_char (change);
116  switch (uc)
117  {
118  case '+':
119  case '=':
120  number++;
121  accel = TRUE;
122  break;
123 
124  case '_':
125  case '-':
126  number--;
127  accel = TRUE;
128  break;
129 
130  case '}':
131  case ']':
132  number += 10;
133  accel = TRUE;
134  break;
135 
136  case '{':
137  case '[':
138  number -= 10;
139  accel = TRUE;
140  break;
141  }
142 
143  if (number < 0)
144  number = 0;
145 
146  /* If there is already a non-number there, don't accelerate. */
147  if (accel && !is_num && (g_strcmp0(_cell->value, "") != 0))
148  accel = FALSE;
149 
150  if (accel)
151  {
152  char buff[128];
153 
154  if (!is_num)
155  number = cell->next_num;
156 
157  strcpy (buff, "");
158  snprintf (buff, sizeof(buff), "%ld", number);
159 
160  if (g_strcmp0 (buff, "") == 0)
161  return;
162 
163  gnc_basic_cell_set_value_internal (&cell->cell, buff);
164 
165  *cursor_position = -1;
166 
167  return;
168  }
169 
170  gnc_basic_cell_set_value_internal (&cell->cell, newval);
171 }
172 
173 BasicCell *
174 gnc_num_cell_new (void)
175 {
176  NumCell *cell;
177 
178  cell = g_new0 (NumCell, 1);
179 
180  gnc_num_cell_init (cell);
181 
182  return &cell->cell;
183 }
184 
185 static void
186 gnc_num_cell_set_value_internal (BasicCell *_cell, const char *str)
187 {
188  NumCell *cell = (NumCell *) _cell;
189 
190  if (!cell->next_num_set)
191  {
192  long int number;
193 
194  if (gnc_parse_num (str, &number))
195  cell->next_num = number + 1;
196  }
197 
198  gnc_basic_cell_set_value_internal (_cell, str);
199 }
200 
201 void
202 gnc_num_cell_set_value (NumCell *cell, const char *str)
203 {
204  if (!cell)
205  return;
206 
207  gnc_num_cell_set_value_internal (&cell->cell, str);
208 }
209 
210 gboolean
211 gnc_num_cell_set_last_num (NumCell *cell, const char *str)
212 {
213  long int number;
214 
215  if (!cell)
216  return FALSE;
217 
218  if (gnc_parse_num (str, &number))
219  {
220  cell->next_num = number + 1;
221  cell->next_num_set = TRUE;
222  return TRUE;
223  }
224 
225  return FALSE;
226 }
227 
228 static void
229 gnc_num_cell_init (NumCell *cell)
230 {
231  gnc_basic_cell_init (&(cell->cell));
232 
233  cell->next_num = 0;
234  cell->next_num_set = FALSE;
235 
236  cell->cell.modify_verify = gnc_num_cell_modify_verify;
237  cell->cell.set_value = gnc_num_cell_set_value_internal;
238 }
gboolean gnc_strisnum(const gchar *s)
All type declarations for the whole Gnucash engine.