~siretart/gnucash/ubuntu-fullsource

« back to all changes in this revision

Viewing changes to src/register/register-gnome/combocell-gnome.c

  • Committer: Reinhard Tartler
  • Date: 2008-08-03 07:25:46 UTC
  • Revision ID: siretart@tauware.de-20080803072546-y6p8xda8zpfi62ys
import gnucash_2.2.4.orig.tar.gz

The original tarball had the md5sum: 27e660297dc5b8ce574515779d05a5a5

Show diffs side-by-side

added added

removed removed

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