GnuCash  5.6-150-g038405b370+
numcell.c
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 static const QofLogModule log_module = G_LOG_DOMAIN;
44 
45 /* This static indicates the debugging module that this .o belongs to. */
46 /* static short module = MOD_REGISTER; */
47 
48 static void gnc_num_cell_init (NumCell *cell);
49 static gboolean gnc_num_cell_enter (BasicCell *cell, int *cursor_position,
50  int *start_selection, int *end_selection);
51 
52 /* Parses the string value and returns true if it is a
53  * number. In that case, *num is set to the value parsed. */
54 static gboolean
55 gnc_parse_num (const char *string, long int *num)
56 {
57  long int number;
58 
59  if (string == NULL)
60  return FALSE;
61 
62  if (!gnc_strisnum (string))
63  return FALSE;
64 
65  number = strtol (string, NULL, 10);
66 
67  if ((number == LONG_MIN) || (number == LONG_MAX))
68  return FALSE;
69 
70  if (num != NULL)
71  *num = number;
72 
73  return TRUE;
74 }
75 
76 static void
77 gnc_num_cell_modify_verify (BasicCell *_cell,
78  const char *change,
79  int change_len,
80  const char *newval,
81  int new_val_len,
82  int *cursor_position,
83  int *start_selection,
84  int *end_selection)
85 {
86  NumCell *cell = (NumCell *) _cell;
87  gboolean accel = FALSE;
88  gboolean is_num;
89  long int number = 0;
90  gunichar uc;
91  glong change_chars;
92 
93  if (change == NULL) /* if we are deleting */
94  /* then just accept the proposed change */
95  {
96  gnc_basic_cell_set_value_internal (&cell->cell, newval);
97  // Remove any selection.
98  *end_selection = *start_selection = *cursor_position;
99  return;
100  }
101 
102  change_chars = g_utf8_strlen (change, -1);
103 
104  if ((change_chars == 0) || /* if we are deleting */
105  (change_chars > 1)) /* or entering > 1 char */
106  /* then just accept the proposed change */
107  {
108  gnc_basic_cell_set_value_internal (&cell->cell, newval);
109  return;
110  }
111 
112  /* otherwise, it may be an accelerator key. */
113 
114  is_num = gnc_parse_num (_cell->value, &number);
115 
116  if (is_num && (number < 0))
117  is_num = FALSE;
118 
119  uc = g_utf8_get_char (change);
120  switch (uc)
121  {
122  case '+':
123  case '=':
124  number++;
125  accel = TRUE;
126  break;
127 
128  case '_':
129  case '-':
130  number--;
131  accel = TRUE;
132  break;
133 
134  case '}':
135  case ']':
136  number += 10;
137  accel = TRUE;
138  break;
139 
140  case '{':
141  case '[':
142  number -= 10;
143  accel = TRUE;
144  break;
145  }
146 
147  if (number < 0)
148  number = 0;
149 
150  /* If there is already a non-number there, don't accelerate. */
151  if (accel && !is_num && (g_strcmp0(_cell->value, "") != 0))
152  accel = FALSE;
153 
154  if (accel)
155  {
156  char buff[128];
157 
158  if (!is_num)
159  number = cell->next_num;
160 
161  strcpy (buff, "");
162  snprintf (buff, sizeof(buff), "%ld", number);
163 
164  if (g_strcmp0 (buff, "") == 0)
165  return;
166 
167  gnc_basic_cell_set_value_internal (&cell->cell, buff);
168 
169  *cursor_position = -1;
170 
171  return;
172  }
173 
174  gnc_basic_cell_set_value_internal (&cell->cell, newval);
175 }
176 
177 BasicCell *
178 gnc_num_cell_new (void)
179 {
180  NumCell *cell;
181 
182  cell = g_new0 (NumCell, 1);
183 
184  gnc_num_cell_init (cell);
185 
186  return &cell->cell;
187 }
188 
189 static void
190 gnc_num_cell_set_value_internal (BasicCell *_cell, const char *str)
191 {
192  NumCell *cell = (NumCell *) _cell;
193 
194  if (!cell->next_num_set)
195  {
196  long int number;
197 
198  if (gnc_parse_num (str, &number))
199  cell->next_num = number + 1;
200  }
201 
202  gnc_basic_cell_set_value_internal (_cell, str);
203 }
204 
205 void
206 gnc_num_cell_set_value (NumCell *cell, const char *str)
207 {
208  if (!cell)
209  return;
210 
211  gnc_num_cell_set_value_internal (&cell->cell, str);
212 }
213 
214 gboolean
215 gnc_num_cell_set_last_num (NumCell *cell, const char *str)
216 {
217  long int number;
218 
219  if (!cell)
220  return FALSE;
221 
222  if (gnc_parse_num (str, &number))
223  {
224  cell->next_num = number + 1;
225  cell->next_num_set = TRUE;
226  return TRUE;
227  }
228 
229  return FALSE;
230 }
231 
232 static void
233 gnc_num_cell_init (NumCell *cell)
234 {
235  gnc_basic_cell_init (&(cell->cell));
236 
237  cell->next_num = 0;
238  cell->next_num_set = FALSE;
239 
240  cell->cell.modify_verify = gnc_num_cell_modify_verify;
241  cell->cell.set_value = gnc_num_cell_set_value_internal;
242  cell->cell.enter_cell = gnc_num_cell_enter;
243 }
244 
245 static gboolean
246 gnc_num_cell_enter (BasicCell *cell, int *cursor_position,
247  int *start_selection, int *end_selection)
248 {
249  DEBUG("%d, %d, %d", *cursor_position, *start_selection, *end_selection);
250  *cursor_position = -1;
251  *start_selection = 0;
252  *end_selection = -1;
253  return TRUE;
254 }
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
gboolean gnc_strisnum(const gchar *s)
Returns true if string s is a number, possibly surrounded by whitespace.
Definition: qofutil.cpp:187
All type declarations for the whole Gnucash engine.
The NumCell object implements a number handling cell.
Definition: numcell.h:39