GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
datecell-gnome.c
1 /********************************************************************\
2  * datecell-gnome.c -- implement date cell handler in 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 [email protected] *
20  * *
21 \********************************************************************/
22 
23 /*
24  * FILE: datecell-gnome.c
25  *
26  * FUNCTION: Implement gnome portion of datecell widget
27  * embedded in a table cell.
28  *
29  * HISTORY:
30  * Copyright (c) 2000 Dave Peticolas <[email protected]>
31  */
32 
33 #include "config.h"
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39 #include <gdk/gdkkeysyms.h>
40 
41 #include "datecell.h"
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"
47 #include "gnucash-sheetP.h"
48 
49 
50 #define DATE_BUF (MAX_DATE_LENGTH+1)
51 
52 typedef struct _PopBox
53 {
54  GnucashSheet *sheet;
55  GncItemEdit *item_edit;
56  GNCDatePicker *date_picker;
57 
58  gboolean signals_connected; /* date picker signals connected? */
59  gboolean calendar_popped; /* calendar is popped up? */
60  gboolean in_date_select;
61 
62  struct tm date;
63 } PopBox;
64 
65 
66 static void block_picker_signals (DateCell *cell);
67 static void unblock_picker_signals (DateCell *cell);
68 static void gnc_date_cell_realize (BasicCell *bcell, gpointer w);
69 static void gnc_date_cell_set_value_internal (BasicCell *bcell,
70  const char *value);
71 static void gnc_date_cell_move (BasicCell *bcell);
72 static void gnc_date_cell_gui_destroy (BasicCell *bcell);
73 static void gnc_date_cell_destroy (BasicCell *bcell);
74 static void gnc_date_cell_modify_verify (BasicCell *_cell,
75  const char *change,
76  int change_len,
77  const char *newval,
78  int newval_len,
79  int *cursor_position,
80  int *start_selection,
81  int *end_selection);
82 static gboolean gnc_date_cell_direct_update (BasicCell *bcell,
83  int *cursor_position,
84  int *start_selection,
85  int *end_selection,
86  void *gui_data);
87 static gboolean gnc_date_cell_enter (BasicCell *bcell,
88  int *cursor_position,
89  int *start_selection,
90  int *end_selection);
91 static void gnc_date_cell_leave (BasicCell *bcell);
92 
93 static gboolean
94 check_readonly_threshold (const gchar *datestr, GDate *d)
95 {
96  GDate *readonly_threshold = qof_book_get_autoreadonly_gdate(gnc_get_current_book());
97  if (g_date_compare(d, readonly_threshold) < 0)
98  {
99 #if 0
100  gchar *dialog_msg = _("The entered date of the new transaction is "
101  "older than the \"Read-Only Threshold\" set for "
102  "this book. This setting can be changed in "
103  "File -> Properties -> Accounts.");
104  gchar *dialog_title = _("Cannot store a transaction at this date");
105  GtkWidget *dialog = gtk_message_dialog_new(NULL,
106  0,
107  GTK_MESSAGE_ERROR,
108  GTK_BUTTONS_OK,
109  "%s", dialog_title);
110  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
111  "%s", dialog_msg);
112  gtk_dialog_run(GTK_DIALOG(dialog));
113  gtk_widget_destroy(dialog);
114 #endif
115  g_warning("Entered date %s is before the \"auto-read-only threshold\";"
116  " resetting to the threshold.", datestr);
117 
118  // Reset the date to the threshold date
119  g_date_set_julian (d, g_date_get_julian (readonly_threshold));
120  g_date_free (readonly_threshold);
121  return TRUE;
122  }
123  g_date_free (readonly_threshold);
124  return FALSE;
125 }
126 
127 static void
128 gnc_parse_date (struct tm *parsed, const char * datestr)
129 {
130  int day, month, year;
131  gboolean use_autoreadonly = qof_book_uses_autoreadonly(gnc_get_current_book());
132 
133  if (!parsed) return;
134  if (!datestr) return;
135 
136  if (!qof_scan_date (datestr, &day, &month, &year))
137  {
138  // Couldn't parse date, use today
139  struct tm tm_today;
140 
141  memset (&tm_today, 0, sizeof (struct tm));
142  gnc_tm_get_today_start (&tm_today);
143  day = tm_today.tm_mday;
144  month = tm_today.tm_mon + 1;
145  year = tm_today.tm_year + 1900;
146  }
147 
148  // If we have an auto-read-only threshold, do not accept a date that is
149  // older than the threshold.
150  if (use_autoreadonly)
151  {
152  GDate *d = g_date_new_dmy(day, month, year);
153  if (check_readonly_threshold (datestr, d))
154  {
155  day = g_date_get_day (d);
156  month = g_date_get_month (d);
157  year = g_date_get_year (d);
158  }
159  g_date_free (d);
160  }
161 
162  parsed->tm_mday = day;
163  parsed->tm_mon = month - 1;
164  parsed->tm_year = year - 1900;
165 
166  gnc_tm_set_day_start(parsed);
167  /* Using gnc_mktime purely for its side effect of filling in the
168  * rest of parsed and to check that it's valid.
169  */
170  if (gnc_mktime (parsed) == -1)
171  gnc_tm_get_today_start (parsed);
172  gnc_mktime (parsed);
173 }
174 
175 static void
176 gnc_date_cell_print_date (DateCell *cell, char *buff)
177 {
178  PopBox *box = cell->cell.gui_private;
179 
181  box->date.tm_mday,
182  box->date.tm_mon + 1,
183  box->date.tm_year + 1900);
184 }
185 
186 static void
187 gnc_date_cell_init (DateCell *cell)
188 {
189  PopBox *box;
190  time64 secs;
191  char buff[DATE_BUF];
192 
193  gnc_basic_cell_init (&(cell->cell));
194 
195  cell->cell.is_popup = TRUE;
196 
197  cell->cell.destroy = gnc_date_cell_destroy;
198 
199  cell->cell.gui_realize = gnc_date_cell_realize;
200  cell->cell.gui_destroy = gnc_date_cell_gui_destroy;
201  cell->cell.modify_verify = gnc_date_cell_modify_verify;
202  cell->cell.direct_update = gnc_date_cell_direct_update;
203  cell->cell.set_value = gnc_date_cell_set_value_internal;
204 
205  box = g_new0 (PopBox, 1);
206 
207  box->sheet = NULL;
208  box->item_edit = NULL;
209  box->date_picker = NULL;
210 
211  box->signals_connected = FALSE;
212  box->calendar_popped = FALSE;
213  box->in_date_select = FALSE;
214 
215  cell->cell.gui_private = box;
216 
217  /* default value is today's date */
218  gnc_time (&secs);
219  gnc_localtime_r (&secs, &(box->date));
220  gnc_date_cell_print_date (cell, buff);
221 
222  gnc_basic_cell_set_value_internal (&cell->cell, buff);
223 }
224 
225 BasicCell *
226 gnc_date_cell_new (void)
227 {
228  DateCell *cell;
229 
230  cell = g_new0 (DateCell, 1);
231 
232  gnc_date_cell_init (cell);
233 
234  return &cell->cell;
235 }
236 
237 static void
238 date_picked_cb (GNCDatePicker *gdp, gpointer data)
239 {
240  DateCell *cell = data;
241  PopBox *box = cell->cell.gui_private;
242  guint day, month, year;
243  char buffer[DATE_BUF];
244 
245  gtk_calendar_get_date (gdp->calendar, &year, &month, &day);
246 
247  qof_print_date_dmy_buff (buffer, MAX_DATE_LENGTH, day, month + 1, year);
248 
249  box->in_date_select = TRUE;
250  gnucash_sheet_modify_current_cell (box->sheet, buffer);
251  box->in_date_select = FALSE;
252 
253  gnc_item_edit_hide_popup (box->item_edit);
254  box->calendar_popped = FALSE;
255 }
256 
257 static void
258 date_selected_cb (GNCDatePicker *gdp, gpointer data)
259 {
260  DateCell *cell = data;
261  PopBox *box = cell->cell.gui_private;
262  guint day, month, year;
263  char buffer[DATE_BUF];
264 
265  gtk_calendar_get_date (gdp->calendar, &year, &month, &day);
266 
267  qof_print_date_dmy_buff (buffer, MAX_DATE_LENGTH, day, month + 1, year);
268 
269  box->in_date_select = TRUE;
270  gnucash_sheet_modify_current_cell (box->sheet, buffer);
271  box->in_date_select = FALSE;
272 }
273 
274 static void
275 key_press_item_cb (GNCDatePicker *gdp, GdkEventKey *event, gpointer data)
276 {
277  DateCell *cell = data;
278  PopBox *box = cell->cell.gui_private;
279 
280  switch (event->keyval)
281  {
282  case GDK_KEY_Escape:
283  gnc_item_edit_hide_popup (box->item_edit);
284  box->calendar_popped = FALSE;
285  break;
286 
287  default:
288  gtk_widget_event(GTK_WIDGET (box->sheet), (GdkEvent *) event);
289  break;
290  }
291 }
292 
293 static void
294 date_picker_disconnect_signals (DateCell *cell)
295 {
296  PopBox *box = cell->cell.gui_private;
297 
298  if (!box->signals_connected)
299  return;
300 
301  g_signal_handlers_disconnect_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
302  0, 0, NULL, NULL, cell);
303 
304  box->signals_connected = FALSE;
305 }
306 
307 static void
308 date_picker_connect_signals (DateCell *cell)
309 {
310  PopBox *box = cell->cell.gui_private;
311 
312  if (box->signals_connected)
313  return;
314 
315  g_signal_connect (box->date_picker, "date_selected",
316  G_CALLBACK(date_selected_cb), cell);
317 
318  g_signal_connect(box->date_picker, "date_picked",
319  G_CALLBACK(date_picked_cb), cell);
320 
321  g_signal_connect(box->date_picker, "key_press_event",
322  G_CALLBACK(key_press_item_cb), cell);
323 
324  box->signals_connected = TRUE;
325 }
326 
327 static void
328 block_picker_signals (DateCell *cell)
329 {
330  PopBox *box = cell->cell.gui_private;
331 
332  if (!box->signals_connected)
333  return;
334 
335  g_signal_handlers_block_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
336  0, 0, NULL, NULL, cell);
337 }
338 
339 static void
340 unblock_picker_signals (DateCell *cell)
341 {
342  PopBox *box = cell->cell.gui_private;
343 
344  if (!box->signals_connected)
345  return;
346 
347  g_signal_handlers_unblock_matched (box->date_picker, G_SIGNAL_MATCH_DATA,
348  0, 0, NULL, NULL, cell);
349 }
350 
351 static void
352 gnc_date_cell_gui_destroy (BasicCell *bcell)
353 {
354  PopBox *box = bcell->gui_private;
355  DateCell *cell = (DateCell *) bcell;
356 
357  if (cell->cell.gui_realize == NULL)
358  {
359  if (box != NULL && box->date_picker != NULL)
360  {
361  date_picker_disconnect_signals (cell);
362  g_object_unref (box->date_picker);
363  box->date_picker = NULL;
364  }
365 
366  /* allow the widget to be shown again */
367  cell->cell.gui_realize = gnc_date_cell_realize;
368  cell->cell.gui_move = NULL;
369  cell->cell.enter_cell = NULL;
370  cell->cell.leave_cell = NULL;
371  cell->cell.gui_destroy = NULL;
372  }
373 }
374 
375 static void
376 gnc_date_cell_destroy (BasicCell *bcell)
377 {
378  DateCell *cell = (DateCell *) bcell;
379  PopBox *box = cell->cell.gui_private;
380 
381  gnc_date_cell_gui_destroy (&(cell->cell));
382 
383  g_free (box);
384 
385  cell->cell.gui_private = NULL;
386  cell->cell.gui_realize = NULL;
387 }
388 
389 void
390 gnc_date_cell_set_value (DateCell *cell, int day, int mon, int year)
391 {
392  PopBox *box = cell->cell.gui_private;
393  struct tm dada;
394  char buff[DATE_BUF];
395 
396  dada.tm_mday = day;
397  dada.tm_mon = mon - 1;
398  dada.tm_year = year - 1900;
399 
400  gnc_tm_set_day_start(&dada);
401  gnc_mktime (&dada);
402 
403  box->date.tm_mday = dada.tm_mday;
404  box->date.tm_mon = dada.tm_mon;
405  box->date.tm_year = dada.tm_year;
406 
407  qof_print_date_dmy_buff (buff, MAX_DATE_LENGTH, dada.tm_mday, dada.tm_mon + 1, dada.tm_year + 1900);
408 
409  gnc_basic_cell_set_value_internal (&cell->cell, buff);
410 
411  if (!box->date_picker)
412  return;
413 
414  block_picker_signals (cell);
415  gnc_date_picker_set_date (box->date_picker, day, mon - 1, year);
416  unblock_picker_signals (cell);
417 }
418 
419 void
420 gnc_date_cell_set_value_secs (DateCell *cell, time64 secs)
421 {
422  PopBox *box = cell->cell.gui_private;
423  char buff[DATE_BUF];
424 
425  gnc_localtime_r (&secs, &(box->date));
426 
428  box->date.tm_mday,
429  box->date.tm_mon + 1,
430  box->date.tm_year + 1900);
431 
432  gnc_basic_cell_set_value_internal (&cell->cell, buff);
433 
434  if (!box->date_picker)
435  return;
436 
437  block_picker_signals (cell);
438  gnc_date_picker_set_date (box->date_picker,
439  box->date.tm_mday,
440  box->date.tm_mon,
441  box->date.tm_year + 1900);
442  unblock_picker_signals (cell);
443 }
444 
445 void
446 gnc_date_cell_commit (DateCell *cell)
447 {
448  PopBox *box = cell->cell.gui_private;
449  char buff[DATE_BUF];
450 
451  if (!cell)
452  return;
453 
454  gnc_parse_date (&(box->date), cell->cell.value);
455 
457  box->date.tm_mday,
458  box->date.tm_mon + 1,
459  box->date.tm_year + 1900);
460 
461  gnc_basic_cell_set_value_internal (&cell->cell, buff);
462 
463  if (!box->date_picker)
464  return;
465 
466  block_picker_signals (cell);
467  gnc_date_picker_set_date (box->date_picker,
468  box->date.tm_mday,
469  box->date.tm_mon,
470  box->date.tm_year + 1900);
471  unblock_picker_signals (cell);
472 }
473 
474 static gboolean
475 gnc_date_cell_direct_update (BasicCell *bcell,
476  int *cursor_position,
477  int *start_selection,
478  int *end_selection,
479  void *gui_data)
480 {
481  DateCell *cell = (DateCell *) bcell;
482  PopBox *box = cell->cell.gui_private;
483  GdkEventKey *event = gui_data;
484  char buff[DATE_BUF];
485 
486  if (!gnc_handle_date_accelerator (event, &(box->date), bcell->value))
487  return FALSE;
488 
490  box->date.tm_mday,
491  box->date.tm_mon + 1,
492  box->date.tm_year + 1900);
493 
494  gnc_basic_cell_set_value_internal (&cell->cell, buff);
495 
496  *start_selection = 0;
497  *end_selection = -1;
498 
499  if (!box->date_picker)
500  return TRUE;
501 
502  block_picker_signals (cell);
503  gnc_date_picker_set_date (box->date_picker,
504  box->date.tm_mday,
505  box->date.tm_mon,
506  box->date.tm_year + 1900);
507  unblock_picker_signals (cell);
508 
509  return TRUE;
510 }
511 
512 static void
513 gnc_date_cell_modify_verify (BasicCell *_cell,
514  const char *change,
515  int change_len,
516  const char *newval,
517  int newval_len,
518  int *cursor_position,
519  int *start_selection,
520  int *end_selection)
521 {
522  DateCell *cell = (DateCell *) _cell;
523  PopBox *box = cell->cell.gui_private;
524  gboolean accept = FALSE;
525 
526  if (box->in_date_select)
527  {
528  gnc_basic_cell_set_value (_cell, newval);
529  return;
530  }
531 
532  /* if user hit backspace, accept the change */
533  if (change == NULL)
534  accept = TRUE;
535  else if (change_len == 0)
536  accept = TRUE;
537  else
538  {
539  int count = 0;
540  unsigned char separator = dateSeparator ();
541  gboolean ok = TRUE;
542  const gchar *c;
543  gunichar uc;
544 
545  /* accept only numbers or a date separator. Note that the
546  * separator of '-' (for DATE_FORMAT_ISO) takes precedence
547  * over the accelerator below! */
548  c = change;
549  while (*c)
550  {
551  uc = g_utf8_get_char (c);
552 
553  if (!g_unichar_isdigit (uc) && (separator != uc))
554  ok = FALSE;
555 
556  if (separator == uc)
557  count++;
558 
559  c = g_utf8_next_char (c);
560  }
561 
562  c = _cell->value;
563  while (*c)
564  {
565  uc = g_utf8_get_char (c);
566 
567  if (separator == uc)
568  count++;
569 
570  c = g_utf8_next_char (c);
571  }
572 
573  if (2 < count)
574  ok = FALSE;
575 
576  if (ok)
577  accept = TRUE;
578  }
579 
580  /* keep a copy of the new value */
581  if (accept)
582  {
583 
584  gnc_basic_cell_set_value_internal (&cell->cell, newval);
585  gnc_parse_date (&(box->date), newval);
586 
587  if (!box->date_picker)
588  return;
589 
590  block_picker_signals (cell);
591  gnc_date_picker_set_date (box->date_picker,
592  box->date.tm_mday,
593  box->date.tm_mon,
594  box->date.tm_year + 1900);
595  unblock_picker_signals (cell);
596  }
597 }
598 
599 static void
600 gnc_date_cell_realize (BasicCell *bcell, gpointer data)
601 {
602  GnucashSheet *sheet = data;
603  GncItemEdit *item_edit = gnucash_sheet_get_item_edit (sheet);
604  DateCell *cell = (DateCell *) bcell;
605  PopBox *box = cell->cell.gui_private;
606 
607  /* initialize gui-specific, private data */
608  box->sheet = sheet;
609  box->item_edit = item_edit;
610  box->date_picker = gnc_item_edit_new_date_picker (box->item_edit);
611  g_object_ref_sink(box->date_picker);
612 
613  /* to mark cell as realized, remove the realize method */
614  cell->cell.gui_realize = NULL;
615  cell->cell.gui_move = gnc_date_cell_move;
616  cell->cell.enter_cell = gnc_date_cell_enter;
617  cell->cell.leave_cell = gnc_date_cell_leave;
618 }
619 
620 static void
621 gnc_date_cell_move (BasicCell *bcell)
622 {
623  PopBox *box = bcell->gui_private;
624 
625  date_picker_disconnect_signals ((DateCell *) bcell);
626 
627  gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
628  NULL, NULL, NULL, NULL, NULL);
629 
630  box->calendar_popped = FALSE;
631 }
632 
633 static int
634 get_popup_height (GnomeCanvasItem *item,
635  int space_available,
636  int row_height,
637  gpointer user_data)
638 {
639  GtkWidget *cal = GTK_WIDGET (GNC_DATE_PICKER (item)->calendar);
640  GtkRequisition req;
641 
642  req.height = 0;
643  req.width = 0;
644 
645  gtk_widget_size_request (cal, &req);
646 
647  return req.height;
648 }
649 
650 static void
651 popup_set_focus (GnomeCanvasItem *item,
652  gpointer user_data)
653 {
654  gtk_widget_grab_focus (GTK_WIDGET (GNC_DATE_PICKER (item)->calendar));
655 }
656 
657 static gboolean
658 gnc_date_cell_enter (BasicCell *bcell,
659  int *cursor_position,
660  int *start_selection,
661  int *end_selection)
662 {
663  DateCell *cell = (DateCell *) bcell;
664  PopBox *box = bcell->gui_private;
665 
666  gnc_item_edit_set_popup (box->item_edit, GNOME_CANVAS_ITEM (box->date_picker),
667  get_popup_height, NULL, popup_set_focus,
668  NULL, NULL, NULL);
669 
670  block_picker_signals (cell);
671  gnc_date_picker_set_date (box->date_picker,
672  box->date.tm_mday,
673  box->date.tm_mon,
674  box->date.tm_year + 1900);
675  unblock_picker_signals (cell);
676 
677  date_picker_connect_signals ((DateCell *) bcell);
678 
679  *start_selection = 0;
680  *end_selection = -1;
681 
682  return TRUE;
683 }
684 
685 static void
686 gnc_date_cell_leave (BasicCell *bcell)
687 {
688  Timespec ts;
689  PopBox *box = bcell->gui_private;
690 
691  date_picker_disconnect_signals ((DateCell *) bcell);
692 
693  gnc_item_edit_set_popup (box->item_edit, NULL, NULL,
694  NULL, NULL, NULL, NULL, NULL);
695 
696  box->calendar_popped = FALSE;
697 
698  /* Refresh the date to expand any shortcuts. */
699  gnc_date_cell_get_date ((DateCell *)bcell, &ts);
700  gnc_date_cell_set_value_secs ((DateCell *)bcell, ts.tv_sec);
701 }
702 
703 void
704 gnc_date_cell_get_date_gdate (DateCell *cell, GDate *date)
705 {
706  PopBox *box = cell->cell.gui_private;
707 
708  if (!cell || !date)
709  return;
710 
711  gnc_parse_date (&(box->date), cell->cell.value);
712 
713  g_date_set_dmy(date,
714  box->date.tm_mday,
715  box->date.tm_mon + 1,
716  box->date.tm_year + 1900);
717 }
718 
719 void
720 gnc_date_cell_get_date (DateCell *cell, Timespec *ts)
721 {
722  PopBox *box = cell->cell.gui_private;
723 
724  if (!cell || !ts)
725  return;
726 
727  gnc_parse_date (&(box->date), cell->cell.value);
728 
729  ts->tv_sec = gnc_mktime (&box->date);
730  ts->tv_nsec = 0;
731 }
732 
733 static void
734 gnc_date_cell_set_value_internal (BasicCell *_cell, const char *str)
735 {
736  DateCell *cell = (DateCell *) _cell;
737  PopBox *box = cell->cell.gui_private;
738  char buff[DATE_BUF];
739 
740  gnc_parse_date (&(box->date), str);
741 
743  box->date.tm_mday,
744  box->date.tm_mon + 1,
745  box->date.tm_year + 1900);
746 
747  gnc_basic_cell_set_value_internal (_cell, buff);
748 
749  if (!box->date_picker)
750  return;
751 
752  block_picker_signals (cell);
753  gnc_date_picker_set_date (box->date_picker,
754  box->date.tm_mday,
755  box->date.tm_mon,
756  box->date.tm_year + 1900);
757  unblock_picker_signals (cell);
758 }
utility functions for the GnuCash UI
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
gchar dateSeparator(void)
struct tm * gnc_localtime_r(const time64 *secs, struct tm *time)
fill out a time struct from a 64-bit time value adjusted for the current time zone.
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
#define MAX_DATE_LENGTH
Definition: gnc-date.h:106
void gnc_tm_get_today_start(struct tm *tm)
size_t qof_print_date_dmy_buff(gchar *buff, size_t buflen, int day, int month, int year)
gboolean qof_scan_date(const char *buff, int *day, int *month, int *year)
time64 gnc_time(time64 *tbuf)
get the current local time
gint64 time64
Definition: gnc-date.h:83
gboolean qof_book_uses_autoreadonly(const QofBook *book)