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 (MAX_DATE_LENGTH+1)
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 g_signal_handlers_disconnect_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
00240 0, 0, NULL, NULL, cell);
00241
00242 box->signals_connected = FALSE;
00243 }
00244
00245 static void
00246 date_picker_connect_signals (DateCell *cell)
00247 {
00248 PopBox *box = cell->cell.gui_private;
00249
00250 if (box->signals_connected)
00251 return;
00252
00253 g_signal_connect (box->date_picker, "date_selected",
00254 G_CALLBACK(date_selected_cb), cell);
00255
00256 g_signal_connect(box->date_picker, "date_picked",
00257 G_CALLBACK(date_picked_cb), cell);
00258
00259 g_signal_connect(box->date_picker, "key_press_event",
00260 G_CALLBACK(key_press_item_cb), cell);
00261
00262 box->signals_connected = TRUE;
00263 }
00264
00265 static void
00266 block_picker_signals (DateCell *cell)
00267 {
00268 PopBox *box = cell->cell.gui_private;
00269
00270 if (!box->signals_connected)
00271 return;
00272
00273 g_signal_handlers_block_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
00274 0, 0, NULL, NULL, cell);
00275 }
00276
00277 static void
00278 unblock_picker_signals (DateCell *cell)
00279 {
00280 PopBox *box = cell->cell.gui_private;
00281
00282 if (!box->signals_connected)
00283 return;
00284
00285 g_signal_handlers_unblock_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
00286 0, 0, NULL, NULL, cell);
00287 }
00288
00289 static void
00290 gnc_date_cell_gui_destroy (BasicCell *bcell)
00291 {
00292 PopBox *box = bcell->gui_private;
00293 DateCell *cell = (DateCell *) bcell;
00294
00295 if (cell->cell.gui_realize == NULL)
00296 {
00297 if (box != NULL && box->date_picker != NULL)
00298 {
00299 date_picker_disconnect_signals (cell);
00300 g_object_unref (box->date_picker);
00301 box->date_picker = NULL;
00302 }
00303
00304
00305 cell->cell.gui_realize = gnc_date_cell_realize;
00306 cell->cell.gui_move = NULL;
00307 cell->cell.enter_cell = NULL;
00308 cell->cell.leave_cell = NULL;
00309 cell->cell.gui_destroy = NULL;
00310 }
00311 }
00312
00313 static void
00314 gnc_date_cell_destroy (BasicCell *bcell)
00315 {
00316 DateCell *cell = (DateCell *) bcell;
00317 PopBox *box = cell->cell.gui_private;
00318
00319 gnc_date_cell_gui_destroy (&(cell->cell));
00320
00321 g_free (box);
00322
00323 cell->cell.gui_private = NULL;
00324 cell->cell.gui_realize = NULL;
00325 }
00326
00327 void
00328 gnc_date_cell_set_value (DateCell *cell, int day, int mon, int year)
00329 {
00330 PopBox *box = cell->cell.gui_private;
00331 struct tm dada;
00332 char buff[DATE_BUF];
00333
00334 dada.tm_mday = day;
00335 dada.tm_mon = mon - 1;
00336 dada.tm_year = year - 1900;
00337
00338 gnc_tm_set_day_start(&dada);
00339 mktime (&dada);
00340
00341 box->date.tm_mday = dada.tm_mday;
00342 box->date.tm_mon = dada.tm_mon;
00343 box->date.tm_year = dada.tm_year;
00344
00345 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH, dada.tm_mday, dada.tm_mon + 1, dada.tm_year + 1900);
00346
00347 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00348
00349 if (!box->date_picker)
00350 return;
00351
00352 block_picker_signals (cell);
00353 gnc_date_picker_set_date (box->date_picker, day, mon - 1, year);
00354 unblock_picker_signals (cell);
00355 }
00356
00357 void
00358 gnc_date_cell_set_value_secs (DateCell *cell, time_t secs)
00359 {
00360 PopBox *box = cell->cell.gui_private;
00361 char buff[DATE_BUF];
00362 struct tm * stm;
00363
00364 stm = localtime (&secs);
00365 box->date = *stm;
00366
00367 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00368 box->date.tm_mday,
00369 box->date.tm_mon + 1,
00370 box->date.tm_year + 1900);
00371
00372 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00373
00374 if (!box->date_picker)
00375 return;
00376
00377 block_picker_signals (cell);
00378 gnc_date_picker_set_date (box->date_picker,
00379 box->date.tm_mday,
00380 box->date.tm_mon,
00381 box->date.tm_year + 1900);
00382 unblock_picker_signals (cell);
00383 }
00384
00385 void
00386 gnc_date_cell_commit (DateCell *cell)
00387 {
00388 PopBox *box = cell->cell.gui_private;
00389 char buff[DATE_BUF];
00390
00391 if (!cell)
00392 return;
00393
00394 gnc_parse_date (&(box->date), cell->cell.value);
00395
00396 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00397 box->date.tm_mday,
00398 box->date.tm_mon + 1,
00399 box->date.tm_year + 1900);
00400
00401 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00402
00403 if (!box->date_picker)
00404 return;
00405
00406 block_picker_signals (cell);
00407 gnc_date_picker_set_date (box->date_picker,
00408 box->date.tm_mday,
00409 box->date.tm_mon,
00410 box->date.tm_year + 1900);
00411 unblock_picker_signals (cell);
00412 }
00413
00414 static gboolean
00415 gnc_date_cell_direct_update (BasicCell *bcell,
00416 int *cursor_position,
00417 int *start_selection,
00418 int *end_selection,
00419 void *gui_data)
00420 {
00421 DateCell *cell = (DateCell *) bcell;
00422 PopBox *box = cell->cell.gui_private;
00423 GdkEventKey *event = gui_data;
00424 char buff[DATE_BUF];
00425
00426 if (!gnc_handle_date_accelerator (event, &(box->date), bcell->value))
00427 return FALSE;
00428
00429 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00430 box->date.tm_mday,
00431 box->date.tm_mon + 1,
00432 box->date.tm_year + 1900);
00433
00434 gnc_basic_cell_set_value_internal (&cell->cell, buff);
00435
00436 *start_selection = 0;
00437 *end_selection = -1;
00438
00439 if (!box->date_picker)
00440 return TRUE;
00441
00442 block_picker_signals (cell);
00443 gnc_date_picker_set_date (box->date_picker,
00444 box->date.tm_mday,
00445 box->date.tm_mon,
00446 box->date.tm_year + 1900);
00447 unblock_picker_signals (cell);
00448
00449 return TRUE;
00450 }
00451
00452 static void
00453 gnc_date_cell_modify_verify (BasicCell *_cell,
00454 const char *change,
00455 int change_len,
00456 const char *newval,
00457 int newval_len,
00458 int *cursor_position,
00459 int *start_selection,
00460 int *end_selection)
00461 {
00462 DateCell *cell = (DateCell *) _cell;
00463 PopBox *box = cell->cell.gui_private;
00464 gboolean accept = FALSE;
00465
00466 if (box->in_date_select)
00467 {
00468 gnc_basic_cell_set_value (_cell, newval);
00469 return;
00470 }
00471
00472
00473 if (change == NULL)
00474 accept = TRUE;
00475 else if (change_len == 0)
00476 accept = TRUE;
00477 else
00478 {
00479 int count = 0;
00480 unsigned char separator = dateSeparator ();
00481 gboolean ok = TRUE;
00482 const gchar *c;
00483 gunichar uc;
00484
00485
00486
00487
00488 c = change;
00489 while (*c)
00490 {
00491 uc = g_utf8_get_char (c);
00492
00493 if (!g_unichar_isdigit (uc) && (separator != uc))
00494 ok = FALSE;
00495
00496 if (separator == uc)
00497 count++;
00498
00499 c = g_utf8_next_char (c);
00500 }
00501
00502 c = _cell->value;
00503 while (*c)
00504 {
00505 uc = g_utf8_get_char (c);
00506
00507 if (separator == uc)
00508 count++;
00509
00510 c = g_utf8_next_char (c);
00511 }
00512
00513 if (2 < count)
00514 ok = FALSE;
00515
00516 if (ok)
00517 accept = TRUE;
00518 }
00519
00520
00521 if (accept)
00522 {
00523
00524 gnc_basic_cell_set_value_internal (&cell->cell, newval);
00525 gnc_parse_date (&(box->date), newval);
00526
00527 if (!box->date_picker)
00528 return;
00529
00530 block_picker_signals (cell);
00531 gnc_date_picker_set_date (box->date_picker,
00532 box->date.tm_mday,
00533 box->date.tm_mon,
00534 box->date.tm_year + 1900);
00535 unblock_picker_signals (cell);
00536 }
00537 }
00538
00539 static void
00540 gnc_date_cell_realize (BasicCell *bcell, gpointer data)
00541 {
00542 GnucashSheet *sheet = data;
00543 GnomeCanvasItem *item = sheet->item_editor;
00544 GncItemEdit *item_edit = GNC_ITEM_EDIT (item);
00545 DateCell *cell = (DateCell *) bcell;
00546 PopBox *box = cell->cell.gui_private;
00547
00548
00549 box->sheet = sheet;
00550 box->item_edit = item_edit;
00551 box->date_picker = gnc_item_edit_new_date_picker (box->item_edit);
00552 g_object_ref_sink(box->date_picker);
00553
00554
00555 cell->cell.gui_realize = NULL;
00556 cell->cell.gui_move = gnc_date_cell_move;
00557 cell->cell.enter_cell = gnc_date_cell_enter;
00558 cell->cell.leave_cell = gnc_date_cell_leave;
00559 }
00560
00561 static void
00562 gnc_date_cell_move (BasicCell *bcell)
00563 {
00564 PopBox *box = bcell->gui_private;
00565
00566 date_picker_disconnect_signals ((DateCell *) bcell);
00567
00568 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
00569 NULL, NULL, NULL, NULL, NULL);
00570
00571 box->calendar_popped = FALSE;
00572 }
00573
00574 static int
00575 get_popup_height (GnomeCanvasItem *item,
00576 int space_available,
00577 int row_height,
00578 gpointer user_data)
00579 {
00580 GtkWidget *cal = GTK_WIDGET (GNC_DATE_PICKER (item)->calendar);
00581 GtkRequisition req;
00582
00583 req.height = 0;
00584 req.width = 0;
00585
00586 gtk_widget_size_request (cal, &req);
00587
00588 return req.height;
00589 }
00590
00591 static void
00592 popup_set_focus (GnomeCanvasItem *item,
00593 gpointer user_data)
00594 {
00595 gtk_widget_grab_focus (GTK_WIDGET (GNC_DATE_PICKER (item)->calendar));
00596 }
00597
00598 static gboolean
00599 gnc_date_cell_enter (BasicCell *bcell,
00600 int *cursor_position,
00601 int *start_selection,
00602 int *end_selection)
00603 {
00604 DateCell *cell = (DateCell *) bcell;
00605 PopBox *box = bcell->gui_private;
00606
00607 gnc_item_edit_set_popup (box->item_edit, GNOME_CANVAS_ITEM (box->date_picker),
00608 get_popup_height, NULL, popup_set_focus,
00609 NULL, NULL, NULL);
00610
00611 block_picker_signals (cell);
00612 gnc_date_picker_set_date (box->date_picker,
00613 box->date.tm_mday,
00614 box->date.tm_mon,
00615 box->date.tm_year + 1900);
00616 unblock_picker_signals (cell);
00617
00618 date_picker_connect_signals ((DateCell *) bcell);
00619
00620 *start_selection = 0;
00621 *end_selection = -1;
00622
00623 return TRUE;
00624 }
00625
00626 static void
00627 gnc_date_cell_leave (BasicCell *bcell)
00628 {
00629 Timespec ts;
00630 PopBox *box = bcell->gui_private;
00631
00632 date_picker_disconnect_signals ((DateCell *) bcell);
00633
00634 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
00635 NULL, NULL, NULL, NULL, NULL);
00636
00637 box->calendar_popped = FALSE;
00638
00639
00640 gnc_date_cell_get_date ((DateCell *)bcell, &ts);
00641 gnc_date_cell_set_value_secs ((DateCell *)bcell, ts.tv_sec);
00642 }
00643
00644 void
00645 gnc_date_cell_get_date_gdate (DateCell *cell, GDate *date)
00646 {
00647 PopBox *box = cell->cell.gui_private;
00648
00649 if (!cell || !date)
00650 return;
00651
00652 gnc_parse_date (&(box->date), cell->cell.value);
00653
00654 g_date_set_dmy(date,
00655 box->date.tm_mday,
00656 box->date.tm_mon + 1,
00657 box->date.tm_year + 1900);
00658 }
00659
00660 void
00661 gnc_date_cell_get_date (DateCell *cell, Timespec *ts)
00662 {
00663 PopBox *box = cell->cell.gui_private;
00664
00665 if (!cell || !ts)
00666 return;
00667
00668 gnc_parse_date (&(box->date), cell->cell.value);
00669
00670 ts->tv_sec = mktime (&box->date);
00671 ts->tv_nsec = 0;
00672 }
00673
00674 static void
00675 gnc_date_cell_set_value_internal (BasicCell *_cell, const char *str)
00676 {
00677 DateCell *cell = (DateCell *) _cell;
00678 PopBox *box = cell->cell.gui_private;
00679 char buff[DATE_BUF];
00680
00681 gnc_parse_date (&(box->date), str);
00682
00683 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00684 box->date.tm_mday,
00685 box->date.tm_mon + 1,
00686 box->date.tm_year + 1900);
00687
00688 gnc_basic_cell_set_value_internal (_cell, buff);
00689
00690 if (!box->date_picker)
00691 return;
00692
00693 block_picker_signals (cell);
00694 gnc_date_picker_set_date (box->date_picker,
00695 box->date.tm_mday,
00696 box->date.tm_mon,
00697 box->date.tm_year + 1900);
00698 unblock_picker_signals (cell);
00699 }