39 #include <gdk/gdkkeysyms.h>
44 #include "gnucash-item-edit.h"
45 #include "gnucash-item-list.h"
46 #include "gnucash-sheet.h"
47 #include "gnucash-sheetP.h"
50 #define GNC_PREF_AUTO_RAISE_LISTS "auto-raise-lists"
57 GtkListStore *tmp_store;
59 gboolean signals_connected;
66 gboolean use_quickfill_cache;
68 gboolean in_list_select;
72 gunichar complete_char;
74 GList *ignore_strings;
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,
85 static void gnc_combo_cell_leave (
BasicCell *bcell);
86 static void gnc_combo_cell_destroy (
BasicCell *bcell);
88 static GOnce auto_pop_init_once = G_ONCE_INIT;
89 static gboolean auto_pop_combos = FALSE;
93 gnc_combo_cell_set_autopop (gpointer prefs, gchar *pref, gpointer user_data)
96 GNC_PREF_AUTO_RAISE_LISTS);
100 gnc_combo_cell_autopop_init (gpointer unused)
103 GNC_PREF_AUTO_RAISE_LISTS);
106 GNC_PREF_AUTO_RAISE_LISTS,
107 gnc_combo_cell_set_autopop,
113 gnc_combo_cell_new (
void)
117 g_once(&auto_pop_init_once, gnc_combo_cell_autopop_init, NULL);
121 gnc_combo_cell_init (cell);
131 gnc_basic_cell_init (&(cell->cell));
133 cell->cell.is_popup = TRUE;
135 cell->cell.destroy = gnc_combo_cell_destroy;
137 cell->cell.gui_realize = gnc_combo_cell_gui_realize;
138 cell->cell.gui_destroy = gnc_combo_cell_gui_destroy;
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;
150 cell->cell.gui_private = box;
152 box->qf = gnc_quickfill_new ();
153 box->use_quickfill_cache = FALSE;
155 box->in_list_select = FALSE;
159 box->complete_char =
'\0';
161 box->ignore_strings = NULL;
165 select_item_cb (
GncItemList *item_list,
char *item_string, gpointer data)
168 PopBox *box = cell->cell.gui_private;
170 box->in_list_select = TRUE;
171 gnucash_sheet_modify_current_cell (box->sheet, item_string);
172 box->in_list_select = FALSE;
174 gnc_item_edit_hide_popup (box->item_edit);
175 box->list_popped = FALSE;
179 change_item_cb (
GncItemList *item_list,
char *item_string, gpointer data)
182 PopBox *box = cell->cell.gui_private;
184 box->in_list_select = TRUE;
185 gnucash_sheet_modify_current_cell (box->sheet, item_string);
186 box->in_list_select = FALSE;
190 activate_item_cb (
GncItemList *item_list,
char *item_string, gpointer data)
193 PopBox *box = cell->cell.gui_private;
195 gnc_item_edit_hide_popup (box->item_edit);
196 box->list_popped = FALSE;
200 key_press_item_cb (
GncItemList *item_list, GdkEventKey *event, gpointer data)
203 PopBox *box = cell->cell.gui_private;
205 switch (event->keyval)
208 gnc_item_edit_hide_popup (box->item_edit);
209 box->list_popped = FALSE;
213 gtk_widget_event (GTK_WIDGET(box->sheet),
220 combo_disconnect_signals (
ComboCell *cell)
222 PopBox *box = cell->cell.gui_private;
224 if (!box->signals_connected)
227 g_signal_handlers_disconnect_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA,
228 0, 0, NULL, NULL, cell);
230 box->signals_connected = FALSE;
236 PopBox *box = cell->cell.gui_private;
238 if (box->signals_connected)
241 g_signal_connect (G_OBJECT (box->item_list),
"select_item",
242 G_CALLBACK (select_item_cb), cell);
244 g_signal_connect (G_OBJECT (box->item_list),
"change_item",
245 G_CALLBACK (change_item_cb), cell);
247 g_signal_connect (G_OBJECT (box->item_list),
"activate_item",
248 G_CALLBACK (activate_item_cb), cell);
250 g_signal_connect (G_OBJECT (box->item_list),
"key_press_event",
251 G_CALLBACK (key_press_item_cb), cell);
253 box->signals_connected = TRUE;
259 PopBox *box = cell->cell.gui_private;
261 if (!box->signals_connected)
264 g_signal_handlers_block_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA,
265 0, 0, NULL, NULL, cell);
271 PopBox *box = cell->cell.gui_private;
273 if (!box->signals_connected)
276 g_signal_handlers_unblock_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA,
277 0, 0, NULL, NULL, cell);
281 gnc_combo_cell_gui_destroy (
BasicCell *bcell)
283 PopBox *box = bcell->gui_private;
286 if (cell->cell.gui_realize == NULL)
288 if (box != NULL && box->item_list != NULL)
290 combo_disconnect_signals(cell);
291 g_object_unref (box->item_list);
292 box->item_list = NULL;
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;
305 gnc_combo_cell_destroy (
BasicCell *bcell)
308 PopBox *box = cell->cell.gui_private;
310 gnc_combo_cell_gui_destroy (&(cell->cell));
317 if (FALSE == box->use_quickfill_cache)
319 gnc_quickfill_destroy (box->qf);
323 for (node = box->ignore_strings; node; node = node->next)
329 g_list_free (box->ignore_strings);
330 box->ignore_strings = NULL;
333 cell->cell.gui_private = NULL;
336 cell->cell.gui_private = NULL;
337 cell->cell.gui_realize = NULL;
348 box = cell->cell.gui_private;
349 if (box->item_list == NULL)
352 block_list_signals (cell);
353 gnc_item_list_set_sort_enabled(box->item_list, enabled);
354 unblock_list_signals (cell);
358 gnc_combo_cell_clear_menu (
ComboCell * cell)
365 box = cell->cell.gui_private;
370 if (FALSE == box->use_quickfill_cache)
372 gnc_quickfill_destroy (box->qf);
373 box->qf = gnc_quickfill_new ();
376 if (box->item_list != NULL)
378 block_list_signals (cell);
380 gnc_item_list_clear (box->item_list);
382 unblock_list_signals (cell);
391 if (cell == NULL)
return;
393 box = cell->cell.gui_private;
394 if (NULL == box)
return;
396 if (FALSE == box->use_quickfill_cache)
398 box->use_quickfill_cache = TRUE;
399 gnc_quickfill_destroy (box->qf);
405 gnc_combo_cell_use_list_store_cache (
ComboCell * cell, gpointer data)
407 if (cell == NULL)
return;
409 cell->shared_store = data;
422 box = cell->cell.gui_private;
424 if (box->item_list != NULL)
426 block_list_signals (cell);
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);
433 unblock_list_signals (cell);
439 gtk_list_store_append(box->tmp_store, &iter);
440 gtk_list_store_set(box->tmp_store, &iter, 0, menustr, -1);
445 if (FALSE == box->use_quickfill_cache)
455 gchar *menu_copy, *value_copy;
462 box = cell->cell.gui_private;
464 if (box->item_list != NULL)
466 block_list_signals (cell);
468 gnc_item_list_append (box->item_list, menustr);
469 if (cell->cell.value)
471 menu_copy = g_strdelimit(g_strdup(menustr),
"-:/\\.",
' ');
473 g_strdelimit(g_strdup(cell->cell.value),
"-:/\\.",
' ');
474 if (strcmp (menu_copy, value_copy) == 0)
476 gnc_combo_cell_set_value (cell, menustr);
477 gnc_item_list_select (box->item_list, menustr);
482 unblock_list_signals (cell);
487 if (FALSE == box->use_quickfill_cache)
494 gnc_combo_cell_set_value (
ComboCell *cell,
const char *str)
496 gnc_basic_cell_set_value (&cell->cell, str);
500 gnc_combo_cell_modify_verify (
BasicCell *_cell,
505 int *cursor_position,
506 int *start_selection,
510 PopBox *box = cell->cell.gui_private;
511 const char *match_str;
517 newval_chars = g_utf8_strlen (newval, newval_len);
518 change_chars = g_utf8_strlen (change, change_len);
520 if (box->in_list_select)
522 gnc_basic_cell_set_value_internal (_cell, newval);
524 *cursor_position = -1;
525 *start_selection = 0;
534 gnc_basic_cell_set_value_internal (_cell, newval);
539 if (*cursor_position < _cell->value_chars)
541 gnc_basic_cell_set_value_internal (_cell, newval);
549 if ((match == NULL) || (match_str == NULL))
551 gnc_basic_cell_set_value_internal (_cell, newval);
553 block_list_signals (cell);
554 gnc_item_list_select (box->item_list, NULL);
555 unblock_list_signals (cell);
560 *start_selection = newval_chars;
562 *cursor_position += change_chars;
564 if (!box->list_popped)
565 pop_list = auto_pop_combos;
571 gnc_item_edit_show_popup (box->item_edit);
572 box->list_popped = TRUE;
575 block_list_signals (cell);
576 gnc_item_list_select (box->item_list, match_str);
577 unblock_list_signals (cell);
579 gnc_basic_cell_set_value_internal (_cell, match_str);
583 gnc_combo_cell_direct_update (
BasicCell *bcell,
584 int *cursor_position,
585 int *start_selection,
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;
596 const char *match_str;
601 if (event->type != GDK_KEY_PRESS)
604 unicode_value = gdk_keyval_to_unicode(event->keyval);
605 switch (event->keyval)
608 if (!(event->state & GDK_MOD1_MASK))
610 if (unicode_value == box->complete_char)
615 keep_on_going = TRUE;
618 case GDK_KEY_ISO_Left_Tab:
619 if (!(event->state & GDK_CONTROL_MASK) &&
624 (box->qf, bcell->value, *cursor_position);
629 (match, &prefix_len);
635 if ((match_str != NULL) &&
636 (strncmp (match_str, bcell->value,
637 strlen (bcell->value)) == 0) &&
638 (strcmp (match_str, bcell->value) != 0))
640 gnc_basic_cell_set_value_internal (bcell,
643 block_list_signals (cell);
644 gnc_item_list_select (box->item_list,
646 unblock_list_signals (cell);
649 *cursor_position += prefix_len;
650 *start_selection = *cursor_position;
656 if (box->complete_char == 0)
659 if (unicode_value != box->complete_char)
662 if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
665 if ((*cursor_position < bcell->value_chars) &&
666 ((*end_selection < bcell->value_chars) ||
667 (*cursor_position < *start_selection)))
670 if ((*cursor_position == bcell->value_chars) &&
671 (*start_selection != *end_selection) &&
672 (*end_selection < bcell->value_chars))
676 if (*start_selection < bcell->value_chars)
678 int i = *start_selection;
682 c = g_utf8_offset_to_pointer (bcell->value, i);
685 uc = g_utf8_get_char (c);
686 if (uc == box->complete_char)
691 c = g_utf8_next_char (c);
696 new_pos = *cursor_position;
705 new_pos = bcell->value_chars;
710 bcell->value, new_pos);
726 if ((match_str != NULL) &&
727 (strncmp (match_str, bcell->value, strlen (bcell->value)) == 0) &&
728 (strcmp (match_str, bcell->value) != 0))
730 gnc_basic_cell_set_value_internal (bcell, match_str);
732 block_list_signals (cell);
733 gnc_item_list_select (box->item_list, match_str);
734 unblock_list_signals (cell);
737 *cursor_position = new_pos;
738 *start_selection = new_pos;
745 gnc_combo_cell_gui_realize (
BasicCell *bcell, gpointer data)
748 GncItemEdit *item_edit = gnucash_sheet_get_item_edit (sheet);
750 PopBox *box = cell->cell.gui_private;
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);
758 box->item_list = gnc_item_edit_new_list(box->item_edit, box->tmp_store);
759 g_object_ref_sink(box->item_list);
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;
772 gnc_combo_cell_gui_move (
BasicCell *bcell)
774 PopBox *box = bcell->gui_private;
776 combo_disconnect_signals ((
ComboCell *) bcell);
778 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
779 NULL, NULL, NULL, NULL, NULL);
781 box->list_popped = FALSE;
785 get_popup_height (GnomeCanvasItem *item,
793 count = gnc_item_list_num_entries(box->item_list);
794 return MIN(space_available, (count * (row_height + pad)) + pad);
798 popup_autosize (GnomeCanvasItem *item,
804 if (!box || !box->autosize)
807 return gnc_item_list_autosize (GNC_ITEM_LIST (item)) + 20;
811 popup_set_focus (GnomeCanvasItem *item,
814 gtk_widget_grab_focus (GTK_WIDGET (GNC_ITEM_LIST (item)->tree_view));
818 popup_post_show (GnomeCanvasItem *item,
826 gtk_widget_size_request (GNC_ITEM_LIST (item)->frame, NULL);
828 gnc_item_list_autosize (GNC_ITEM_LIST (item));
829 gnc_item_list_show_selected (GNC_ITEM_LIST (item));
833 popup_get_width (GnomeCanvasItem *item,
836 return GTK_WIDGET (GNC_ITEM_LIST (item)->tree_view)->allocation.width;
841 int *cursor_position,
842 int *start_selection,
846 PopBox *box = bcell->gui_private;
850 find = g_list_find_custom (box->ignore_strings,
852 (GCompareFunc) strcmp);
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);
862 block_list_signals (cell);
863 gnc_item_list_select (box->item_list, bcell->value);
864 unblock_list_signals (cell);
866 combo_connect_signals (cell);
868 *cursor_position = -1;
869 *start_selection = 0;
878 PopBox *box = bcell->gui_private;
880 combo_disconnect_signals ((
ComboCell *) bcell);
882 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
883 NULL, NULL, NULL, NULL, NULL);
885 box->list_popped = FALSE;
891 if (gnc_item_in_list (box->item_list, bcell->value))
894 if (g_list_find_custom (box->ignore_strings,
896 (GCompareFunc) strcmp))
899 gnc_basic_cell_set_value_internal (bcell,
"");
911 box = cell->cell.gui_private;
913 box->strict = strict;
924 box = cell->cell.gui_private;
926 box->complete_char = complete_char;
931 const char *ignore_string)
941 box = cell->cell.gui_private;
943 box->ignore_strings = g_list_prepend (box->ignore_strings,
944 g_strdup (ignore_string));
955 box = cell->cell.gui_private;
959 box->autosize = autosize;
void gnc_quickfill_insert(QuickFill *qf, const char *text, QuickFillSort sort)
QuickFill * gnc_quickfill_get_char_match(QuickFill *qf, gunichar uc)
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)
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)
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)
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)
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
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)