1
/********************************************************************\
2
* datecell-gnome.c -- implement date cell handler in gnome *
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. *
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. *
14
* You should have received a copy of the GNU General Public License*
15
* along with this program; if not, contact: *
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 *
21
\********************************************************************/
24
* FILE: datecell-gnome.c
26
* FUNCTION: Implement gnome portion of datecell widget
27
* embedded in a table cell.
30
* Copyright (c) 2000 Dave Peticolas <dave@krondo.com>
42
#include "dialog-utils.h"
43
#include "gnc-ui-util.h"
44
#include "gnucash-date-picker.h"
45
#include "gnucash-item-edit.h"
46
#include "gnucash-sheet.h"
49
#define DATE_BUF (MAX_DATE_LENGTH+1)
51
typedef struct _PopBox
54
GncItemEdit *item_edit;
55
GNCDatePicker *date_picker;
57
gboolean signals_connected; /* date picker signals connected? */
58
gboolean calendar_popped; /* calendar is popped up? */
59
gboolean in_date_select;
65
static void block_picker_signals (DateCell *cell);
66
static void unblock_picker_signals (DateCell *cell);
67
static void gnc_date_cell_realize (BasicCell *bcell, gpointer w);
68
static void gnc_date_cell_set_value_internal (BasicCell *bcell,
70
static void gnc_date_cell_move (BasicCell *bcell);
71
static void gnc_date_cell_gui_destroy (BasicCell *bcell);
72
static void gnc_date_cell_destroy (BasicCell *bcell);
73
static void gnc_date_cell_modify_verify (BasicCell *_cell,
81
static gboolean gnc_date_cell_direct_update (BasicCell *bcell,
86
static gboolean gnc_date_cell_enter (BasicCell *bcell,
90
static void gnc_date_cell_leave (BasicCell *bcell);
94
gnc_parse_date (struct tm *parsed, const char * datestr)
101
qof_scan_date (datestr, &day, &month, &year);
103
parsed->tm_mday = day;
104
parsed->tm_mon = month - 1;
105
parsed->tm_year = year - 1900;
107
gnc_tm_set_day_start(parsed);
108
if (mktime (parsed) == -1)
109
gnc_tm_get_today_start (parsed);
114
gnc_date_cell_print_date (DateCell *cell, char *buff)
116
PopBox *box = cell->cell.gui_private;
118
qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
120
box->date.tm_mon + 1,
121
box->date.tm_year+1900);
125
gnc_date_cell_init (DateCell *cell)
131
gnc_basic_cell_init (&(cell->cell));
133
cell->cell.is_popup = TRUE;
135
cell->cell.destroy = gnc_date_cell_destroy;
137
cell->cell.gui_realize = gnc_date_cell_realize;
138
cell->cell.gui_destroy = gnc_date_cell_gui_destroy;
139
cell->cell.modify_verify = gnc_date_cell_modify_verify;
140
cell->cell.direct_update = gnc_date_cell_direct_update;
141
cell->cell.set_value = gnc_date_cell_set_value_internal;
143
box = g_new0 (PopBox, 1);
146
box->item_edit = NULL;
147
box->date_picker = NULL;
149
box->signals_connected = FALSE;
150
box->calendar_popped = FALSE;
151
box->in_date_select = FALSE;
153
cell->cell.gui_private = box;
155
/* default value is today's date */
157
box->date = *localtime (&secs);
158
gnc_date_cell_print_date (cell, buff);
160
gnc_basic_cell_set_value_internal (&cell->cell, buff);
164
gnc_date_cell_new (void)
168
cell = g_new0 (DateCell, 1);
170
gnc_date_cell_init (cell);
176
date_picked_cb (GNCDatePicker *gdp, gpointer data)
178
DateCell *cell = data;
179
PopBox *box = cell->cell.gui_private;
180
guint day, month, year;
181
char buffer[DATE_BUF];
183
gtk_calendar_get_date (gdp->calendar, &year, &month, &day);
185
qof_print_date_dmy_buff (buffer, MAX_DATE_LENGTH, day, month + 1, year);
187
box->in_date_select = TRUE;
188
gnucash_sheet_modify_current_cell (box->sheet, buffer);
189
box->in_date_select = FALSE;
191
gnc_item_edit_hide_popup (box->item_edit);
192
box->calendar_popped = FALSE;
196
date_selected_cb (GNCDatePicker *gdp, gpointer data)
198
DateCell *cell = data;
199
PopBox *box = cell->cell.gui_private;
200
guint day, month, year;
201
char buffer[DATE_BUF];
203
gtk_calendar_get_date (gdp->calendar, &year, &month, &day);
205
qof_print_date_dmy_buff (buffer, MAX_DATE_LENGTH, day, month + 1, year);
207
box->in_date_select = TRUE;
208
gnucash_sheet_modify_current_cell (box->sheet, buffer);
209
box->in_date_select = FALSE;
213
key_press_item_cb (GNCDatePicker *gdp, GdkEventKey *event, gpointer data)
215
DateCell *cell = data;
216
PopBox *box = cell->cell.gui_private;
218
switch(event->keyval)
221
gnc_item_edit_hide_popup (box->item_edit);
222
box->calendar_popped = FALSE;
226
gtk_widget_event(GTK_WIDGET (box->sheet), (GdkEvent *) event);
232
date_picker_disconnect_signals (DateCell *cell)
234
PopBox *box = cell->cell.gui_private;
236
if (!box->signals_connected)
239
g_signal_handlers_disconnect_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
240
0, 0, NULL, NULL, cell);
242
box->signals_connected = FALSE;
246
date_picker_connect_signals (DateCell *cell)
248
PopBox *box = cell->cell.gui_private;
250
if (box->signals_connected)
253
g_signal_connect (box->date_picker, "date_selected",
254
G_CALLBACK(date_selected_cb), cell);
256
g_signal_connect(box->date_picker, "date_picked",
257
G_CALLBACK(date_picked_cb), cell);
259
g_signal_connect(box->date_picker, "key_press_event",
260
G_CALLBACK(key_press_item_cb), cell);
262
box->signals_connected = TRUE;
266
block_picker_signals (DateCell *cell)
268
PopBox *box = cell->cell.gui_private;
270
if (!box->signals_connected)
273
g_signal_handlers_block_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
274
0, 0, NULL, NULL, cell);
278
unblock_picker_signals (DateCell *cell)
280
PopBox *box = cell->cell.gui_private;
282
if (!box->signals_connected)
285
g_signal_handlers_unblock_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
286
0, 0, NULL, NULL, cell);
290
gnc_date_cell_gui_destroy (BasicCell *bcell)
292
PopBox *box = bcell->gui_private;
293
DateCell *cell = (DateCell *) bcell;
295
if (cell->cell.gui_realize == NULL)
297
if (box != NULL && box->date_picker != NULL)
299
date_picker_disconnect_signals (cell);
300
g_object_unref (box->date_picker);
301
box->date_picker = NULL;
304
/* allow the widget to be shown again */
305
cell->cell.gui_realize = gnc_date_cell_realize;
306
cell->cell.gui_move = NULL;
307
cell->cell.enter_cell = NULL;
308
cell->cell.leave_cell = NULL;
309
cell->cell.gui_destroy = NULL;
314
gnc_date_cell_destroy (BasicCell *bcell)
316
DateCell *cell = (DateCell *) bcell;
317
PopBox *box = cell->cell.gui_private;
319
gnc_date_cell_gui_destroy (&(cell->cell));
323
cell->cell.gui_private = NULL;
324
cell->cell.gui_realize = NULL;
328
gnc_date_cell_set_value (DateCell *cell, int day, int mon, int year)
330
PopBox *box = cell->cell.gui_private;
335
dada.tm_mon = mon - 1;
336
dada.tm_year = year - 1900;
338
gnc_tm_set_day_start(&dada);
341
box->date.tm_mday = dada.tm_mday;
342
box->date.tm_mon = dada.tm_mon;
343
box->date.tm_year = dada.tm_year;
345
qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH, dada.tm_mday, dada.tm_mon + 1, dada.tm_year + 1900);
347
gnc_basic_cell_set_value_internal (&cell->cell, buff);
349
if (!box->date_picker)
352
block_picker_signals (cell);
353
gnc_date_picker_set_date (box->date_picker, day, mon - 1, year);
354
unblock_picker_signals (cell);
358
gnc_date_cell_set_value_secs (DateCell *cell, time_t secs)
360
PopBox *box = cell->cell.gui_private;
364
stm = localtime (&secs);
367
qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
369
box->date.tm_mon + 1,
370
box->date.tm_year + 1900);
372
gnc_basic_cell_set_value_internal (&cell->cell, buff);
374
if (!box->date_picker)
377
block_picker_signals (cell);
378
gnc_date_picker_set_date (box->date_picker,
381
box->date.tm_year + 1900);
382
unblock_picker_signals (cell);
386
gnc_date_cell_commit (DateCell *cell)
388
PopBox *box = cell->cell.gui_private;
394
gnc_parse_date (&(box->date), cell->cell.value);
396
qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
398
box->date.tm_mon + 1,
399
box->date.tm_year + 1900);
401
gnc_basic_cell_set_value_internal (&cell->cell, buff);
403
if (!box->date_picker)
406
block_picker_signals (cell);
407
gnc_date_picker_set_date (box->date_picker,
410
box->date.tm_year + 1900);
411
unblock_picker_signals (cell);
415
gnc_date_cell_direct_update (BasicCell *bcell,
416
int *cursor_position,
417
int *start_selection,
421
DateCell *cell = (DateCell *) bcell;
422
PopBox *box = cell->cell.gui_private;
423
GdkEventKey *event = gui_data;
426
if (!gnc_handle_date_accelerator (event, &(box->date), bcell->value))
429
qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
431
box->date.tm_mon + 1,
432
box->date.tm_year + 1900);
434
gnc_basic_cell_set_value_internal (&cell->cell, buff);
436
*start_selection = 0;
439
if (!box->date_picker)
442
block_picker_signals (cell);
443
gnc_date_picker_set_date (box->date_picker,
446
box->date.tm_year + 1900);
447
unblock_picker_signals (cell);
453
gnc_date_cell_modify_verify (BasicCell *_cell,
458
int *cursor_position,
459
int *start_selection,
462
DateCell *cell = (DateCell *) _cell;
463
PopBox *box = cell->cell.gui_private;
464
gboolean accept = FALSE;
466
if (box->in_date_select)
468
gnc_basic_cell_set_value (_cell, newval);
472
/* if user hit backspace, accept the change */
475
else if (change_len == 0)
480
unsigned char separator = dateSeparator ();
485
/* accept only numbers or a date separator. Note that the
486
* separator of '-' (for DATE_FORMAT_ISO) takes precedence
487
* over the accelerator below! */
491
uc = g_utf8_get_char (c);
493
if (!g_unichar_isdigit (uc) && (separator != uc))
499
c = g_utf8_next_char (c);
505
uc = g_utf8_get_char (c);
510
c = g_utf8_next_char (c);
520
/* keep a copy of the new value */
524
gnc_basic_cell_set_value_internal (&cell->cell, newval);
525
gnc_parse_date (&(box->date), newval);
527
if (!box->date_picker)
530
block_picker_signals (cell);
531
gnc_date_picker_set_date (box->date_picker,
534
box->date.tm_year + 1900);
535
unblock_picker_signals (cell);
540
gnc_date_cell_realize (BasicCell *bcell, gpointer data)
542
GnucashSheet *sheet = data;
543
GnomeCanvasItem *item = sheet->item_editor;
544
GncItemEdit *item_edit = GNC_ITEM_EDIT (item);
545
DateCell *cell = (DateCell *) bcell;
546
PopBox *box = cell->cell.gui_private;
548
/* initialize gui-specific, private data */
550
box->item_edit = item_edit;
551
box->date_picker = gnc_item_edit_new_date_picker (box->item_edit);
553
g_object_ref_sink(box->date_picker);
555
g_object_ref (box->date_picker);
556
gtk_object_sink (GTK_OBJECT(box->date_picker));
559
/* to mark cell as realized, remove the realize method */
560
cell->cell.gui_realize = NULL;
561
cell->cell.gui_move = gnc_date_cell_move;
562
cell->cell.enter_cell = gnc_date_cell_enter;
563
cell->cell.leave_cell = gnc_date_cell_leave;
567
gnc_date_cell_move (BasicCell *bcell)
569
PopBox *box = bcell->gui_private;
571
date_picker_disconnect_signals ((DateCell *) bcell);
573
gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
574
NULL, NULL, NULL, NULL, NULL);
576
box->calendar_popped = FALSE;
580
get_popup_height (GnomeCanvasItem *item,
585
GtkWidget *cal = GTK_WIDGET (GNC_DATE_PICKER (item)->calendar);
591
gtk_widget_size_request (cal, &req);
597
popup_set_focus (GnomeCanvasItem *item,
600
gtk_widget_grab_focus (GTK_WIDGET (GNC_DATE_PICKER (item)->calendar));
604
gnc_date_cell_enter (BasicCell *bcell,
605
int *cursor_position,
606
int *start_selection,
609
DateCell *cell = (DateCell *) bcell;
610
PopBox *box = bcell->gui_private;
612
gnc_item_edit_set_popup (box->item_edit, GNOME_CANVAS_ITEM (box->date_picker),
613
get_popup_height, NULL, popup_set_focus,
616
block_picker_signals (cell);
617
gnc_date_picker_set_date (box->date_picker,
620
box->date.tm_year + 1900);
621
unblock_picker_signals (cell);
623
date_picker_connect_signals ((DateCell *) bcell);
625
*start_selection = 0;
632
gnc_date_cell_leave (BasicCell *bcell)
635
PopBox *box = bcell->gui_private;
637
date_picker_disconnect_signals ((DateCell *) bcell);
639
gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
640
NULL, NULL, NULL, NULL, NULL);
642
box->calendar_popped = FALSE;
644
/* Refresh the date to expand any shortcuts. */
645
gnc_date_cell_get_date ((DateCell *)bcell, &ts);
646
gnc_date_cell_set_value_secs ((DateCell *)bcell, ts.tv_sec);
650
gnc_date_cell_get_date (DateCell *cell, Timespec *ts)
652
PopBox *box = cell->cell.gui_private;
657
gnc_parse_date (&(box->date), cell->cell.value);
659
ts->tv_sec = mktime (&box->date);
664
gnc_date_cell_set_value_internal (BasicCell *_cell, const char *str)
666
DateCell *cell = (DateCell *) _cell;
667
PopBox *box = cell->cell.gui_private;
670
gnc_parse_date (&(box->date), str);
672
qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
674
box->date.tm_mon + 1,
675
box->date.tm_year + 1900);
677
gnc_basic_cell_set_value_internal (_cell, buff);
679
if (!box->date_picker)
682
block_picker_signals (cell);
683
gnc_date_picker_set_date (box->date_picker,
686
box->date.tm_year + 1900);
687
unblock_picker_signals (cell);