GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
combocell-gnome.c
1 /********************************************************************\
2  * combocell-gnome.c -- implement combobox pull down cell for gnome *
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: combocell-gnome.c
25  *
26  * FUNCTION: Implement gnome portion of a pull-down combo widget
27  * embedded in a table cell.
28  *
29  * HISTORY:
30  * Copyright (c) 1998 Linas Vepstas <[email protected]>
31  * Copyright (c) 1998-1999 Rob Browning <[email protected]>
32  * Copyright (c) 2000 Linas Vepstas <[email protected]>
33  * Copyright (c) 2006 David Hampton <[email protected]>
34  */
35 
36 #include "config.h"
37 
38 #include <string.h>
39 #include <gdk/gdkkeysyms.h>
40 
41 #include "QuickFill.h"
42 #include "combocell.h"
43 #include "gnc-prefs.h"
44 #include "gnucash-item-edit.h"
45 #include "gnucash-item-list.h"
46 #include "gnucash-sheet.h"
47 #include "gnucash-sheetP.h"
48 #include "table-allgui.h"
49 
50 #define GNC_PREF_AUTO_RAISE_LISTS "auto-raise-lists"
51 
52 typedef struct _PopBox
53 {
54  GnucashSheet *sheet;
55  GncItemEdit *item_edit;
56  GncItemList *item_list;
57  GtkListStore *tmp_store;
58 
59  gboolean signals_connected; /* list signals connected? */
60 
61  gboolean list_popped; /* list is popped up? */
62 
63  gboolean autosize;
64 
65  QuickFill *qf;
66  gboolean use_quickfill_cache; /* If TRUE, we don't own the qf */
67 
68  gboolean in_list_select;
69 
70  gboolean strict;
71 
72  gunichar complete_char; /* char to be used for auto-completion */
73 
74  GList *ignore_strings;
75 } PopBox;
76 
77 
78 static void gnc_combo_cell_gui_realize (BasicCell *bcell, gpointer w);
79 static void gnc_combo_cell_gui_move (BasicCell *bcell);
80 static void gnc_combo_cell_gui_destroy (BasicCell *bcell);
81 static gboolean gnc_combo_cell_enter (BasicCell *bcell,
82  int *cursor_position,
83  int *start_selection,
84  int *end_selection);
85 static void gnc_combo_cell_leave (BasicCell *bcell);
86 static void gnc_combo_cell_destroy (BasicCell *bcell);
87 
88 static GOnce auto_pop_init_once = G_ONCE_INIT;
89 static gboolean auto_pop_combos = FALSE;
90 
91 
92 static void
93 gnc_combo_cell_set_autopop (gpointer prefs, gchar *pref, gpointer user_data)
94 {
95  auto_pop_combos = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
96  GNC_PREF_AUTO_RAISE_LISTS);
97 }
98 
99 static gpointer
100 gnc_combo_cell_autopop_init (gpointer unused)
101 {
102  auto_pop_combos = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
103  GNC_PREF_AUTO_RAISE_LISTS);
104 
105  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL_REGISTER,
106  GNC_PREF_AUTO_RAISE_LISTS,
107  gnc_combo_cell_set_autopop,
108  NULL);
109  return NULL;
110 }
111 
112 BasicCell *
113 gnc_combo_cell_new (void)
114 {
115  ComboCell * cell;
116 
117  g_once(&auto_pop_init_once, gnc_combo_cell_autopop_init, NULL);
118 
119  cell = g_new0 (ComboCell, 1);
120 
121  gnc_combo_cell_init (cell);
122 
123  return &cell->cell;
124 }
125 
126 void
127 gnc_combo_cell_init (ComboCell *cell)
128 {
129  PopBox *box;
130 
131  gnc_basic_cell_init (&(cell->cell));
132 
133  cell->cell.is_popup = TRUE;
134 
135  cell->cell.destroy = gnc_combo_cell_destroy;
136 
137  cell->cell.gui_realize = gnc_combo_cell_gui_realize;
138  cell->cell.gui_destroy = gnc_combo_cell_gui_destroy;
139 
140  box = g_new0 (PopBox, 1);
141 
142  box->sheet = NULL;
143  box->item_edit = NULL;
144  box->item_list = NULL;
145  box->tmp_store = gtk_list_store_new (1, G_TYPE_STRING);
146  box->signals_connected = FALSE;
147  box->list_popped = FALSE;
148  box->autosize = FALSE;
149 
150  cell->cell.gui_private = box;
151 
152  box->qf = gnc_quickfill_new ();
153  box->use_quickfill_cache = FALSE;
154 
155  box->in_list_select = FALSE;
156 
157  box->strict = TRUE;
158 
159  box->complete_char = '\0';
160 
161  box->ignore_strings = NULL;
162 }
163 
164 static void
165 select_item_cb (GncItemList *item_list, char *item_string, gpointer data)
166 {
167  ComboCell *cell = data;
168  PopBox *box = cell->cell.gui_private;
169 
170  box->in_list_select = TRUE;
171  gnucash_sheet_modify_current_cell (box->sheet, item_string);
172  box->in_list_select = FALSE;
173 
174  gnc_item_edit_hide_popup (box->item_edit);
175  box->list_popped = FALSE;
176 }
177 
178 static void
179 change_item_cb (GncItemList *item_list, char *item_string, gpointer data)
180 {
181  ComboCell *cell = data;
182  PopBox *box = cell->cell.gui_private;
183 
184  box->in_list_select = TRUE;
185  gnucash_sheet_modify_current_cell (box->sheet, item_string);
186  box->in_list_select = FALSE;
187 }
188 
189 static void
190 activate_item_cb (GncItemList *item_list, char *item_string, gpointer data)
191 {
192  ComboCell *cell = data;
193  PopBox *box = cell->cell.gui_private;
194 
195  gnc_item_edit_hide_popup (box->item_edit);
196  box->list_popped = FALSE;
197 }
198 
199 static void
200 key_press_item_cb (GncItemList *item_list, GdkEventKey *event, gpointer data)
201 {
202  ComboCell *cell = data;
203  PopBox *box = cell->cell.gui_private;
204 
205  switch (event->keyval)
206  {
207  case GDK_KEY_Escape:
208  gnc_item_edit_hide_popup (box->item_edit);
209  box->list_popped = FALSE;
210  break;
211 
212  default:
213  gtk_widget_event (GTK_WIDGET(box->sheet),
214  (GdkEvent *) event);
215  break;
216  }
217 }
218 
219 static void
220 combo_disconnect_signals (ComboCell *cell)
221 {
222  PopBox *box = cell->cell.gui_private;
223 
224  if (!box->signals_connected)
225  return;
226 
227  g_signal_handlers_disconnect_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA,
228  0, 0, NULL, NULL, cell);
229 
230  box->signals_connected = FALSE;
231 }
232 
233 static void
234 combo_connect_signals (ComboCell *cell)
235 {
236  PopBox *box = cell->cell.gui_private;
237 
238  if (box->signals_connected)
239  return;
240 
241  g_signal_connect (G_OBJECT (box->item_list), "select_item",
242  G_CALLBACK (select_item_cb), cell);
243 
244  g_signal_connect (G_OBJECT (box->item_list), "change_item",
245  G_CALLBACK (change_item_cb), cell);
246 
247  g_signal_connect (G_OBJECT (box->item_list), "activate_item",
248  G_CALLBACK (activate_item_cb), cell);
249 
250  g_signal_connect (G_OBJECT (box->item_list), "key_press_event",
251  G_CALLBACK (key_press_item_cb), cell);
252 
253  box->signals_connected = TRUE;
254 }
255 
256 static void
257 block_list_signals (ComboCell *cell)
258 {
259  PopBox *box = cell->cell.gui_private;
260 
261  if (!box->signals_connected)
262  return;
263 
264  g_signal_handlers_block_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA,
265  0, 0, NULL, NULL, cell);
266 }
267 
268 static void
269 unblock_list_signals (ComboCell *cell)
270 {
271  PopBox *box = cell->cell.gui_private;
272 
273  if (!box->signals_connected)
274  return;
275 
276  g_signal_handlers_unblock_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA,
277  0, 0, NULL, NULL, cell);
278 }
279 
280 static void
281 gnc_combo_cell_gui_destroy (BasicCell *bcell)
282 {
283  PopBox *box = bcell->gui_private;
284  ComboCell *cell = (ComboCell *) bcell;
285 
286  if (cell->cell.gui_realize == NULL)
287  {
288  if (box != NULL && box->item_list != NULL)
289  {
290  combo_disconnect_signals(cell);
291  g_object_unref (box->item_list);
292  box->item_list = NULL;
293  }
294 
295  /* allow the widget to be shown again */
296  cell->cell.gui_realize = gnc_combo_cell_gui_realize;
297  cell->cell.gui_move = NULL;
298  cell->cell.enter_cell = NULL;
299  cell->cell.leave_cell = NULL;
300  cell->cell.gui_destroy = NULL;
301  }
302 }
303 
304 static void
305 gnc_combo_cell_destroy (BasicCell *bcell)
306 {
307  ComboCell *cell = (ComboCell *) bcell;
308  PopBox *box = cell->cell.gui_private;
309 
310  gnc_combo_cell_gui_destroy (&(cell->cell));
311 
312  if (box != NULL)
313  {
314  GList *node;
315 
316  /* Don't destroy the qf if its not ours to destroy */
317  if (FALSE == box->use_quickfill_cache)
318  {
319  gnc_quickfill_destroy (box->qf);
320  box->qf = NULL;
321  }
322 
323  for (node = box->ignore_strings; node; node = node->next)
324  {
325  g_free (node->data);
326  node->data = NULL;
327  }
328 
329  g_list_free (box->ignore_strings);
330  box->ignore_strings = NULL;
331 
332  g_free (box);
333  cell->cell.gui_private = NULL;
334  }
335 
336  cell->cell.gui_private = NULL;
337  cell->cell.gui_realize = NULL;
338 }
339 
340 void
342 {
343  PopBox *box;
344 
345  if (cell == NULL)
346  return;
347 
348  box = cell->cell.gui_private;
349  if (box->item_list == NULL)
350  return;
351 
352  block_list_signals (cell);
353  gnc_item_list_set_sort_enabled(box->item_list, enabled);
354  unblock_list_signals (cell);
355 }
356 
357 void
358 gnc_combo_cell_clear_menu (ComboCell * cell)
359 {
360  PopBox *box;
361 
362  if (cell == NULL)
363  return;
364 
365  box = cell->cell.gui_private;
366  if (box == NULL)
367  return;
368 
369  /* Don't destroy the qf if its not ours to destroy */
370  if (FALSE == box->use_quickfill_cache)
371  {
372  gnc_quickfill_destroy (box->qf);
373  box->qf = gnc_quickfill_new ();
374  }
375 
376  if (box->item_list != NULL)
377  {
378  block_list_signals (cell);
379 
380  gnc_item_list_clear (box->item_list);
381 
382  unblock_list_signals (cell);
383  }
384 }
385 
386 void
388 {
389  PopBox *box;
390 
391  if (cell == NULL) return;
392 
393  box = cell->cell.gui_private;
394  if (NULL == box) return;
395 
396  if (FALSE == box->use_quickfill_cache)
397  {
398  box->use_quickfill_cache = TRUE;
399  gnc_quickfill_destroy (box->qf);
400  }
401  box->qf = shared_qf;
402 }
403 
404 void
405 gnc_combo_cell_use_list_store_cache (ComboCell * cell, gpointer data)
406 {
407  if (cell == NULL) return;
408 
409  cell->shared_store = data;
410 }
411 
412 void
413 gnc_combo_cell_add_menu_item (ComboCell *cell, const char * menustr)
414 {
415  PopBox *box;
416 
417  if (cell == NULL)
418  return;
419  if (menustr == NULL)
420  return;
421 
422  box = cell->cell.gui_private;
423 
424  if (box->item_list != NULL)
425  {
426  block_list_signals (cell);
427 
428  gnc_item_list_append (box->item_list, menustr);
429  if (cell->cell.value &&
430  (strcmp (menustr, cell->cell.value) == 0))
431  gnc_item_list_select (box->item_list, menustr);
432 
433  unblock_list_signals (cell);
434  }
435  else
436  {
437  GtkTreeIter iter;
438 
439  gtk_list_store_append(box->tmp_store, &iter);
440  gtk_list_store_set(box->tmp_store, &iter, 0, menustr, -1);
441  }
442 
443  /* If we're going to be using a pre-fab quickfill,
444  * then don't fill it in here */
445  if (FALSE == box->use_quickfill_cache)
446  {
447  gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA);
448  }
449 }
450 
451 void
453 {
454  PopBox *box;
455  gchar *menu_copy, *value_copy;
456 
457  if (cell == NULL)
458  return;
459  if (menustr == NULL)
460  return;
461 
462  box = cell->cell.gui_private;
463 
464  if (box->item_list != NULL)
465  {
466  block_list_signals (cell);
467 
468  gnc_item_list_append (box->item_list, menustr);
469  if (cell->cell.value)
470  {
471  menu_copy = g_strdelimit(g_strdup(menustr), "-:/\\.", ' ');
472  value_copy =
473  g_strdelimit(g_strdup(cell->cell.value), "-:/\\.", ' ');
474  if (strcmp (menu_copy, value_copy) == 0)
475  {
476  gnc_combo_cell_set_value (cell, menustr);
477  gnc_item_list_select (box->item_list, menustr);
478  }
479  g_free(value_copy);
480  g_free(menu_copy);
481  }
482  unblock_list_signals (cell);
483  }
484 
485  /* If we're going to be using a pre-fab quickfill,
486  * then don't fill it in here */
487  if (FALSE == box->use_quickfill_cache)
488  {
489  gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA);
490  }
491 }
492 
493 void
494 gnc_combo_cell_set_value (ComboCell *cell, const char *str)
495 {
496  gnc_basic_cell_set_value (&cell->cell, str);
497 }
498 
499 static void
500 gnc_combo_cell_modify_verify (BasicCell *_cell,
501  const char *change,
502  int change_len,
503  const char *newval,
504  int newval_len,
505  int *cursor_position,
506  int *start_selection,
507  int *end_selection)
508 {
509  ComboCell *cell = (ComboCell *) _cell;
510  PopBox *box = cell->cell.gui_private;
511  const char *match_str;
512  QuickFill *match;
513  gboolean pop_list;
514  glong newval_chars;
515  glong change_chars;
516 
517  newval_chars = g_utf8_strlen (newval, newval_len);
518  change_chars = g_utf8_strlen (change, change_len);
519 
520  if (box->in_list_select)
521  {
522  gnc_basic_cell_set_value_internal (_cell, newval);
523 
524  *cursor_position = -1;
525  *start_selection = 0;
526  *end_selection = -1;
527 
528  return;
529  }
530 
531  /* If deleting, just accept */
532  if (change == NULL)
533  {
534  gnc_basic_cell_set_value_internal (_cell, newval);
535  return;
536  }
537 
538  /* If we are inserting in the middle, just accept */
539  if (*cursor_position < _cell->value_chars)
540  {
541  gnc_basic_cell_set_value_internal (_cell, newval);
542  return;
543  }
544 
545  match = gnc_quickfill_get_string_match (box->qf, newval);
546 
547  match_str = gnc_quickfill_string (match);
548 
549  if ((match == NULL) || (match_str == NULL))
550  {
551  gnc_basic_cell_set_value_internal (_cell, newval);
552 
553  block_list_signals (cell);
554  gnc_item_list_select (box->item_list, NULL);
555  unblock_list_signals (cell);
556 
557  return;
558  }
559 
560  *start_selection = newval_chars;
561  *end_selection = -1;
562  *cursor_position += change_chars;
563 
564  if (!box->list_popped)
565  pop_list = auto_pop_combos;
566  else
567  pop_list = FALSE;
568 
569  if (pop_list)
570  {
571  gnc_item_edit_show_popup (box->item_edit);
572  box->list_popped = TRUE;
573  }
574 
575  block_list_signals (cell);
576  gnc_item_list_select (box->item_list, match_str);
577  unblock_list_signals (cell);
578 
579  gnc_basic_cell_set_value_internal (_cell, match_str);
580 }
581 
582 static gboolean
583 gnc_combo_cell_direct_update (BasicCell *bcell,
584  int *cursor_position,
585  int *start_selection,
586  int *end_selection,
587  void *gui_data)
588 {
589  ComboCell *cell = (ComboCell *) bcell;
590  PopBox *box = cell->cell.gui_private;
591  GdkEventKey *event = gui_data;
592  gboolean keep_on_going = FALSE;
593  gboolean extra_colon;
594  gunichar unicode_value;
595  QuickFill *match;
596  const char *match_str;
597  int prefix_len;
598  int find_pos;
599  int new_pos;
600 
601  if (event->type != GDK_KEY_PRESS)
602  return FALSE;
603 
604  unicode_value = gdk_keyval_to_unicode(event->keyval);
605  switch (event->keyval)
606  {
607  case GDK_KEY_slash:
608  if (!(event->state & GDK_MOD1_MASK))
609  {
610  if (unicode_value == box->complete_char)
611  break;
612 
613  return FALSE;
614  }
615  keep_on_going = TRUE;
616  /* fall through */
617  case GDK_KEY_Tab:
618  case GDK_KEY_ISO_Left_Tab:
619  if (!(event->state & GDK_CONTROL_MASK) &&
620  !keep_on_going)
621  return FALSE;
622 
624  (box->qf, bcell->value, *cursor_position);
625  if (match == NULL)
626  return TRUE;
627 
629  (match, &prefix_len);
630  if (match == NULL)
631  return TRUE;
632 
633  match_str = gnc_quickfill_string (match);
634 
635  if ((match_str != NULL) &&
636  (strncmp (match_str, bcell->value,
637  strlen (bcell->value)) == 0) &&
638  (strcmp (match_str, bcell->value) != 0))
639  {
640  gnc_basic_cell_set_value_internal (bcell,
641  match_str);
642 
643  block_list_signals (cell);
644  gnc_item_list_select (box->item_list,
645  match_str);
646  unblock_list_signals (cell);
647  }
648 
649  *cursor_position += prefix_len;
650  *start_selection = *cursor_position;
651  *end_selection = -1;
652 
653  return TRUE;
654  }
655 
656  if (box->complete_char == 0)
657  return FALSE;
658 
659  if (unicode_value != box->complete_char)
660  return FALSE;
661 
662  if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
663  return FALSE;
664 
665  if ((*cursor_position < bcell->value_chars) &&
666  ((*end_selection < bcell->value_chars) ||
667  (*cursor_position < *start_selection)))
668  return FALSE;
669 
670  if ((*cursor_position == bcell->value_chars) &&
671  (*start_selection != *end_selection) &&
672  (*end_selection < bcell->value_chars))
673  return FALSE;
674 
675  find_pos = -1;
676  if (*start_selection < bcell->value_chars)
677  {
678  int i = *start_selection;
679  const char *c;
680  gunichar uc;
681 
682  c = g_utf8_offset_to_pointer (bcell->value, i);
683  while (*c)
684  {
685  uc = g_utf8_get_char (c);
686  if (uc == box->complete_char)
687  {
688  find_pos = (i + 1);
689  break;
690  }
691  c = g_utf8_next_char (c);
692  i++;
693  }
694  }
695 
696  new_pos = *cursor_position;
697 
698  if (find_pos >= 0)
699  {
700  new_pos = find_pos;
701  extra_colon = FALSE;
702  }
703  else
704  {
705  new_pos = bcell->value_chars;
706  extra_colon = TRUE;
707  }
708 
709  match = gnc_quickfill_get_string_len_match (box->qf,
710  bcell->value, new_pos);
711  if (match == NULL)
712  return FALSE;
713 
714  if (extra_colon)
715  {
716  match = gnc_quickfill_get_char_match (match,
717  box->complete_char);
718  if (match == NULL)
719  return FALSE;
720 
721  new_pos++;
722  }
723 
724  match_str = gnc_quickfill_string (match);
725 
726  if ((match_str != NULL) &&
727  (strncmp (match_str, bcell->value, strlen (bcell->value)) == 0) &&
728  (strcmp (match_str, bcell->value) != 0))
729  {
730  gnc_basic_cell_set_value_internal (bcell, match_str);
731 
732  block_list_signals (cell);
733  gnc_item_list_select (box->item_list, match_str);
734  unblock_list_signals (cell);
735  }
736 
737  *cursor_position = new_pos;
738  *start_selection = new_pos;
739  *end_selection = -1;
740 
741  return TRUE;
742 }
743 
744 static void
745 gnc_combo_cell_gui_realize (BasicCell *bcell, gpointer data)
746 {
747  GnucashSheet *sheet = data;
748  GncItemEdit *item_edit = gnucash_sheet_get_item_edit (sheet);
749  ComboCell *cell = (ComboCell *) bcell;
750  PopBox *box = cell->cell.gui_private;
751 
752  /* initialize gui-specific, private data */
753  box->sheet = sheet;
754  box->item_edit = item_edit;
755  if (cell->shared_store)
756  box->item_list = gnc_item_edit_new_list(box->item_edit, cell->shared_store);
757  else
758  box->item_list = gnc_item_edit_new_list(box->item_edit, box->tmp_store);
759  g_object_ref_sink(box->item_list);
760 
761  /* to mark cell as realized, remove the realize method */
762  cell->cell.gui_realize = NULL;
763  cell->cell.gui_move = gnc_combo_cell_gui_move;
764  cell->cell.enter_cell = gnc_combo_cell_enter;
765  cell->cell.leave_cell = gnc_combo_cell_leave;
766  cell->cell.gui_destroy = gnc_combo_cell_gui_destroy;
767  cell->cell.modify_verify = gnc_combo_cell_modify_verify;
768  cell->cell.direct_update = gnc_combo_cell_direct_update;
769 }
770 
771 static void
772 gnc_combo_cell_gui_move (BasicCell *bcell)
773 {
774  PopBox *box = bcell->gui_private;
775 
776  combo_disconnect_signals ((ComboCell *) bcell);
777 
778  gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
779  NULL, NULL, NULL, NULL, NULL);
780 
781  box->list_popped = FALSE;
782 }
783 
784 static int
785 get_popup_height (GnomeCanvasItem *item,
786  int space_available,
787  int row_height,
788  gpointer user_data)
789 {
790  PopBox *box = user_data;
791  int count, pad = 4;
792 
793  count = gnc_item_list_num_entries(box->item_list);
794  return MIN(space_available, (count * (row_height + pad)) + pad);
795 }
796 
797 static int
798 popup_autosize (GnomeCanvasItem *item,
799  int max_width,
800  gpointer user_data)
801 {
802  PopBox *box = user_data;
803 
804  if (!box || !box->autosize)
805  return max_width;
806 
807  return gnc_item_list_autosize (GNC_ITEM_LIST (item)) + 20;
808 }
809 
810 static void
811 popup_set_focus (GnomeCanvasItem *item,
812  gpointer user_data)
813 {
814  gtk_widget_grab_focus (GTK_WIDGET (GNC_ITEM_LIST (item)->tree_view));
815 }
816 
817 static void
818 popup_post_show (GnomeCanvasItem *item,
819  gpointer user_data)
820 {
821  /* What the hell is this doing here? Well, under gtk+ 1.2.9,
822  * the scrollbars never appear without it. Why does it work?
823  * Why are you asking so many questions? There's nothing to
824  * see here. These aren't the droids you're looking for.
825  * Move along. */
826  gtk_widget_size_request (GNC_ITEM_LIST (item)->frame, NULL);
827 
828  gnc_item_list_autosize (GNC_ITEM_LIST (item));
829  gnc_item_list_show_selected (GNC_ITEM_LIST (item));
830 }
831 
832 static int
833 popup_get_width (GnomeCanvasItem *item,
834  gpointer user_data)
835 {
836  return GTK_WIDGET (GNC_ITEM_LIST (item)->tree_view)->allocation.width;
837 }
838 
839 static gboolean
840 gnc_combo_cell_enter (BasicCell *bcell,
841  int *cursor_position,
842  int *start_selection,
843  int *end_selection)
844 {
845  ComboCell *cell = (ComboCell *) bcell;
846  PopBox *box = bcell->gui_private;
847  GList *find = NULL;
848 
849  if (bcell->value)
850  find = g_list_find_custom (box->ignore_strings,
851  bcell->value,
852  (GCompareFunc) strcmp);
853  if (find)
854  return FALSE;
855 
856  gnc_item_edit_set_popup (box->item_edit,
857  GNOME_CANVAS_ITEM (box->item_list),
858  get_popup_height, popup_autosize,
859  popup_set_focus, popup_post_show,
860  popup_get_width, box);
861 
862  block_list_signals (cell);
863  gnc_item_list_select (box->item_list, bcell->value);
864  unblock_list_signals (cell);
865 
866  combo_connect_signals (cell);
867 
868  *cursor_position = -1;
869  *start_selection = 0;
870  *end_selection = -1;
871 
872  return TRUE;
873 }
874 
875 static void
876 gnc_combo_cell_leave (BasicCell *bcell)
877 {
878  PopBox *box = bcell->gui_private;
879 
880  combo_disconnect_signals ((ComboCell *) bcell);
881 
882  gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
883  NULL, NULL, NULL, NULL, NULL);
884 
885  box->list_popped = FALSE;
886 
887  if (box->strict)
888  {
889  if (bcell->value)
890  {
891  if (gnc_item_in_list (box->item_list, bcell->value))
892  return;
893 
894  if (g_list_find_custom (box->ignore_strings,
895  bcell->value,
896  (GCompareFunc) strcmp))
897  return;
898  }
899  gnc_basic_cell_set_value_internal (bcell, "");
900  }
901 }
902 
903 void
904 gnc_combo_cell_set_strict (ComboCell *cell, gboolean strict)
905 {
906  PopBox *box;
907 
908  if (cell == NULL)
909  return;
910 
911  box = cell->cell.gui_private;
912 
913  box->strict = strict;
914 }
915 
916 void
917 gnc_combo_cell_set_complete_char (ComboCell *cell, gunichar complete_char)
918 {
919  PopBox *box;
920 
921  if (cell == NULL)
922  return;
923 
924  box = cell->cell.gui_private;
925 
926  box->complete_char = complete_char;
927 }
928 
929 void
931  const char *ignore_string)
932 {
933  PopBox *box;
934 
935  if (cell == NULL)
936  return;
937 
938  if (!ignore_string)
939  return;
940 
941  box = cell->cell.gui_private;
942 
943  box->ignore_strings = g_list_prepend (box->ignore_strings,
944  g_strdup (ignore_string));
945 }
946 
947 void
948 gnc_combo_cell_set_autosize (ComboCell *cell, gboolean autosize)
949 {
950  PopBox *box;
951 
952  if (!cell)
953  return;
954 
955  box = cell->cell.gui_private;
956  if (!box)
957  return;
958 
959  box->autosize = autosize;
960 }
961 
void gnc_quickfill_insert(QuickFill *qf, const char *text, QuickFillSort sort)
Definition: QuickFill.c:229
QuickFill * gnc_quickfill_get_char_match(QuickFill *qf, gunichar uc)
Definition: QuickFill.c:135
void gnc_combo_cell_set_autosize(ComboCell *cell, gboolean autosize)
void gnc_combo_cell_set_sort_enabled(ComboCell *cell, gboolean enabled)
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:128
void gnc_combo_cell_add_account_menu_item(ComboCell *cell, char *menustr)
void gnc_combo_cell_use_quickfill_cache(ComboCell *cell, QuickFill *shared_qf)
QuickFill * gnc_quickfill_get_string_len_match(QuickFill *qf, const char *str, int len)
Definition: QuickFill.c:150
void gnc_combo_cell_set_complete_char(ComboCell *cell, gunichar complete_char)
void gnc_combo_cell_add_menu_item(ComboCell *cell, const char *menustr)
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it...
QuickFill * gnc_quickfill_get_string_match(QuickFill *qf, const char *str)
Definition: QuickFill.c:179
void gnc_combo_cell_add_ignore_string(ComboCell *cell, const char *ignore_string)
Generic api to store and retrieve preferences.
void gnc_combo_cell_set_strict(ComboCell *cell, gboolean strict)
const char * gnc_quickfill_string(QuickFill *qf)
Definition: QuickFill.c:123
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
Declarations for the Table object.
QuickFill is used to auto-complete typed user entries.
QuickFill * gnc_quickfill_get_unique_len_match(QuickFill *qf, int *length)
Definition: QuickFill.c:199