GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pricecell-gnome.c
1 /********************************************************************\
2  * This program is free software; you can redistribute it and/or *
3  * modify it under the terms of the GNU General Public License as *
4  * published by the Free Software Foundation; either version 2 of *
5  * the License, or (at your option) any later version. *
6  * *
7  * This program is distributed in the hope that it will be useful, *
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
10  * GNU General Public License for more details. *
11  * *
12  * You should have received a copy of the GNU General Public License*
13  * along with this program; if not, contact: *
14  * *
15  * Free Software Foundation Voice: +1-617-542-5942 *
16  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
17  * Boston, MA 02110-1301, USA [email protected] *
18  * *
19 \********************************************************************/
20 
21 /* pricecell-gnome.c
22  *
23  * Implements gnome dependent price cell functions :
24  *
25  * Often the decimal key in the keypad is not mapped to the correct locale
26  * decimal point, the function PriceDirect handle this case.
27  */
28 
29 #include "config.h"
30 
31 #include <locale.h>
32 #include <gdk/gdkkeysyms.h>
33 
34 #include "gnc-locale-utils.h"
35 #include "gnc-exp-parser.h"
36 #include "gnc-ui-util.h"
37 #include "pricecell.h"
38 #include "pricecell-gnome.h"
39 
40 #ifdef G_OS_WIN32
41 # include <gdk/gdkwin32.h>
42 #endif
43 
44 static gboolean
45 gnc_price_cell_direct_update (BasicCell *bcell,
46  int *cursor_position,
47  int *start_selection,
48  int *end_selection,
49  void *gui_data)
50 {
51  PriceCell *cell = (PriceCell *) bcell;
52  GdkEventKey *event = gui_data;
53  struct lconv *lc;
54  gboolean is_return;
55 
56  if (event->type != GDK_KEY_PRESS)
57  return FALSE;
58 
59  lc = gnc_localeconv ();
60 
61  is_return = FALSE;
62 
63 #ifdef G_OS_WIN32
64  /* gdk never sends GDK_KP_Decimal on win32. See #486658 */
65  if (event->hardware_keycode == VK_DECIMAL)
66  event->keyval = GDK_KP_Decimal;
67 #endif
68  switch (event->keyval)
69  {
70  case GDK_KEY_Return:
71  if (!(event->state &
72  (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SHIFT_MASK)))
73  is_return = TRUE;
74  /* fall through */
75 
76  case GDK_KEY_KP_Enter:
77  {
78  char *error_loc;
79  gnc_numeric amount;
80  gboolean parse_ok;
81  gboolean changed = FALSE;
82 
83  if (!cell->need_to_parse)
84  return FALSE;
85 
86  parse_ok = gnc_exp_parser_parse (cell->cell.value,
87  &amount, &error_loc);
88 
89  if (parse_ok)
90  changed = gnc_price_cell_set_value (cell, amount);
91  else if (!cell->cell.value || cell->cell.value[0] == '\0')
92  changed = gnc_price_cell_set_value (cell,
93  gnc_numeric_zero ());
94  else
95  *cursor_position = error_loc - cell->cell.value;
96 
97  /* If there is a problem with the parse, swallow
98  * the key so we stay put. */
99  if (!parse_ok)
100  return TRUE;
101 
102  /* If nothing has changed, let the key cause a
103  * cursor activation no matter what. */
104  if (!changed)
105  return FALSE;
106 
107  /* If it's not a plain return, stay put. This
108  * allows a 'calculator' style operation using
109  * keypad enter where you can keep entering more
110  * items to add, say. */
111  return !is_return;
112  }
113 
114  case GDK_KEY_KP_Decimal:
115  break;
116 
117  default:
118  return FALSE;
119  }
120 
121  /* This point is only reached when the KP_Decimal key is pressed. */
122  gnc_basic_cell_insert_decimal(bcell,
123  cell->print_info.monetary
124  ? lc->mon_decimal_point[0]
125  : lc->decimal_point[0],
126  cursor_position,
127  start_selection,
128  end_selection);
129 
130  cell->need_to_parse = TRUE;
131 
132  return TRUE;
133 }
134 
135 BasicCell *
136 gnc_price_cell_gnome_new (void)
137 {
138  BasicCell *cell;
139 
140  cell = gnc_price_cell_new ();
141 
142  cell->direct_update = gnc_price_cell_direct_update;
143 
144  return cell;
145 }
146 
147 void
148 gnc_basic_cell_insert_decimal(BasicCell *bcell,
149  char decimal_point,
150  int *cursor_position,
151  int *start_selection,
152  int *end_selection)
153 {
154  GString *newval_gs;
155  gint start, end;
156  gchar *buf;
157 
158  /* allocate space for newval_ptr : oldval + one letter ( the
159  decimal_point ) */
160  newval_gs = g_string_new("");
161 
162  start = MIN(*start_selection, *end_selection);
163  end = MAX(*start_selection, *end_selection);
164 
165  /* length in bytes, not chars. do not use g_utf8_strlen. */
166  buf = g_malloc0(strlen(bcell->value) + 1);
167  g_utf8_strncpy(buf, bcell->value, start);
168  g_string_append(newval_gs, buf);
169  g_free(buf);
170 
171  g_string_append_unichar(newval_gs, decimal_point);
172 
173  buf = g_utf8_offset_to_pointer(bcell->value, end);
174  g_string_append(newval_gs, buf);
175 
176  /* update the cursor position */
177  *cursor_position = start + 1;
178 
179  gnc_basic_cell_set_value_internal (bcell, newval_gs->str);
180 
181  g_string_free (newval_gs, TRUE);
182 }
183 
utility functions for the GnuCash UI