|
GnuCash 2.4.99
|
00001 /********************************************************************\ 00002 * combocell-gnome.c -- implement combobox pull down cell for gnome * 00003 * * 00004 * This program is free software; you can redistribute it and/or * 00005 * modify it under the terms of the GNU General Public License as * 00006 * published by the Free Software Foundation; either version 2 of * 00007 * the License, or (at your option) any later version. * 00008 * * 00009 * This program is distributed in the hope that it will be useful, * 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00012 * GNU General Public License for more details. * 00013 * * 00014 * You should have received a copy of the GNU General Public License* 00015 * along with this program; if not, contact: * 00016 * * 00017 * Free Software Foundation Voice: +1-617-542-5942 * 00018 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00019 * Boston, MA 02110-1301, USA gnu@gnu.org * 00020 * * 00021 \********************************************************************/ 00022 00023 /* 00024 * FILE: combocell-gnome.c 00025 * 00026 * FUNCTION: Implement gnome portion of a pull-down combo widget 00027 * embedded in a table cell. 00028 * 00029 * HISTORY: 00030 * Copyright (c) 1998 Linas Vepstas <linas@linas.org> 00031 * Copyright (c) 1998-1999 Rob Browning <rlb@cs.utexas.edu> 00032 * Copyright (c) 2000 Linas Vepstas <linas@linas.org> 00033 * Copyright (c) 2006 David Hampton <hampton@employees.org> 00034 */ 00035 00036 #include "config.h" 00037 00038 #include <gnome.h> 00039 #include <string.h> 00040 00041 #include "QuickFill.h" 00042 #include "combocell.h" 00043 #include "gnc-gconf-utils.h" 00044 #include "gnucash-item-edit.h" 00045 #include "gnucash-item-list.h" 00046 #include "gnucash-sheet.h" 00047 #include "table-allgui.h" 00048 00049 #define KEY_AUTO_RAISE_LISTS "auto_raise_lists" 00050 00051 typedef struct _PopBox 00052 { 00053 GnucashSheet *sheet; 00054 GncItemEdit *item_edit; 00055 GncItemList *item_list; 00056 GtkListStore *tmp_store; 00057 00058 gboolean signals_connected; /* list signals connected? */ 00059 00060 gboolean list_popped; /* list is popped up? */ 00061 00062 gboolean autosize; 00063 00064 QuickFill *qf; 00065 gboolean use_quickfill_cache; /* If TRUE, we don't own the qf */ 00066 00067 gboolean in_list_select; 00068 00069 gboolean strict; 00070 00071 gunichar complete_char; /* char to be used for auto-completion */ 00072 00073 GList *ignore_strings; 00074 } PopBox; 00075 00076 00077 static void gnc_combo_cell_gui_realize (BasicCell *bcell, gpointer w); 00078 static void gnc_combo_cell_gui_move (BasicCell *bcell); 00079 static void gnc_combo_cell_gui_destroy (BasicCell *bcell); 00080 static gboolean gnc_combo_cell_enter (BasicCell *bcell, 00081 int *cursor_position, 00082 int *start_selection, 00083 int *end_selection); 00084 static void gnc_combo_cell_leave (BasicCell *bcell); 00085 static void gnc_combo_cell_destroy (BasicCell *bcell); 00086 00087 static GOnce auto_pop_init_once = G_ONCE_INIT; 00088 static gboolean auto_pop_combos = FALSE; 00089 00090 00091 static void 00092 gnc_combo_cell_set_autopop (GConfEntry *entry, gpointer user_data) 00093 { 00094 GConfValue *value; 00095 00096 value = gconf_entry_get_value(entry); 00097 auto_pop_combos = gconf_value_get_bool(value); 00098 } 00099 00100 static gpointer 00101 gnc_combo_cell_autopop_init (gpointer unused) 00102 { 00103 auto_pop_combos = gnc_gconf_get_bool (GCONF_GENERAL_REGISTER, 00104 KEY_AUTO_RAISE_LISTS, 00105 NULL); 00106 00107 gnc_gconf_general_register_cb(KEY_AUTO_RAISE_LISTS, 00108 gnc_combo_cell_set_autopop, 00109 NULL); 00110 return NULL; 00111 } 00112 00113 BasicCell * 00114 gnc_combo_cell_new (void) 00115 { 00116 ComboCell * cell; 00117 00118 g_once(&auto_pop_init_once, gnc_combo_cell_autopop_init, NULL); 00119 00120 cell = g_new0 (ComboCell, 1); 00121 00122 gnc_combo_cell_init (cell); 00123 00124 return &cell->cell; 00125 } 00126 00127 void 00128 gnc_combo_cell_init (ComboCell *cell) 00129 { 00130 PopBox *box; 00131 00132 gnc_basic_cell_init (&(cell->cell)); 00133 00134 cell->cell.is_popup = TRUE; 00135 00136 cell->cell.destroy = gnc_combo_cell_destroy; 00137 00138 cell->cell.gui_realize = gnc_combo_cell_gui_realize; 00139 cell->cell.gui_destroy = gnc_combo_cell_gui_destroy; 00140 00141 box = g_new0 (PopBox, 1); 00142 00143 box->sheet = NULL; 00144 box->item_edit = NULL; 00145 box->item_list = NULL; 00146 box->tmp_store = gtk_list_store_new (1, G_TYPE_STRING); 00147 box->signals_connected = FALSE; 00148 box->list_popped = FALSE; 00149 box->autosize = FALSE; 00150 00151 cell->cell.gui_private = box; 00152 00153 box->qf = gnc_quickfill_new (); 00154 box->use_quickfill_cache = FALSE; 00155 00156 box->in_list_select = FALSE; 00157 00158 box->strict = TRUE; 00159 00160 box->complete_char = '\0'; 00161 00162 box->ignore_strings = NULL; 00163 } 00164 00165 static void 00166 select_item_cb (GncItemList *item_list, char *item_string, gpointer data) 00167 { 00168 ComboCell *cell = data; 00169 PopBox *box = cell->cell.gui_private; 00170 00171 box->in_list_select = TRUE; 00172 gnucash_sheet_modify_current_cell (box->sheet, item_string); 00173 box->in_list_select = FALSE; 00174 00175 gnc_item_edit_hide_popup (box->item_edit); 00176 box->list_popped = FALSE; 00177 } 00178 00179 static void 00180 change_item_cb (GncItemList *item_list, char *item_string, gpointer data) 00181 { 00182 ComboCell *cell = data; 00183 PopBox *box = cell->cell.gui_private; 00184 00185 box->in_list_select = TRUE; 00186 gnucash_sheet_modify_current_cell (box->sheet, item_string); 00187 box->in_list_select = FALSE; 00188 } 00189 00190 static void 00191 activate_item_cb (GncItemList *item_list, char *item_string, gpointer data) 00192 { 00193 ComboCell *cell = data; 00194 PopBox *box = cell->cell.gui_private; 00195 00196 gnc_item_edit_hide_popup (box->item_edit); 00197 box->list_popped = FALSE; 00198 } 00199 00200 static void 00201 key_press_item_cb (GncItemList *item_list, GdkEventKey *event, gpointer data) 00202 { 00203 ComboCell *cell = data; 00204 PopBox *box = cell->cell.gui_private; 00205 00206 switch (event->keyval) 00207 { 00208 case GDK_Escape: 00209 gnc_item_edit_hide_popup (box->item_edit); 00210 box->list_popped = FALSE; 00211 break; 00212 00213 default: 00214 gtk_widget_event (GTK_WIDGET(box->sheet), 00215 (GdkEvent *) event); 00216 break; 00217 } 00218 } 00219 00220 static void 00221 combo_disconnect_signals (ComboCell *cell) 00222 { 00223 PopBox *box = cell->cell.gui_private; 00224 00225 if (!box->signals_connected) 00226 return; 00227 00228 g_signal_handlers_disconnect_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA, 00229 0, 0, NULL, NULL, cell); 00230 00231 box->signals_connected = FALSE; 00232 } 00233 00234 static void 00235 combo_connect_signals (ComboCell *cell) 00236 { 00237 PopBox *box = cell->cell.gui_private; 00238 00239 if (box->signals_connected) 00240 return; 00241 00242 g_signal_connect (G_OBJECT (box->item_list), "select_item", 00243 G_CALLBACK (select_item_cb), cell); 00244 00245 g_signal_connect (G_OBJECT (box->item_list), "change_item", 00246 G_CALLBACK (change_item_cb), cell); 00247 00248 g_signal_connect (G_OBJECT (box->item_list), "activate_item", 00249 G_CALLBACK (activate_item_cb), cell); 00250 00251 g_signal_connect (G_OBJECT (box->item_list), "key_press_event", 00252 G_CALLBACK (key_press_item_cb), cell); 00253 00254 box->signals_connected = TRUE; 00255 } 00256 00257 static void 00258 block_list_signals (ComboCell *cell) 00259 { 00260 PopBox *box = cell->cell.gui_private; 00261 00262 if (!box->signals_connected) 00263 return; 00264 00265 g_signal_handlers_block_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA, 00266 0, 0, NULL, NULL, cell); 00267 } 00268 00269 static void 00270 unblock_list_signals (ComboCell *cell) 00271 { 00272 PopBox *box = cell->cell.gui_private; 00273 00274 if (!box->signals_connected) 00275 return; 00276 00277 g_signal_handlers_unblock_matched (G_OBJECT (box->item_list), G_SIGNAL_MATCH_DATA, 00278 0, 0, NULL, NULL, cell); 00279 } 00280 00281 static void 00282 gnc_combo_cell_gui_destroy (BasicCell *bcell) 00283 { 00284 PopBox *box = bcell->gui_private; 00285 ComboCell *cell = (ComboCell *) bcell; 00286 00287 if (cell->cell.gui_realize == NULL) 00288 { 00289 if (box != NULL && box->item_list != NULL) 00290 { 00291 combo_disconnect_signals(cell); 00292 g_object_unref (box->item_list); 00293 box->item_list = NULL; 00294 } 00295 00296 /* allow the widget to be shown again */ 00297 cell->cell.gui_realize = gnc_combo_cell_gui_realize; 00298 cell->cell.gui_move = NULL; 00299 cell->cell.enter_cell = NULL; 00300 cell->cell.leave_cell = NULL; 00301 cell->cell.gui_destroy = NULL; 00302 } 00303 } 00304 00305 static void 00306 gnc_combo_cell_destroy (BasicCell *bcell) 00307 { 00308 ComboCell *cell = (ComboCell *) bcell; 00309 PopBox *box = cell->cell.gui_private; 00310 00311 gnc_combo_cell_gui_destroy (&(cell->cell)); 00312 00313 if (box != NULL) 00314 { 00315 GList *node; 00316 00317 /* Don't destroy the qf if its not ours to destroy */ 00318 if (FALSE == box->use_quickfill_cache) 00319 { 00320 gnc_quickfill_destroy (box->qf); 00321 box->qf = NULL; 00322 } 00323 00324 for (node = box->ignore_strings; node; node = node->next) 00325 { 00326 g_free (node->data); 00327 node->data = NULL; 00328 } 00329 00330 g_list_free (box->ignore_strings); 00331 box->ignore_strings = NULL; 00332 00333 g_free (box); 00334 cell->cell.gui_private = NULL; 00335 } 00336 00337 cell->cell.gui_private = NULL; 00338 cell->cell.gui_realize = NULL; 00339 } 00340 00341 void 00342 gnc_combo_cell_set_sort_enabled (ComboCell *cell, gboolean enabled) 00343 { 00344 PopBox *box; 00345 00346 if (cell == NULL) 00347 return; 00348 00349 box = cell->cell.gui_private; 00350 if (box->item_list == NULL) 00351 return; 00352 00353 block_list_signals (cell); 00354 gnc_item_list_set_sort_enabled(box->item_list, enabled); 00355 unblock_list_signals (cell); 00356 } 00357 00358 void 00359 gnc_combo_cell_clear_menu (ComboCell * cell) 00360 { 00361 PopBox *box; 00362 00363 if (cell == NULL) 00364 return; 00365 00366 box = cell->cell.gui_private; 00367 if (box == NULL) 00368 return; 00369 00370 /* Don't destroy the qf if its not ours to destroy */ 00371 if (FALSE == box->use_quickfill_cache) 00372 { 00373 gnc_quickfill_destroy (box->qf); 00374 box->qf = gnc_quickfill_new (); 00375 } 00376 00377 if (box->item_list != NULL) 00378 { 00379 block_list_signals (cell); 00380 00381 gnc_item_list_clear (box->item_list); 00382 00383 unblock_list_signals (cell); 00384 } 00385 } 00386 00387 void 00388 gnc_combo_cell_use_quickfill_cache (ComboCell * cell, QuickFill *shared_qf) 00389 { 00390 PopBox *box; 00391 00392 if (cell == NULL) return; 00393 00394 box = cell->cell.gui_private; 00395 if (NULL == box) return; 00396 00397 if (FALSE == box->use_quickfill_cache) 00398 { 00399 box->use_quickfill_cache = TRUE; 00400 gnc_quickfill_destroy (box->qf); 00401 } 00402 box->qf = shared_qf; 00403 } 00404 00405 void 00406 gnc_combo_cell_use_list_store_cache (ComboCell * cell, gpointer data) 00407 { 00408 if (cell == NULL) return; 00409 00410 cell->shared_store = data; 00411 } 00412 00413 void 00414 gnc_combo_cell_add_menu_item (ComboCell *cell, const char * menustr) 00415 { 00416 PopBox *box; 00417 00418 if (cell == NULL) 00419 return; 00420 if (menustr == NULL) 00421 return; 00422 00423 box = cell->cell.gui_private; 00424 00425 if (box->item_list != NULL) 00426 { 00427 block_list_signals (cell); 00428 00429 gnc_item_list_append (box->item_list, menustr); 00430 if (cell->cell.value && 00431 (strcmp (menustr, cell->cell.value) == 0)) 00432 gnc_item_list_select (box->item_list, menustr); 00433 00434 unblock_list_signals (cell); 00435 } 00436 else 00437 { 00438 GtkTreeIter iter; 00439 00440 gtk_list_store_append(box->tmp_store, &iter); 00441 gtk_list_store_set(box->tmp_store, &iter, 0, menustr, -1); 00442 } 00443 00444 /* If we're going to be using a pre-fab quickfill, 00445 * then don't fill it in here */ 00446 if (FALSE == box->use_quickfill_cache) 00447 { 00448 gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA); 00449 } 00450 } 00451 00452 void 00453 gnc_combo_cell_add_account_menu_item (ComboCell *cell, char * menustr) 00454 { 00455 PopBox *box; 00456 gchar *menu_copy, *value_copy; 00457 00458 if (cell == NULL) 00459 return; 00460 if (menustr == NULL) 00461 return; 00462 00463 box = cell->cell.gui_private; 00464 00465 if (box->item_list != NULL) 00466 { 00467 block_list_signals (cell); 00468 00469 gnc_item_list_append (box->item_list, menustr); 00470 if (cell->cell.value) 00471 { 00472 menu_copy = g_strdelimit(g_strdup(menustr), "-:/\\.", ' '); 00473 value_copy = 00474 g_strdelimit(g_strdup(cell->cell.value), "-:/\\.", ' '); 00475 if (strcmp (menu_copy, value_copy) == 0) 00476 { 00477 gnc_combo_cell_set_value (cell, menustr); 00478 gnc_item_list_select (box->item_list, menustr); 00479 } 00480 g_free(value_copy); 00481 g_free(menu_copy); 00482 } 00483 unblock_list_signals (cell); 00484 } 00485 00486 /* If we're going to be using a pre-fab quickfill, 00487 * then don't fill it in here */ 00488 if (FALSE == box->use_quickfill_cache) 00489 { 00490 gnc_quickfill_insert (box->qf, menustr, QUICKFILL_ALPHA); 00491 } 00492 } 00493 00494 void 00495 gnc_combo_cell_set_value (ComboCell *cell, const char *str) 00496 { 00497 gnc_basic_cell_set_value (&cell->cell, str); 00498 } 00499 00500 static void 00501 gnc_combo_cell_modify_verify (BasicCell *_cell, 00502 const char *change, 00503 int change_len, 00504 const char *newval, 00505 int newval_len, 00506 int *cursor_position, 00507 int *start_selection, 00508 int *end_selection) 00509 { 00510 ComboCell *cell = (ComboCell *) _cell; 00511 PopBox *box = cell->cell.gui_private; 00512 const char *match_str; 00513 QuickFill *match; 00514 gboolean pop_list; 00515 glong newval_chars; 00516 glong change_chars; 00517 00518 newval_chars = g_utf8_strlen (newval, newval_len); 00519 change_chars = g_utf8_strlen (change, change_len); 00520 00521 if (box->in_list_select) 00522 { 00523 gnc_basic_cell_set_value_internal (_cell, newval); 00524 00525 *cursor_position = -1; 00526 *start_selection = 0; 00527 *end_selection = -1; 00528 00529 return; 00530 } 00531 00532 /* If deleting, just accept */ 00533 if (change == NULL) 00534 { 00535 gnc_basic_cell_set_value_internal (_cell, newval); 00536 return; 00537 } 00538 00539 /* If we are inserting in the middle, just accept */ 00540 if (*cursor_position < _cell->value_chars) 00541 { 00542 gnc_basic_cell_set_value_internal (_cell, newval); 00543 return; 00544 } 00545 00546 match = gnc_quickfill_get_string_match (box->qf, newval); 00547 00548 match_str = gnc_quickfill_string (match); 00549 00550 if ((match == NULL) || (match_str == NULL)) 00551 { 00552 gnc_basic_cell_set_value_internal (_cell, newval); 00553 00554 block_list_signals (cell); 00555 gnc_item_list_select (box->item_list, NULL); 00556 unblock_list_signals (cell); 00557 00558 return; 00559 } 00560 00561 *start_selection = newval_chars; 00562 *end_selection = -1; 00563 *cursor_position += change_chars; 00564 00565 if (!box->list_popped) 00566 pop_list = auto_pop_combos; 00567 else 00568 pop_list = FALSE; 00569 00570 if (pop_list) 00571 { 00572 gnc_item_edit_show_popup (box->item_edit); 00573 box->list_popped = TRUE; 00574 } 00575 00576 block_list_signals (cell); 00577 gnc_item_list_select (box->item_list, match_str); 00578 unblock_list_signals (cell); 00579 00580 gnc_basic_cell_set_value_internal (_cell, match_str); 00581 } 00582 00583 static gboolean 00584 gnc_combo_cell_direct_update (BasicCell *bcell, 00585 int *cursor_position, 00586 int *start_selection, 00587 int *end_selection, 00588 void *gui_data) 00589 { 00590 ComboCell *cell = (ComboCell *) bcell; 00591 PopBox *box = cell->cell.gui_private; 00592 GdkEventKey *event = gui_data; 00593 gboolean keep_on_going = FALSE; 00594 gboolean extra_colon; 00595 gunichar unicode_value; 00596 QuickFill *match; 00597 const char *match_str; 00598 int prefix_len; 00599 int find_pos; 00600 int new_pos; 00601 00602 if (event->type != GDK_KEY_PRESS) 00603 return FALSE; 00604 00605 unicode_value = gdk_keyval_to_unicode(event->keyval); 00606 switch (event->keyval) 00607 { 00608 case GDK_slash: 00609 if (!(event->state & GDK_MOD1_MASK)) 00610 { 00611 if (unicode_value == box->complete_char) 00612 break; 00613 00614 return FALSE; 00615 } 00616 keep_on_going = TRUE; 00617 /* fall through */ 00618 case GDK_Tab: 00619 case GDK_ISO_Left_Tab: 00620 if (!(event->state & GDK_CONTROL_MASK) && 00621 !keep_on_going) 00622 return FALSE; 00623 00624 match = gnc_quickfill_get_string_len_match 00625 (box->qf, bcell->value, *cursor_position); 00626 if (match == NULL) 00627 return TRUE; 00628 00629 match = gnc_quickfill_get_unique_len_match 00630 (match, &prefix_len); 00631 if (match == NULL) 00632 return TRUE; 00633 00634 match_str = gnc_quickfill_string (match); 00635 00636 if ((match_str != NULL) && 00637 (strncmp (match_str, bcell->value, 00638 strlen (bcell->value)) == 0) && 00639 (strcmp (match_str, bcell->value) != 0)) 00640 { 00641 gnc_basic_cell_set_value_internal (bcell, 00642 match_str); 00643 00644 block_list_signals (cell); 00645 gnc_item_list_select (box->item_list, 00646 match_str); 00647 unblock_list_signals (cell); 00648 } 00649 00650 *cursor_position += prefix_len; 00651 *start_selection = *cursor_position; 00652 *end_selection = -1; 00653 00654 return TRUE; 00655 } 00656 00657 if (box->complete_char == 0) 00658 return FALSE; 00659 00660 if (unicode_value != box->complete_char) 00661 return FALSE; 00662 00663 if (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) 00664 return FALSE; 00665 00666 if ((*cursor_position < bcell->value_chars) && 00667 ((*end_selection < bcell->value_chars) || 00668 (*cursor_position < *start_selection))) 00669 return FALSE; 00670 00671 if ((*cursor_position == bcell->value_chars) && 00672 (*start_selection != *end_selection) && 00673 (*end_selection < bcell->value_chars)) 00674 return FALSE; 00675 00676 find_pos = -1; 00677 if (*start_selection < bcell->value_chars) 00678 { 00679 int i = *start_selection; 00680 const char *c; 00681 gunichar uc; 00682 00683 c = g_utf8_offset_to_pointer (bcell->value, i); 00684 while (*c) 00685 { 00686 uc = g_utf8_get_char (c); 00687 if (uc == box->complete_char) 00688 { 00689 find_pos = (i + 1); 00690 break; 00691 } 00692 c = g_utf8_next_char (c); 00693 i++; 00694 } 00695 } 00696 00697 new_pos = *cursor_position; 00698 00699 if (find_pos >= 0) 00700 { 00701 new_pos = find_pos; 00702 extra_colon = FALSE; 00703 } 00704 else 00705 { 00706 new_pos = bcell->value_chars; 00707 extra_colon = TRUE; 00708 } 00709 00710 match = gnc_quickfill_get_string_len_match (box->qf, 00711 bcell->value, new_pos); 00712 if (match == NULL) 00713 return FALSE; 00714 00715 if (extra_colon) 00716 { 00717 match = gnc_quickfill_get_char_match (match, 00718 box->complete_char); 00719 if (match == NULL) 00720 return FALSE; 00721 00722 new_pos++; 00723 } 00724 00725 match_str = gnc_quickfill_string (match); 00726 00727 if ((match_str != NULL) && 00728 (strncmp (match_str, bcell->value, strlen (bcell->value)) == 0) && 00729 (strcmp (match_str, bcell->value) != 0)) 00730 { 00731 gnc_basic_cell_set_value_internal (bcell, match_str); 00732 00733 block_list_signals (cell); 00734 gnc_item_list_select (box->item_list, match_str); 00735 unblock_list_signals (cell); 00736 } 00737 00738 *cursor_position = new_pos; 00739 *start_selection = new_pos; 00740 *end_selection = -1; 00741 00742 return TRUE; 00743 } 00744 00745 static void 00746 gnc_combo_cell_gui_realize (BasicCell *bcell, gpointer data) 00747 { 00748 GnucashSheet *sheet = data; 00749 GnomeCanvasItem *item = sheet->item_editor; 00750 GncItemEdit *item_edit = GNC_ITEM_EDIT (item); 00751 ComboCell *cell = (ComboCell *) bcell; 00752 PopBox *box = cell->cell.gui_private; 00753 00754 /* initialize gui-specific, private data */ 00755 box->sheet = sheet; 00756 box->item_edit = item_edit; 00757 if (cell->shared_store) 00758 box->item_list = gnc_item_edit_new_list(box->item_edit, cell->shared_store); 00759 else 00760 box->item_list = gnc_item_edit_new_list(box->item_edit, box->tmp_store); 00761 g_object_ref_sink(box->item_list); 00762 00763 /* to mark cell as realized, remove the realize method */ 00764 cell->cell.gui_realize = NULL; 00765 cell->cell.gui_move = gnc_combo_cell_gui_move; 00766 cell->cell.enter_cell = gnc_combo_cell_enter; 00767 cell->cell.leave_cell = gnc_combo_cell_leave; 00768 cell->cell.gui_destroy = gnc_combo_cell_gui_destroy; 00769 cell->cell.modify_verify = gnc_combo_cell_modify_verify; 00770 cell->cell.direct_update = gnc_combo_cell_direct_update; 00771 } 00772 00773 static void 00774 gnc_combo_cell_gui_move (BasicCell *bcell) 00775 { 00776 PopBox *box = bcell->gui_private; 00777 00778 combo_disconnect_signals ((ComboCell *) bcell); 00779 00780 gnc_item_edit_set_popup (box->item_edit, NULL, NULL, 00781 NULL, NULL, NULL, NULL, NULL); 00782 00783 box->list_popped = FALSE; 00784 } 00785 00786 static int 00787 get_popup_height (GnomeCanvasItem *item, 00788 int space_available, 00789 int row_height, 00790 gpointer user_data) 00791 { 00792 PopBox *box = user_data; 00793 int count, pad = 4; 00794 00795 count = gnc_item_list_num_entries(box->item_list); 00796 return MIN(space_available, (count * (row_height + pad)) + pad); 00797 } 00798 00799 static int 00800 popup_autosize (GnomeCanvasItem *item, 00801 int max_width, 00802 gpointer user_data) 00803 { 00804 PopBox *box = user_data; 00805 00806 if (!box || !box->autosize) 00807 return max_width; 00808 00809 return gnc_item_list_autosize (GNC_ITEM_LIST (item)) + 20; 00810 } 00811 00812 static void 00813 popup_set_focus (GnomeCanvasItem *item, 00814 gpointer user_data) 00815 { 00816 gtk_widget_grab_focus (GTK_WIDGET (GNC_ITEM_LIST (item)->tree_view)); 00817 } 00818 00819 static void 00820 popup_post_show (GnomeCanvasItem *item, 00821 gpointer user_data) 00822 { 00823 /* What the hell is this doing here? Well, under gtk+ 1.2.9, 00824 * the scrollbars never appear without it. Why does it work? 00825 * Why are you asking so many questions? There's nothing to 00826 * see here. These aren't the droids you're looking for. 00827 * Move along. */ 00828 gtk_widget_size_request (GNC_ITEM_LIST (item)->frame, NULL); 00829 00830 gnc_item_list_autosize (GNC_ITEM_LIST (item)); 00831 gnc_item_list_show_selected (GNC_ITEM_LIST (item)); 00832 } 00833 00834 static int 00835 popup_get_width (GnomeCanvasItem *item, 00836 gpointer user_data) 00837 { 00838 return GTK_WIDGET (GNC_ITEM_LIST (item)->tree_view)->allocation.width; 00839 } 00840 00841 static gboolean 00842 gnc_combo_cell_enter (BasicCell *bcell, 00843 int *cursor_position, 00844 int *start_selection, 00845 int *end_selection) 00846 { 00847 ComboCell *cell = (ComboCell *) bcell; 00848 PopBox *box = bcell->gui_private; 00849 GList *find = NULL; 00850 00851 if (bcell->value) 00852 find = g_list_find_custom (box->ignore_strings, 00853 bcell->value, 00854 (GCompareFunc) strcmp); 00855 if (find) 00856 return FALSE; 00857 00858 gnc_item_edit_set_popup (box->item_edit, 00859 GNOME_CANVAS_ITEM (box->item_list), 00860 get_popup_height, popup_autosize, 00861 popup_set_focus, popup_post_show, 00862 popup_get_width, box); 00863 00864 block_list_signals (cell); 00865 gnc_item_list_select (box->item_list, bcell->value); 00866 unblock_list_signals (cell); 00867 00868 combo_connect_signals (cell); 00869 00870 *cursor_position = -1; 00871 *start_selection = 0; 00872 *end_selection = -1; 00873 00874 return TRUE; 00875 } 00876 00877 static void 00878 gnc_combo_cell_leave (BasicCell *bcell) 00879 { 00880 PopBox *box = bcell->gui_private; 00881 00882 combo_disconnect_signals ((ComboCell *) bcell); 00883 00884 gnc_item_edit_set_popup (box->item_edit, NULL, NULL, 00885 NULL, NULL, NULL, NULL, NULL); 00886 00887 box->list_popped = FALSE; 00888 00889 if (box->strict) 00890 { 00891 if (bcell->value) 00892 { 00893 if (gnc_item_in_list (box->item_list, bcell->value)) 00894 return; 00895 00896 if (g_list_find_custom (box->ignore_strings, 00897 bcell->value, 00898 (GCompareFunc) strcmp)) 00899 return; 00900 } 00901 gnc_basic_cell_set_value_internal (bcell, ""); 00902 } 00903 } 00904 00905 void 00906 gnc_combo_cell_set_strict (ComboCell *cell, gboolean strict) 00907 { 00908 PopBox *box; 00909 00910 if (cell == NULL) 00911 return; 00912 00913 box = cell->cell.gui_private; 00914 00915 box->strict = strict; 00916 } 00917 00918 void 00919 gnc_combo_cell_set_complete_char (ComboCell *cell, gunichar complete_char) 00920 { 00921 PopBox *box; 00922 00923 if (cell == NULL) 00924 return; 00925 00926 box = cell->cell.gui_private; 00927 00928 box->complete_char = complete_char; 00929 } 00930 00931 void 00932 gnc_combo_cell_add_ignore_string (ComboCell *cell, 00933 const char *ignore_string) 00934 { 00935 PopBox *box; 00936 00937 if (cell == NULL) 00938 return; 00939 00940 if (!ignore_string) 00941 return; 00942 00943 box = cell->cell.gui_private; 00944 00945 box->ignore_strings = g_list_prepend (box->ignore_strings, 00946 g_strdup (ignore_string)); 00947 } 00948 00949 void 00950 gnc_combo_cell_set_autosize (ComboCell *cell, gboolean autosize) 00951 { 00952 PopBox *box; 00953 00954 if (!cell) 00955 return; 00956 00957 box = cell->cell.gui_private; 00958 if (!box) 00959 return; 00960 00961 box->autosize = autosize; 00962 } 00963
1.7.4