00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "config.h"
00034
00035 #include <gnome.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <time.h>
00040
00041 #include "datecell.h"
00042 #include "dialog-utils.h"
00043 #include "gnc-ui-util.h"
00044 #include "gnucash-date-picker.h"
00045 #include "gnucash-item-edit.h"
00046 #include "gnucash-sheet.h"
00047
00048
00049 #define DATE_BUF 30
00050
00051 typedef struct _PopBox
00052 {
00053 GnucashSheet *sheet;
00054 GncItemEdit *item_edit;
00055 GNCDatePicker *date_picker;
00056
00057 gboolean signals_connected;
00058 gboolean calendar_popped;
00059 gboolean in_date_select;
00060
00061 struct tm date;
00062 } PopBox;
00063
00064
00065 static void block_picker_signals (DateCell *cell);
00066 static void unblock_picker_signals (DateCell *cell);
00067 static void gnc_date_cell_realize (BasicCell *bcell, gpointer w);
00068 static void gnc_date_cell_set_value_internal (BasicCell *bcell,
00069 const char *value);
00070 static void gnc_date_cell_move (BasicCell *bcell);
00071 static void gnc_date_cell_gui_destroy (BasicCell *bcell);
00072 static void gnc_date_cell_destroy (BasicCell *bcell);
00073 static void gnc_date_cell_modify_verify (BasicCell *_cell,
00074 const char *change,
00075 int change_len,
00076 const char *newval,
00077 int newval_len,
00078 int *cursor_position,
00079 int *start_selection,
00080 int *end_selection);
00081 static gboolean gnc_date_cell_direct_update (BasicCell *bcell,
00082 int *cursor_position,
00083 int *start_selection,
00084 int *end_selection,
00085 void *gui_data);
00086 static gboolean gnc_date_cell_enter (BasicCell *bcell,
00087 int *cursor_position,
00088 int *start_selection,
00089 int *end_selection);
00090 static void gnc_date_cell_leave (BasicCell *bcell);
00091
00092
00093 static void
00094 gnc_parse_date (struct tm *parsed, const char * datestr)
00095 {
00096 int day, month, year;
00097
00098 if (!parsed) return;
00099 if (!datestr) return;
00100
00101 qof_scan_date (datestr, &day, &month, &year);
00102
00103 parsed->tm_mday = day;
00104 parsed->tm_mon = month - 1;
00105 parsed->tm_year = year - 1900;
00106
00107 gnc_tm_set_day_start(parsed);
00108 if (mktime (parsed) == -1)
00109 gnc_tm_get_today_start (parsed);
00110 mktime (parsed);
00111 }
00112
00113 static void
00114 gnc_date_cell_print_date (DateCell *cell, char *buff)
00115 {
00116 PopBox *box = cell->cell.gui_private;
00117
00118 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00119 box->date.tm_mday,
00120 box->date.tm_mon + 1,
00121 box->date.tm_year+1900);
00122 }
00123
00124 static void
00125 gnc_date_cell_init (DateCell *cell)
00126 {
00127 PopBox *box;
00128 time_t secs;
00129 char buff[DATE_BUF];
00130
00131 gnc_basic_cell_init (&(cell->cell));
00132
00133 cell->cell.is_popup = TRUE;
00134
00135 cell->cell.destroy = gnc_date_cell_destroy;
00136
00137 cell->cell.gui_realize = gnc_date_cell_realize;
00138 cell->cell.gui_destroy = gnc_date_cell_gui_destroy;
00139 cell->cell.modify_verify = gnc_date_cell_modify_verify;
00140 cell->cell.direct_update = gnc_date_cell_direct_update;
00141 cell->cell.set_value = gnc_date_cell_set_value_internal;
00142
00143 box = g_new0 (PopBox, 1);
00144
00145 box->sheet = NULL;
00146 box->item_edit = NULL;
00147 box->date_picker = NULL;
00148
00149 box->signals_connected = FALSE;
00150 box->calendar_popped = FALSE;
00151 box->in_date_select = FALSE;
00152
00153 cell->cell.gui_private = box;
00154
00155
00156 time (&secs);
00157 box->date = *localtime (&secs);
00158 gnc_date_cell_print_date (cell, buff);
00159
00160 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00161 }
00162
00163 BasicCell *
00164 gnc_date_cell_new (void)
00165 {
00166 DateCell *cell;
00167
00168 cell = g_new0 (DateCell, 1);
00169
00170 gnc_date_cell_init (cell);
00171
00172 return &cell->cell;
00173 }
00174
00175 static void
00176 date_picked_cb (GNCDatePicker *gdp, gpointer data)
00177 {
00178 DateCell *cell = data;
00179 PopBox *box = cell->cell.gui_private;
00180 guint day, month, year;
00181 char buffer[DATE_BUF];
00182
00183 gtk_calendar_get_date (gdp->calendar, &year, &month, &day);
00184
00185 qof_print_date_dmy_buff (buffer, MAX_DATE_LENGTH, day, month + 1, year);
00186
00187 box->in_date_select = TRUE;
00188 gnucash_sheet_modify_current_cell (box->sheet, buffer);
00189 box->in_date_select = FALSE;
00190
00191 gnc_item_edit_hide_popup (box->item_edit);
00192 box->calendar_popped = FALSE;
00193 }
00194
00195 static void
00196 date_selected_cb (GNCDatePicker *gdp, gpointer data)
00197 {
00198 DateCell *cell = data;
00199 PopBox *box = cell->cell.gui_private;
00200 guint day, month, year;
00201 char buffer[DATE_BUF];
00202
00203 gtk_calendar_get_date (gdp->calendar, &year, &month, &day);
00204
00205 qof_print_date_dmy_buff (buffer, MAX_DATE_LENGTH, day, month + 1, year);
00206
00207 box->in_date_select = TRUE;
00208 gnucash_sheet_modify_current_cell (box->sheet, buffer);
00209 box->in_date_select = FALSE;
00210 }
00211
00212 static void
00213 key_press_item_cb (GNCDatePicker *gdp, GdkEventKey *event, gpointer data)
00214 {
00215 DateCell *cell = data;
00216 PopBox *box = cell->cell.gui_private;
00217
00218 switch(event->keyval)
00219 {
00220 case GDK_Escape:
00221 gnc_item_edit_hide_popup (box->item_edit);
00222 box->calendar_popped = FALSE;
00223 break;
00224
00225 default:
00226 gtk_widget_event(GTK_WIDGET (box->sheet), (GdkEvent *) event);
00227 break;
00228 }
00229 }
00230
00231 static void
00232 date_picker_disconnect_signals (DateCell *cell)
00233 {
00234 PopBox *box = cell->cell.gui_private;
00235
00236 if (!box->signals_connected)
00237 return;
00238
00239 gtk_signal_disconnect_by_data (GTK_OBJECT (box->date_picker), cell);
00240
00241 box->signals_connected = FALSE;
00242 }
00243
00244 static void
00245 date_picker_connect_signals (DateCell *cell)
00246 {
00247 PopBox *box = cell->cell.gui_private;
00248
00249 if (box->signals_connected)
00250 return;
00251
00252 gtk_signal_connect (GTK_OBJECT(box->date_picker), "date_selected",
00253 GTK_SIGNAL_FUNC(date_selected_cb), cell);
00254
00255 gtk_signal_connect(GTK_OBJECT(box->date_picker), "date_picked",
00256 GTK_SIGNAL_FUNC(date_picked_cb), cell);
00257
00258 gtk_signal_connect(GTK_OBJECT(box->date_picker), "key_press_event",
00259 GTK_SIGNAL_FUNC(key_press_item_cb), cell);
00260
00261 box->signals_connected = TRUE;
00262 }
00263
00264 static void
00265 block_picker_signals (DateCell *cell)
00266 {
00267 PopBox *box = cell->cell.gui_private;
00268
00269 if (!box->signals_connected)
00270 return;
00271
00272 gtk_signal_handler_block_by_data (GTK_OBJECT (box->date_picker), cell);
00273 }
00274
00275 static void
00276 unblock_picker_signals (DateCell *cell)
00277 {
00278 PopBox *box = cell->cell.gui_private;
00279
00280 if (!box->signals_connected)
00281 return;
00282
00283 gtk_signal_handler_unblock_by_data (GTK_OBJECT (box->date_picker), cell);
00284 }
00285
00286 static void
00287 gnc_date_cell_gui_destroy (BasicCell *bcell)
00288 {
00289 PopBox *box = bcell->gui_private;
00290 DateCell *cell = (DateCell *) bcell;
00291
00292 if (cell->cell.gui_realize == NULL)
00293 {
00294 if (box != NULL && box->date_picker != NULL)
00295 {
00296 date_picker_disconnect_signals (cell);
00297 g_object_unref (box->date_picker);
00298 box->date_picker = NULL;
00299 }
00300
00301
00302 cell->cell.gui_realize = gnc_date_cell_realize;
00303 cell->cell.gui_move = NULL;
00304 cell->cell.enter_cell = NULL;
00305 cell->cell.leave_cell = NULL;
00306 cell->cell.gui_destroy = NULL;
00307 }
00308 }
00309
00310 static void
00311 gnc_date_cell_destroy (BasicCell *bcell)
00312 {
00313 DateCell *cell = (DateCell *) bcell;
00314 PopBox *box = cell->cell.gui_private;
00315
00316 gnc_date_cell_gui_destroy (&(cell->cell));
00317
00318 g_free (box);
00319
00320 cell->cell.gui_private = NULL;
00321 cell->cell.gui_realize = NULL;
00322 }
00323
00324 void
00325 gnc_date_cell_set_value (DateCell *cell, int day, int mon, int year)
00326 {
00327 PopBox *box = cell->cell.gui_private;
00328 struct tm dada;
00329 char buff[DATE_BUF];
00330
00331 dada.tm_mday = day;
00332 dada.tm_mon = mon - 1;
00333 dada.tm_year = year - 1900;
00334
00335 gnc_tm_set_day_start(&dada);
00336 mktime (&dada);
00337
00338 box->date.tm_mday = dada.tm_mday;
00339 box->date.tm_mon = dada.tm_mon;
00340 box->date.tm_year = dada.tm_year;
00341
00342 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH, dada.tm_mday, dada.tm_mon + 1, dada.tm_year + 1900);
00343
00344 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00345
00346 if (!box->date_picker)
00347 return;
00348
00349 block_picker_signals (cell);
00350 gnc_date_picker_set_date (box->date_picker, day, mon - 1, year);
00351 unblock_picker_signals (cell);
00352 }
00353
00354 void
00355 gnc_date_cell_set_value_secs (DateCell *cell, time_t secs)
00356 {
00357 PopBox *box = cell->cell.gui_private;
00358 char buff[DATE_BUF];
00359 struct tm * stm;
00360
00361 stm = localtime (&secs);
00362 box->date = *stm;
00363
00364 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00365 box->date.tm_mday,
00366 box->date.tm_mon + 1,
00367 box->date.tm_year + 1900);
00368
00369 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00370
00371 if (!box->date_picker)
00372 return;
00373
00374 block_picker_signals (cell);
00375 gnc_date_picker_set_date (box->date_picker,
00376 box->date.tm_mday,
00377 box->date.tm_mon,
00378 box->date.tm_year + 1900);
00379 unblock_picker_signals (cell);
00380 }
00381
00382 void
00383 gnc_date_cell_commit (DateCell *cell)
00384 {
00385 PopBox *box = cell->cell.gui_private;
00386 char buff[DATE_BUF];
00387
00388 if (!cell)
00389 return;
00390
00391 gnc_parse_date (&(box->date), cell->cell.value);
00392
00393 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00394 box->date.tm_mday,
00395 box->date.tm_mon + 1,
00396 box->date.tm_year + 1900);
00397
00398 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00399
00400 if (!box->date_picker)
00401 return;
00402
00403 block_picker_signals (cell);
00404 gnc_date_picker_set_date (box->date_picker,
00405 box->date.tm_mday,
00406 box->date.tm_mon,
00407 box->date.tm_year + 1900);
00408 unblock_picker_signals (cell);
00409 }
00410
00411 static gboolean
00412 gnc_date_cell_direct_update (BasicCell *bcell,
00413 int *cursor_position,
00414 int *start_selection,
00415 int *end_selection,
00416 void *gui_data)
00417 {
00418 DateCell *cell = (DateCell *) bcell;
00419 PopBox *box = cell->cell.gui_private;
00420 GdkEventKey *event = gui_data;
00421 char buff[DATE_BUF];
00422
00423 if (!gnc_handle_date_accelerator (event, &(box->date), bcell->value))
00424 return FALSE;
00425
00426 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00427 box->date.tm_mday,
00428 box->date.tm_mon + 1,
00429 box->date.tm_year + 1900);
00430
00431 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00432
00433 *start_selection = 0;
00434 *end_selection = -1;
00435
00436 if (!box->date_picker)
00437 return TRUE;
00438
00439 block_picker_signals (cell);
00440 gnc_date_picker_set_date (box->date_picker,
00441 box->date.tm_mday,
00442 box->date.tm_mon,
00443 box->date.tm_year + 1900);
00444 unblock_picker_signals (cell);
00445
00446 return TRUE;
00447 }
00448
00449 static void
00450 gnc_date_cell_modify_verify (BasicCell *_cell,
00451 const char *change,
00452 int change_len,
00453 const char *newval,
00454 int newval_len,
00455 int *cursor_position,
00456 int *start_selection,
00457 int *end_selection)
00458 {
00459 DateCell *cell = (DateCell *) _cell;
00460 PopBox *box = cell->cell.gui_private;
00461 gboolean accept = FALSE;
00462
00463 if (box->in_date_select)
00464 {
00465 gnc_basic_cell_set_value (_cell, newval);
00466 return;
00467 }
00468
00469
00470 if (change == NULL)
00471 accept = TRUE;
00472 else if (change_len == 0)
00473 accept = TRUE;
00474 else
00475 {
00476 int count = 0;
00477 unsigned char separator = dateSeparator ();
00478 gboolean ok = TRUE;
00479 const gchar *c;
00480 gunichar uc;
00481
00482
00483
00484
00485 c = change;
00486 while (*c)
00487 {
00488 uc = g_utf8_get_char (c);
00489
00490 if (!g_unichar_isdigit (uc) && (separator != uc))
00491 ok = FALSE;
00492
00493 if (separator == uc)
00494 count++;
00495
00496 c = g_utf8_next_char (c);
00497 }
00498
00499 c = _cell->value;
00500 while (*c)
00501 {
00502 uc = g_utf8_get_char (c);
00503
00504 if (separator == uc)
00505 count++;
00506
00507 c = g_utf8_next_char (c);
00508 }
00509
00510 if (2 < count)
00511 ok = FALSE;
00512
00513 if (ok)
00514 accept = TRUE;
00515 }
00516
00517
00518 if (accept)
00519 {
00520
00521 gnc_basic_cell_set_value_internal (&cell->cell, newval);
00522 gnc_parse_date (&(box->date), newval);
00523
00524 if (!box->date_picker)
00525 return;
00526
00527 block_picker_signals (cell);
00528 gnc_date_picker_set_date (box->date_picker,
00529 box->date.tm_mday,
00530 box->date.tm_mon,
00531 box->date.tm_year + 1900);
00532 unblock_picker_signals (cell);
00533 }
00534 }
00535
00536 static void
00537 gnc_date_cell_realize (BasicCell *bcell, gpointer data)
00538 {
00539 GnucashSheet *sheet = data;
00540 GnomeCanvasItem *item = sheet->item_editor;
00541 GncItemEdit *item_edit = GNC_ITEM_EDIT (item);
00542 DateCell *cell = (DateCell *) bcell;
00543 PopBox *box = cell->cell.gui_private;
00544
00545
00546 box->sheet = sheet;
00547 box->item_edit = item_edit;
00548 box->date_picker = gnc_item_edit_new_date_picker (box->item_edit);
00549 g_object_ref (box->date_picker);
00550 gtk_object_sink (GTK_OBJECT(box->date_picker));
00551
00552
00553 cell->cell.gui_realize = NULL;
00554 cell->cell.gui_move = gnc_date_cell_move;
00555 cell->cell.enter_cell = gnc_date_cell_enter;
00556 cell->cell.leave_cell = gnc_date_cell_leave;
00557 }
00558
00559 static void
00560 gnc_date_cell_move (BasicCell *bcell)
00561 {
00562 PopBox *box = bcell->gui_private;
00563
00564 date_picker_disconnect_signals ((DateCell *) bcell);
00565
00566 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
00567 NULL, NULL, NULL, NULL, NULL);
00568
00569 box->calendar_popped = FALSE;
00570 }
00571
00572 static int
00573 get_popup_height (GnomeCanvasItem *item,
00574 int space_available,
00575 int row_height,
00576 gpointer user_data)
00577 {
00578 GtkWidget *cal = GTK_WIDGET (GNC_DATE_PICKER (item)->calendar);
00579 GtkRequisition req;
00580
00581 req.height = 0;
00582 req.width = 0;
00583
00584 gtk_widget_size_request (cal, &req);
00585
00586 return req.height;
00587 }
00588
00589 static void
00590 popup_set_focus (GnomeCanvasItem *item,
00591 gpointer user_data)
00592 {
00593 gtk_widget_grab_focus (GTK_WIDGET (GNC_DATE_PICKER (item)->calendar));
00594 }
00595
00596 static gboolean
00597 gnc_date_cell_enter (BasicCell *bcell,
00598 int *cursor_position,
00599 int *start_selection,
00600 int *end_selection)
00601 {
00602 DateCell *cell = (DateCell *) bcell;
00603 PopBox *box = bcell->gui_private;
00604
00605 gnc_item_edit_set_popup (box->item_edit, GNOME_CANVAS_ITEM (box->date_picker),
00606 get_popup_height, NULL, popup_set_focus,
00607 NULL, NULL, NULL);
00608
00609 block_picker_signals (cell);
00610 gnc_date_picker_set_date (box->date_picker,
00611 box->date.tm_mday,
00612 box->date.tm_mon,
00613 box->date.tm_year + 1900);
00614 unblock_picker_signals (cell);
00615
00616 date_picker_connect_signals ((DateCell *) bcell);
00617
00618 *start_selection = 0;
00619 *end_selection = -1;
00620
00621 return TRUE;
00622 }
00623
00624 static void
00625 gnc_date_cell_leave (BasicCell *bcell)
00626 {
00627 Timespec ts;
00628 PopBox *box = bcell->gui_private;
00629
00630 date_picker_disconnect_signals ((DateCell *) bcell);
00631
00632 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
00633 NULL, NULL, NULL, NULL, NULL);
00634
00635 box->calendar_popped = FALSE;
00636
00637
00638 gnc_date_cell_get_date ((DateCell *)bcell, &ts);
00639 gnc_date_cell_set_value_secs ((DateCell *)bcell, ts.tv_sec);
00640 }
00641
00642 void
00643 gnc_date_cell_get_date (DateCell *cell, Timespec *ts)
00644 {
00645 PopBox *box = cell->cell.gui_private;
00646
00647 if (!cell || !ts)
00648 return;
00649
00650 gnc_parse_date (&(box->date), cell->cell.value);
00651
00652 ts->tv_sec = mktime (&box->date);
00653 ts->tv_nsec = 0;
00654 }
00655
00656 static void
00657 gnc_date_cell_set_value_internal (BasicCell *_cell, const char *str)
00658 {
00659 DateCell *cell = (DateCell *) _cell;
00660 PopBox *box = cell->cell.gui_private;
00661 char buff[DATE_BUF];
00662
00663 gnc_parse_date (&(box->date), str);
00664
00665 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00666 box->date.tm_mday,
00667 box->date.tm_mon + 1,
00668 box->date.tm_year + 1900);
00669
00670 gnc_basic_cell_set_value_internal (_cell, buff);
00671
00672 if (!box->date_picker)
00673 return;
00674
00675 block_picker_signals (cell);
00676 gnc_date_picker_set_date (box->date_picker,
00677 box->date.tm_mday,
00678 box->date.tm_mon,
00679 box->date.tm_year + 1900);
00680 unblock_picker_signals (cell);
00681 }