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 #ifdef HAVE_GTK_2_10
00553 g_object_ref_sink(box->date_picker);
00554 #else
00555 g_object_ref (box->date_picker);
00556 gtk_object_sink (GTK_OBJECT(box->date_picker));
00557 #endif
00558
00559
00560 cell->cell.gui_realize = NULL;
00561 cell->cell.gui_move = gnc_date_cell_move;
00562 cell->cell.enter_cell = gnc_date_cell_enter;
00563 cell->cell.leave_cell = gnc_date_cell_leave;
00564 }
00565
00566 static void
00567 gnc_date_cell_move (BasicCell *bcell)
00568 {
00569 PopBox *box = bcell->gui_private;
00570
00571 date_picker_disconnect_signals ((DateCell *) bcell);
00572
00573 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
00574 NULL, NULL, NULL, NULL, NULL);
00575
00576 box->calendar_popped = FALSE;
00577 }
00578
00579 static int
00580 get_popup_height (GnomeCanvasItem *item,
00581 int space_available,
00582 int row_height,
00583 gpointer user_data)
00584 {
00585 GtkWidget *cal = GTK_WIDGET (GNC_DATE_PICKER (item)->calendar);
00586 GtkRequisition req;
00587
00588 req.height = 0;
00589 req.width = 0;
00590
00591 gtk_widget_size_request (cal, &req);
00592
00593 return req.height;
00594 }
00595
00596 static void
00597 popup_set_focus (GnomeCanvasItem *item,
00598 gpointer user_data)
00599 {
00600 gtk_widget_grab_focus (GTK_WIDGET (GNC_DATE_PICKER (item)->calendar));
00601 }
00602
00603 static gboolean
00604 gnc_date_cell_enter (BasicCell *bcell,
00605 int *cursor_position,
00606 int *start_selection,
00607 int *end_selection)
00608 {
00609 DateCell *cell = (DateCell *) bcell;
00610 PopBox *box = bcell->gui_private;
00611
00612 gnc_item_edit_set_popup (box->item_edit, GNOME_CANVAS_ITEM (box->date_picker),
00613 get_popup_height, NULL, popup_set_focus,
00614 NULL, NULL, NULL);
00615
00616 block_picker_signals (cell);
00617 gnc_date_picker_set_date (box->date_picker,
00618 box->date.tm_mday,
00619 box->date.tm_mon,
00620 box->date.tm_year + 1900);
00621 unblock_picker_signals (cell);
00622
00623 date_picker_connect_signals ((DateCell *) bcell);
00624
00625 *start_selection = 0;
00626 *end_selection = -1;
00627
00628 return TRUE;
00629 }
00630
00631 static void
00632 gnc_date_cell_leave (BasicCell *bcell)
00633 {
00634 Timespec ts;
00635 PopBox *box = bcell->gui_private;
00636
00637 date_picker_disconnect_signals ((DateCell *) bcell);
00638
00639 gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
00640 NULL, NULL, NULL, NULL, NULL);
00641
00642 box->calendar_popped = FALSE;
00643
00644
00645 gnc_date_cell_get_date ((DateCell *)bcell, &ts);
00646 gnc_date_cell_set_value_secs ((DateCell *)bcell, ts.tv_sec);
00647 }
00648
00649 void
00650 gnc_date_cell_get_date (DateCell *cell, Timespec *ts)
00651 {
00652 PopBox *box = cell->cell.gui_private;
00653
00654 if (!cell || !ts)
00655 return;
00656
00657 gnc_parse_date (&(box->date), cell->cell.value);
00658
00659 ts->tv_sec = mktime (&box->date);
00660 ts->tv_nsec = 0;
00661 }
00662
00663 static void
00664 gnc_date_cell_set_value_internal (BasicCell *_cell, const char *str)
00665 {
00666 DateCell *cell = (DateCell *) _cell;
00667 PopBox *box = cell->cell.gui_private;
00668 char buff[DATE_BUF];
00669
00670 gnc_parse_date (&(box->date), str);
00671
00672 qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH,
00673 box->date.tm_mday,
00674 box->date.tm_mon + 1,
00675 box->date.tm_year + 1900);
00676
00677 gnc_basic_cell_set_value_internal (_cell, buff);
00678
00679 if (!box->date_picker)
00680 return;
00681
00682 block_picker_signals (cell);
00683 gnc_date_picker_set_date (box->date_picker,
00684 box->date.tm_mday,
00685 box->date.tm_mon,
00686 box->date.tm_year + 1900);
00687 unblock_picker_signals (cell);
00688 }