GnuCash  4.11-354-g0815ab64c1
qofbook.cpp
1 /********************************************************************\
2  * qofbook.c -- dataset access (set of books of entities) *
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 gnu@gnu.org *
20 \********************************************************************/
21 
22 /*
23  * FILE:
24  * qofbook.cpp
25  *
26  * FUNCTION:
27  * Encapsulate all the information about a QOF dataset.
28  *
29  * HISTORY:
30  * Created by Linas Vepstas December 1998
31  * Copyright (c) 1998-2001,2003 Linas Vepstas <linas@linas.org>
32  * Copyright (c) 2000 Dave Peticolas
33  * Copyright (c) 2007 David Hampton <hampton@employees.org>
34  */
35 #include <glib.h>
36 
37 extern "C"
38 {
39 
40 #include <config.h>
41 
42 #include <stdlib.h>
43 #include <string.h>
44 
45 #ifdef GNC_PLATFORM_WINDOWS
46  /* Mingw disables the standard type macros for C++ without this override. */
47 #define __STDC_FORMAT_MACROS = 1
48 #endif
49 #include <inttypes.h>
50 
51 }
52 
53 #include "qof.h"
54 #include "qofevent-p.h"
55 #include "qofbackend.h"
56 #include "qofbook-p.h"
57 #include "qofid-p.h"
58 #include "qofobject-p.h"
59 #include "qofbookslots.h"
60 #include "kvp-frame.hpp"
61 // For GNC_ID_ROOT_ACCOUNT:
62 #include "AccountP.h"
63 
64 static QofLogModule log_module = QOF_MOD_ENGINE;
65 #define AB_KEY "hbci"
66 #define AB_TEMPLATES "template-list"
67 
68 enum
69 {
70  PROP_0,
71 // PROP_ROOT_ACCOUNT, /* Table */
72 // PROP_ROOT_TEMPLATE, /* Table */
73  PROP_OPT_TRADING_ACCOUNTS, /* KVP */
74  PROP_OPT_AUTO_READONLY_DAYS, /* KVP */
75  PROP_OPT_NUM_FIELD_SOURCE, /* KVP */
76  PROP_OPT_DEFAULT_BUDGET, /* KVP */
77  PROP_OPT_FY_END, /* KVP */
78  PROP_AB_TEMPLATES, /* KVP */
79  N_PROPERTIES /* Just a counter */
80 };
81 
82 static void
83 qof_book_option_num_field_source_changed_cb (GObject *gobject,
84  GParamSpec *pspec,
85  gpointer user_data);
86 static void
87 qof_book_option_num_autoreadonly_changed_cb (GObject *gobject,
88  GParamSpec *pspec,
89  gpointer user_data);
90 
91 // Use a #define for the GParam name to avoid typos
92 #define PARAM_NAME_NUM_FIELD_SOURCE "split-action-num-field"
93 #define PARAM_NAME_NUM_AUTOREAD_ONLY "autoreadonly-days"
94 
95 G_DEFINE_TYPE(QofBook, qof_book, QOF_TYPE_INSTANCE);
96 QOF_GOBJECT_DISPOSE(qof_book);
97 QOF_GOBJECT_FINALIZE(qof_book);
98 
99 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
100 #undef G_PARAM_READWRITE
101 #define G_PARAM_READWRITE static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_WRITABLE)
102 /* ====================================================================== */
103 /* constructor / destructor */
104 
105 static void coll_destroy(gpointer col)
106 {
107  qof_collection_destroy((QofCollection *) col);
108 }
109 
110 static void
111 qof_book_init (QofBook *book)
112 {
113  if (!book) return;
114 
115  book->hash_of_collections = g_hash_table_new_full(
116  g_str_hash, g_str_equal,
117  (GDestroyNotify)qof_string_cache_remove, /* key_destroy_func */
118  coll_destroy); /* value_destroy_func */
119 
120  qof_instance_init_data (&book->inst, QOF_ID_BOOK, book);
121 
122  book->data_tables = g_hash_table_new (g_str_hash, g_str_equal);
123  book->data_table_finalizers = g_hash_table_new (g_str_hash, g_str_equal);
124 
125  book->book_open = 'y';
126  book->read_only = FALSE;
127  book->session_dirty = FALSE;
128  book->version = 0;
129  book->cached_num_field_source_isvalid = FALSE;
130  book->cached_num_days_autoreadonly_isvalid = FALSE;
131 
132  // Register a callback on this NUM_FIELD_SOURCE property of that object
133  // because it gets called quite a lot, so that its value must be stored in
134  // a bool member variable instead of a KVP lookup on each getter call.
135  g_signal_connect (G_OBJECT(book),
136  "notify::" PARAM_NAME_NUM_FIELD_SOURCE,
137  G_CALLBACK (qof_book_option_num_field_source_changed_cb),
138  book);
139 
140  // Register a callback on this NUM_AUTOREAD_ONLY property of that object
141  // because it gets called quite a lot, so that its value must be stored in
142  // a bool member variable instead of a KVP lookup on each getter call.
143  g_signal_connect (G_OBJECT(book),
144  "notify::" PARAM_NAME_NUM_AUTOREAD_ONLY,
145  G_CALLBACK (qof_book_option_num_autoreadonly_changed_cb),
146  book);
147 }
148 
149 static const std::string str_KVP_OPTION_PATH(KVP_OPTION_PATH);
150 static const std::string str_OPTION_SECTION_ACCOUNTS(OPTION_SECTION_ACCOUNTS);
151 static const std::string str_OPTION_SECTION_BUDGETING(OPTION_SECTION_BUDGETING);
152 static const std::string str_OPTION_NAME_DEFAULT_BUDGET(OPTION_NAME_DEFAULT_BUDGET);
153 static const std::string str_OPTION_NAME_TRADING_ACCOUNTS(OPTION_NAME_TRADING_ACCOUNTS);
154 static const std::string str_OPTION_NAME_AUTO_READONLY_DAYS(OPTION_NAME_AUTO_READONLY_DAYS);
155 static const std::string str_OPTION_NAME_NUM_FIELD_SOURCE(OPTION_NAME_NUM_FIELD_SOURCE);
156 
157 static void
158 qof_book_get_property (GObject* object,
159  guint prop_id,
160  GValue* value,
161  GParamSpec* pspec)
162 {
163  QofBook *book;
164  gchar *key;
165 
166  g_return_if_fail (QOF_IS_BOOK (object));
167  book = QOF_BOOK (object);
168  switch (prop_id)
169  {
170  case PROP_OPT_TRADING_ACCOUNTS:
171  qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
172  str_OPTION_SECTION_ACCOUNTS, str_OPTION_NAME_TRADING_ACCOUNTS});
173  break;
174  case PROP_OPT_AUTO_READONLY_DAYS:
175  qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
176  str_OPTION_SECTION_ACCOUNTS, str_OPTION_NAME_AUTO_READONLY_DAYS});
177  break;
178  case PROP_OPT_NUM_FIELD_SOURCE:
179  qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
180  str_OPTION_SECTION_ACCOUNTS, str_OPTION_NAME_NUM_FIELD_SOURCE});
181  break;
182  case PROP_OPT_DEFAULT_BUDGET:
183  qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
184  str_OPTION_SECTION_BUDGETING, str_OPTION_NAME_DEFAULT_BUDGET});
185  break;
186  case PROP_OPT_FY_END:
187  qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {"fy_end"});
188  break;
189  case PROP_AB_TEMPLATES:
190  qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {"AB_KEY", "AB_TEMPLATES"});
191  break;
192  default:
193  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
194  break;
195  }
196 }
197 
198 static void
199 qof_book_set_property (GObject *object,
200  guint prop_id,
201  const GValue *value,
202  GParamSpec *pspec)
203 {
204  QofBook *book;
205  gchar *key;
206 
207  g_return_if_fail (QOF_IS_BOOK (object));
208  book = QOF_BOOK (object);
209  g_assert (qof_instance_get_editlevel(book));
210 
211  switch (prop_id)
212  {
213  case PROP_OPT_TRADING_ACCOUNTS:
214  qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
215  str_OPTION_SECTION_ACCOUNTS, str_OPTION_NAME_TRADING_ACCOUNTS});
216  break;
217  case PROP_OPT_AUTO_READONLY_DAYS:
218  qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
219  str_OPTION_SECTION_ACCOUNTS, str_OPTION_NAME_AUTO_READONLY_DAYS});
220  break;
221  case PROP_OPT_NUM_FIELD_SOURCE:
222  qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
223  str_OPTION_SECTION_ACCOUNTS, str_OPTION_NAME_NUM_FIELD_SOURCE});
224  break;
225  case PROP_OPT_DEFAULT_BUDGET:
226  qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {str_KVP_OPTION_PATH,
227  str_OPTION_SECTION_BUDGETING, OPTION_NAME_DEFAULT_BUDGET});
228  break;
229  case PROP_OPT_FY_END:
230  qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {"fy_end"});
231  break;
232  case PROP_AB_TEMPLATES:
233  qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {AB_KEY, AB_TEMPLATES});
234  break;
235  default:
236  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
237  break;
238  }
239 }
240 
241 static void
242 qof_book_class_init (QofBookClass *klass)
243 {
244  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
245  gobject_class->dispose = qof_book_dispose;
246  gobject_class->finalize = qof_book_finalize;
247  gobject_class->get_property = qof_book_get_property;
248  gobject_class->set_property = qof_book_set_property;
249 
250  g_object_class_install_property
251  (gobject_class,
252  PROP_OPT_TRADING_ACCOUNTS,
253  g_param_spec_string("trading-accts",
254  "Use Trading Accounts",
255  "Scheme true ('t') or NULL. If 't', then the book "
256  "uses trading accounts for managing multiple-currency "
257  "transactions.",
258  NULL,
259  G_PARAM_READWRITE));
260 
261  g_object_class_install_property
262  (gobject_class,
263  PROP_OPT_NUM_FIELD_SOURCE,
264  g_param_spec_string(PARAM_NAME_NUM_FIELD_SOURCE,
265  "Use Split-Action in the Num Field",
266  "Scheme true ('t') or NULL. If 't', then the book "
267  "will put the split action value in the Num field.",
268  NULL,
269  G_PARAM_READWRITE));
270 
271  g_object_class_install_property
272  (gobject_class,
273  PROP_OPT_AUTO_READONLY_DAYS,
274  g_param_spec_double("autoreadonly-days",
275  "Transaction Auto-read-only Days",
276  "Prevent editing of transactions posted more than "
277  "this many days ago.",
278  0,
279  G_MAXDOUBLE,
280  0,
281  G_PARAM_READWRITE));
282 
283  g_object_class_install_property
284  (gobject_class,
285  PROP_OPT_DEFAULT_BUDGET,
286  g_param_spec_boxed("default-budget",
287  "Book Default Budget",
288  "The default Budget for this book.",
289  GNC_TYPE_GUID,
290  G_PARAM_READWRITE));
291  g_object_class_install_property
292  (gobject_class,
293  PROP_OPT_FY_END,
294  g_param_spec_boxed("fy-end",
295  "Book Fiscal Year End",
296  "A GDate with a bogus year having the last Month and "
297  "Day of the Fiscal year for the book.",
298  G_TYPE_DATE,
299  G_PARAM_READWRITE));
300  g_object_class_install_property
301  (gobject_class,
302  PROP_AB_TEMPLATES,
303  g_param_spec_boxed("ab-templates",
304  "AQBanking Template List",
305  "A GList of AQBanking Templates",
306  GNC_TYPE_VALUE_LIST,
307  G_PARAM_READWRITE));
308 }
309 
310 QofBook *
312 {
313  QofBook *book;
314 
315  ENTER (" ");
316  book = static_cast<QofBook*>(g_object_new(QOF_TYPE_BOOK, NULL));
317  qof_object_book_begin (book);
318 
319  qof_event_gen (&book->inst, QOF_EVENT_CREATE, NULL);
320  LEAVE ("book=%p", book);
321  return book;
322 }
323 
324 static void
325 book_final (gpointer key, gpointer value, gpointer booq)
326 {
327  QofBookFinalCB cb = reinterpret_cast<QofBookFinalCB>(value);
328  QofBook *book = static_cast<QofBook*>(booq);
329 
330  gpointer user_data = g_hash_table_lookup (book->data_tables, key);
331  (*cb) (book, key, user_data);
332 }
333 
334 static void
335 qof_book_dispose_real (G_GNUC_UNUSED GObject *bookp)
336 {
337 }
338 
339 static void
340 qof_book_finalize_real (G_GNUC_UNUSED GObject *bookp)
341 {
342 }
343 
344 void
345 qof_book_destroy (QofBook *book)
346 {
347  GHashTable* cols;
348 
349  if (!book) return;
350  ENTER ("book=%p", book);
351 
352  book->shutting_down = TRUE;
353  qof_event_force (&book->inst, QOF_EVENT_DESTROY, NULL);
354 
355  /* Call the list of finalizers, let them do their thing.
356  * Do this before tearing into the rest of the book.
357  */
358  g_hash_table_foreach (book->data_table_finalizers, book_final, book);
359 
360  qof_object_book_end (book);
361 
362  g_hash_table_destroy (book->data_table_finalizers);
363  book->data_table_finalizers = NULL;
364  g_hash_table_destroy (book->data_tables);
365  book->data_tables = NULL;
366 
367  /* qof_instance_release (&book->inst); */
368 
369  /* Note: we need to save this hashtable until after we remove ourself
370  * from it, otherwise we'll crash in our dispose() function when we
371  * DO remove ourself from the collection but the collection had already
372  * been destroyed.
373  */
374  cols = book->hash_of_collections;
375  g_object_unref (book);
376  g_hash_table_destroy (cols);
377  /*book->hash_of_collections = NULL;*/
378 
379  LEAVE ("book=%p", book);
380 }
381 
382 /* ====================================================================== */
383 
384 gboolean
385 qof_book_session_not_saved (const QofBook *book)
386 {
387  if (!book) return FALSE;
388  return !qof_book_empty(book) && book->session_dirty;
389 
390 }
391 
392 void
394 {
395  if (!book) return;
396 
397  book->dirty_time = 0;
398  if (book->session_dirty)
399  {
400  /* Set the session clean upfront, because the callback will check. */
401  book->session_dirty = FALSE;
402  if (book->dirty_cb)
403  book->dirty_cb(book, FALSE, book->dirty_data);
404  }
405 }
406 
407 void qof_book_mark_session_dirty (QofBook *book)
408 {
409  if (!book) return;
410  if (!book->session_dirty)
411  {
412  /* Set the session dirty upfront, because the callback will check. */
413  book->session_dirty = TRUE;
414  book->dirty_time = gnc_time (NULL);
415  if (book->dirty_cb)
416  book->dirty_cb(book, TRUE, book->dirty_data);
417  }
418 }
419 
420 void
421 qof_book_print_dirty (const QofBook *book)
422 {
423  if (qof_book_session_not_saved(book))
424  PINFO("book is dirty.");
425  qof_book_foreach_collection
426  (book, (QofCollectionForeachCB)qof_collection_print_dirty, NULL);
427 }
428 
429 time64
430 qof_book_get_session_dirty_time (const QofBook *book)
431 {
432  return book->dirty_time;
433 }
434 
435 void
436 qof_book_set_dirty_cb(QofBook *book, QofBookDirtyCB cb, gpointer user_data)
437 {
438  g_return_if_fail(book);
439  if (book->dirty_cb)
440  PWARN("Already existing callback %p, will be overwritten by %p\n",
441  book->dirty_cb, cb);
442  book->dirty_data = user_data;
443  book->dirty_cb = cb;
444 }
445 
446 /* ====================================================================== */
447 /* getters */
448 
449 QofBackend *
450 qof_book_get_backend (const QofBook *book)
451 {
452  if (!book) return NULL;
453  return book->backend;
454 }
455 
456 gboolean
457 qof_book_shutting_down (const QofBook *book)
458 {
459  if (!book) return FALSE;
460  return book->shutting_down;
461 }
462 
463 /* ====================================================================== */
464 /* setters */
465 
466 void
467 qof_book_set_backend (QofBook *book, QofBackend *be)
468 {
469  if (!book) return;
470  ENTER ("book=%p be=%p", book, be);
471  book->backend = be;
472  LEAVE (" ");
473 }
474 
475 /* ====================================================================== */
476 /* Store arbitrary pointers in the QofBook for data storage extensibility */
477 /* XXX if data is NULL, we should remove the key from the hash table!
478  */
479 void
480 qof_book_set_data (QofBook *book, const char *key, gpointer data)
481 {
482  if (!book || !key) return;
483  g_hash_table_insert (book->data_tables, (gpointer)key, data);
484 }
485 
486 void
487 qof_book_set_data_fin (QofBook *book, const char *key, gpointer data, QofBookFinalCB cb)
488 {
489  if (!book || !key) return;
490  g_hash_table_insert (book->data_tables, (gpointer)key, data);
491 
492  if (!cb) return;
493  g_hash_table_insert (book->data_table_finalizers, (gpointer)key,
494  reinterpret_cast<void*>(cb));
495 }
496 
497 gpointer
498 qof_book_get_data (const QofBook *book, const char *key)
499 {
500  if (!book || !key) return NULL;
501  return g_hash_table_lookup (book->data_tables, (gpointer)key);
502 }
503 
504 /* ====================================================================== */
505 gboolean
506 qof_book_is_readonly(const QofBook *book)
507 {
508  g_return_val_if_fail( book != NULL, TRUE );
509  return book->read_only;
510 }
511 
512 void
514 {
515  g_return_if_fail( book != NULL );
516  book->read_only = TRUE;
517 }
518 
519 gboolean
520 qof_book_empty(const QofBook *book)
521 {
522  if (!book) return TRUE;
523  auto root_acct_col = qof_book_get_collection (book, GNC_ID_ROOT_ACCOUNT);
524  return qof_collection_get_data(root_acct_col) == nullptr;
525 }
526 
527 /* ====================================================================== */
528 
529 QofCollection *
530 qof_book_get_collection (const QofBook *book, QofIdType entity_type)
531 {
532  QofCollection *col;
533 
534  if (!book || !entity_type) return NULL;
535 
536  col = static_cast<QofCollection*>(g_hash_table_lookup (book->hash_of_collections, entity_type));
537  if (!col)
538  {
539  col = qof_collection_new (entity_type);
540  g_hash_table_insert(
541  book->hash_of_collections,
542  (gpointer)qof_string_cache_insert(entity_type), col);
543  }
544  return col;
545 }
546 
547 struct _iterate
548 {
550  gpointer data;
551 };
552 
553 static void
554 foreach_cb (G_GNUC_UNUSED gpointer key, gpointer item, gpointer arg)
555 {
556  struct _iterate *iter = static_cast<_iterate*>(arg);
557  QofCollection *col = static_cast<QofCollection*>(item);
558 
559  iter->fn (col, iter->data);
560 }
561 
562 void
563 qof_book_foreach_collection (const QofBook *book,
564  QofCollectionForeachCB cb, gpointer user_data)
565 {
566  struct _iterate iter;
567 
568  g_return_if_fail (book);
569  g_return_if_fail (cb);
570 
571  iter.fn = cb;
572  iter.data = user_data;
573 
574  g_hash_table_foreach (book->hash_of_collections, foreach_cb, &iter);
575 }
576 
577 /* ====================================================================== */
578 
579 void qof_book_mark_closed (QofBook *book)
580 {
581  if (!book)
582  {
583  return;
584  }
585  book->book_open = 'n';
586 }
587 
588 gint64
589 qof_book_get_counter (QofBook *book, const char *counter_name)
590 {
591  KvpFrame *kvp;
592  KvpValue *value;
593 
594  if (!book)
595  {
596  PWARN ("No book!!!");
597  return -1;
598  }
599 
600  if (!counter_name || *counter_name == '\0')
601  {
602  PWARN ("Invalid counter name.");
603  return -1;
604  }
605 
606  /* Use the KVP in the book */
607  kvp = qof_instance_get_slots (QOF_INSTANCE (book));
608 
609  if (!kvp)
610  {
611  PWARN ("Book has no KVP_Frame");
612  return -1;
613  }
614 
615  value = kvp->get_slot({"counters", counter_name});
616  if (value)
617  {
618  /* found it */
619  return value->get<int64_t>();
620  }
621  else
622  {
623  /* New counter */
624  return 0;
625  }
626 }
627 
628 gchar *
629 qof_book_increment_and_format_counter (QofBook *book, const char *counter_name)
630 {
631  KvpFrame *kvp;
632  KvpValue *value;
633  gint64 counter;
634  gchar* format;
635  gchar* result;
636 
637  if (!book)
638  {
639  PWARN ("No book!!!");
640  return NULL;
641  }
642 
643  if (!counter_name || *counter_name == '\0')
644  {
645  PWARN ("Invalid counter name.");
646  return NULL;
647  }
648 
649  /* Get the current counter value from the KVP in the book. */
650  counter = qof_book_get_counter(book, counter_name);
651 
652  /* Check if an error occurred */
653  if (counter < 0)
654  return NULL;
655 
656  /* Increment the counter */
657  counter++;
658 
659  /* Get the KVP from the current book */
660  kvp = qof_instance_get_slots (QOF_INSTANCE (book));
661 
662  if (!kvp)
663  {
664  PWARN ("Book has no KVP_Frame");
665  return NULL;
666  }
667 
668  /* Save off the new counter */
669  qof_book_begin_edit(book);
670  value = new KvpValue(counter);
671  delete kvp->set_path({"counters", counter_name}, value);
672  qof_instance_set_dirty (QOF_INSTANCE (book));
673  qof_book_commit_edit(book);
674 
675  format = qof_book_get_counter_format(book, counter_name);
676 
677  if (!format)
678  {
679  PWARN("Cannot get format for counter");
680  return NULL;
681  }
682 
683  /* Generate a string version of the counter */
684  result = g_strdup_printf(format, counter);
685  g_free (format);
686  return result;
687 }
688 
689 char *
690 qof_book_get_counter_format(const QofBook *book, const char *counter_name)
691 {
692  KvpFrame *kvp;
693  const char *user_format = NULL;
694  gchar *norm_format = NULL;
695  KvpValue *value;
696  gchar *error = NULL;
697 
698  if (!book)
699  {
700  PWARN ("No book!!!");
701  return NULL;
702  }
703 
704  if (!counter_name || *counter_name == '\0')
705  {
706  PWARN ("Invalid counter name.");
707  return NULL;
708  }
709 
710  /* Get the KVP from the current book */
711  kvp = qof_instance_get_slots (QOF_INSTANCE (book));
712 
713  if (!kvp)
714  {
715  PWARN ("Book has no KVP_Frame");
716  return NULL;
717  }
718 
719  /* Get the format string */
720  value = kvp->get_slot({"counter_formats", counter_name});
721  if (value)
722  {
723  user_format = value->get<const char*>();
724  norm_format = qof_book_normalize_counter_format(user_format, &error);
725  if (!norm_format)
726  {
727  PWARN("Invalid counter format string. Format string: '%s' Counter: '%s' Error: '%s')", user_format, counter_name, error);
728  /* Invalid format string */
729  user_format = NULL;
730  g_free(error);
731  }
732  }
733 
734  /* If no (valid) format string was found, use the default format
735  * string */
736  if (!norm_format)
737  {
738  /* Use the default format */
739  norm_format = g_strdup ("%.6" PRIi64);
740  }
741  return norm_format;
742 }
743 
744 gchar *
745 qof_book_normalize_counter_format(const gchar *p, gchar **err_msg)
746 {
747  const gchar *valid_formats [] = {
748  G_GINT64_FORMAT,
749  "lli",
750  "I64i",
751  PRIi64,
752  "li",
753  NULL,
754  };
755  int i = 0;
756  gchar *normalized_spec = NULL;
757 
758  while (valid_formats[i])
759  {
760 
761  if (err_msg && *err_msg)
762  {
763  g_free (*err_msg);
764  *err_msg = NULL;
765  }
766 
767  normalized_spec = qof_book_normalize_counter_format_internal(p, valid_formats[i], err_msg);
768  if (normalized_spec)
769  return normalized_spec; /* Found a valid format specifier, return */
770  i++;
771  }
772 
773  return NULL;
774 }
775 
776 gchar *
778  const gchar *gint64_format, gchar **err_msg)
779 {
780  const gchar *conv_start, *base, *tmp = NULL;
781  gchar *normalized_str = NULL, *aux_str = NULL;
782 
783  /* Validate a counter format. This is a very simple "parser" that
784  * simply checks for a single gint64 conversion specification,
785  * allowing all modifiers and flags that printf(3) specifies (except
786  * for the * width and precision, which need an extra argument). */
787  base = p;
788 
789  /* Skip a prefix of any character except % */
790  while (*p)
791  {
792  /* Skip two adjacent percent marks, which are literal percent
793  * marks */
794  if (p[0] == '%' && p[1] == '%')
795  {
796  p += 2;
797  continue;
798  }
799  /* Break on a single percent mark, which is the start of the
800  * conversion specification */
801  if (*p == '%')
802  break;
803  /* Skip all other characters */
804  p++;
805  }
806 
807  if (!*p)
808  {
809  if (err_msg)
810  *err_msg = g_strdup("Format string ended without any conversion specification");
811  return NULL;
812  }
813 
814  /* Store the start of the conversion for error messages */
815  conv_start = p;
816 
817  /* Skip the % */
818  p++;
819 
820  /* See whether we have already reached the correct format
821  * specification (e.g. "li" on Unix, "I64i" on Windows). */
822  tmp = strstr(p, gint64_format);
823 
824  if (!tmp)
825  {
826  if (err_msg)
827  *err_msg = g_strdup_printf("Format string doesn't contain requested format specifier: %s", gint64_format);
828  return NULL;
829  }
830 
831  /* Skip any number of flag characters */
832  while (*p && (tmp != p) && strchr("#0- +'I", *p))
833  {
834  p++;
835  tmp = strstr(p, gint64_format);
836  }
837 
838  /* Skip any number of field width digits,
839  * and precision specifier digits (including the leading dot) */
840  while (*p && (tmp != p) && strchr("0123456789.", *p))
841  {
842  p++;
843  tmp = strstr(p, gint64_format);
844  }
845 
846  if (!*p)
847  {
848  if (err_msg)
849  *err_msg = g_strdup_printf("Format string ended during the conversion specification. Conversion seen so far: %s", conv_start);
850  return NULL;
851  }
852 
853  /* See if the format string starts with the correct format
854  * specification. */
855  tmp = strstr(p, gint64_format);
856  if (tmp == NULL)
857  {
858  if (err_msg)
859  *err_msg = g_strdup_printf("Invalid length modifier and/or conversion specifier ('%.4s'), it should be: %s", p, gint64_format);
860  return NULL;
861  }
862  else if (tmp != p)
863  {
864  if (err_msg)
865  *err_msg = g_strdup_printf("Garbage before length modifier and/or conversion specifier: '%*s'", (int)(tmp - p), p);
866  return NULL;
867  }
868 
869  /* Copy the string we have so far and add normalized format specifier for long int */
870  aux_str = g_strndup (base, p - base);
871  normalized_str = g_strconcat (aux_str, PRIi64, nullptr);
872  g_free (aux_str);
873 
874  /* Skip length modifier / conversion specifier */
875  p += strlen(gint64_format);
876  tmp = p;
877 
878  /* Skip a suffix of any character except % */
879  while (*p)
880  {
881  /* Skip two adjacent percent marks, which are literal percent
882  * marks */
883  if (p[0] == '%' && p[1] == '%')
884  {
885  p += 2;
886  continue;
887  }
888  /* Break on a single percent mark, which is the start of the
889  * conversion specification */
890  if (*p == '%')
891  {
892  if (err_msg)
893  *err_msg = g_strdup_printf("Format string contains unescaped %% signs (or multiple conversion specifications) at '%s'", p);
894  g_free (normalized_str);
895  return NULL;
896  }
897  /* Skip all other characters */
898  p++;
899  }
900 
901  /* Add the suffix to our normalized string */
902  aux_str = normalized_str;
903  normalized_str = g_strconcat (aux_str, tmp, nullptr);
904  g_free (aux_str);
905 
906  /* If we end up here, the string was valid, so return no error
907  * message */
908  return normalized_str;
909 }
910 
911 /* Determine whether this book uses trading accounts */
912 gboolean
913 qof_book_use_trading_accounts (const QofBook *book)
914 {
915  char *opt = nullptr;
916  qof_instance_get (QOF_INSTANCE (book), "trading-accts", &opt, nullptr);
917  auto retval = (opt && opt[0] == 't' && opt[1] == 0);
918  g_free (opt);
919  return retval;
920 }
921 
922 /* Returns TRUE if this book uses split action field as the 'Num' field, FALSE
923  * if it uses transaction number field */
924 gboolean
926 {
927  g_return_val_if_fail (book, FALSE);
928  if (!book->cached_num_field_source_isvalid)
929  {
930  // No cached value? Then do the expensive KVP lookup
931  gboolean result;
932  char *opt = NULL;
933  qof_instance_get (QOF_INSTANCE (book),
934  PARAM_NAME_NUM_FIELD_SOURCE, &opt,
935  NULL);
936 
937  if (opt && opt[0] == 't' && opt[1] == 0)
938  result = TRUE;
939  else
940  result = FALSE;
941  g_free (opt);
942 
943  // We need to const_cast the "book" argument into a non-const pointer,
944  // but as we are dealing only with cache variables, I think this is
945  // understandable enough.
946  const_cast<QofBook*>(book)->cached_num_field_source = result;
947  const_cast<QofBook*>(book)->cached_num_field_source_isvalid = TRUE;
948  }
949  // Value is cached now. Use the cheap variable returning.
950  return book->cached_num_field_source;
951 }
952 
953 // The callback that is called when the KVP option value of
954 // "split-action-num-field" changes, so that we mark the cached value as
955 // invalid.
956 static void
957 qof_book_option_num_field_source_changed_cb (GObject *gobject,
958  GParamSpec *pspec,
959  gpointer user_data)
960 {
961  QofBook *book = reinterpret_cast<QofBook*>(user_data);
962  g_return_if_fail(QOF_IS_BOOK(book));
963  book->cached_num_field_source_isvalid = FALSE;
964 }
965 
966 gboolean qof_book_uses_autoreadonly (const QofBook *book)
967 {
968  g_assert(book);
969  return (qof_book_get_num_days_autoreadonly(book) != 0);
970 }
971 
972 gint qof_book_get_num_days_autoreadonly (const QofBook *book)
973 {
974  g_assert(book);
975 
976  if (!book->cached_num_days_autoreadonly_isvalid)
977  {
978  double tmp;
979 
980  // No cached value? Then do the expensive KVP lookup
981  qof_instance_get (QOF_INSTANCE (book),
982  PARAM_NAME_NUM_AUTOREAD_ONLY, &tmp,
983  NULL);
984 
985  const_cast<QofBook*>(book)->cached_num_days_autoreadonly = tmp;
986  const_cast<QofBook*>(book)->cached_num_days_autoreadonly_isvalid = TRUE;
987  }
988  // Value is cached now. Use the cheap variable returning.
989  return (gint) book->cached_num_days_autoreadonly;
990 }
991 
992 GDate* qof_book_get_autoreadonly_gdate (const QofBook *book)
993 {
994  gint num_days;
995  GDate* result = NULL;
996 
997  g_assert(book);
998  num_days = qof_book_get_num_days_autoreadonly(book);
999  if (num_days > 0)
1000  {
1001  result = gnc_g_date_new_today();
1002  g_date_subtract_days(result, num_days);
1003  }
1004  return result;
1005 }
1006 
1007 // The callback that is called when the KVP option value of
1008 // "autoreadonly-days" changes, so that we mark the cached value as
1009 // invalid.
1010 static void
1011 qof_book_option_num_autoreadonly_changed_cb (GObject *gobject,
1012  GParamSpec *pspec,
1013  gpointer user_data)
1014 {
1015  QofBook *book = reinterpret_cast<QofBook*>(user_data);
1016  g_return_if_fail(QOF_IS_BOOK(book));
1017  book->cached_num_days_autoreadonly_isvalid = FALSE;
1018 }
1019 
1020 /* Note: this will fail if the book slots we're looking for here are flattened at some point !
1021  * When that happens, this function can be removed. */
1022 static Path opt_name_to_path (const char* opt_name)
1023 {
1024  Path result;
1025  g_return_val_if_fail (opt_name, result);
1026  auto opt_name_list = g_strsplit(opt_name, "/", -1);
1027  for (int i=0; opt_name_list[i]; i++)
1028  result.push_back (opt_name_list[i]);
1029  g_strfreev (opt_name_list);
1030  return result;
1031 }
1032 
1033 const char*
1034 qof_book_get_string_option(const QofBook* book, const char* opt_name)
1035 {
1036  auto slot = qof_instance_get_slots(QOF_INSTANCE (book))->get_slot(opt_name_to_path(opt_name));
1037  if (slot == nullptr)
1038  return nullptr;
1039  return slot->get<const char*>();
1040 }
1041 
1042 void
1043 qof_book_set_string_option(QofBook* book, const char* opt_name, const char* opt_val)
1044 {
1045  qof_book_begin_edit(book);
1046  auto frame = qof_instance_get_slots(QOF_INSTANCE(book));
1047  auto opt_path = opt_name_to_path(opt_name);
1048  if (opt_val && (*opt_val != '\0'))
1049  delete frame->set_path(opt_path, new KvpValue(g_strdup(opt_val)));
1050  else
1051  delete frame->set_path(opt_path, nullptr);
1052  qof_instance_set_dirty (QOF_INSTANCE (book));
1053  qof_book_commit_edit(book);
1054 }
1055 
1056 const GncGUID*
1057 qof_book_get_guid_option(QofBook* book, GSList* path)
1058 {
1059  g_return_val_if_fail(book != nullptr, nullptr);
1060  g_return_val_if_fail(path != nullptr, nullptr);
1061 
1062  auto table_value = qof_book_get_option(book, path);
1063  if (!table_value)
1064  return nullptr;
1065  return table_value->get<GncGUID*>();
1066 }
1067 
1068 void
1069 qof_book_option_frame_delete (QofBook *book, const char* opt_name)
1070 {
1071  if (opt_name && (*opt_name != '\0'))
1072  {
1073  qof_book_begin_edit(book);
1074  auto frame = qof_instance_get_slots(QOF_INSTANCE(book));
1075  auto opt_path = opt_name_to_path(opt_name);
1076  delete frame->set_path(opt_path, nullptr);
1077  qof_instance_set_dirty (QOF_INSTANCE (book));
1078  qof_book_commit_edit(book);
1079  }
1080 }
1081 
1082 void
1083 qof_book_begin_edit (QofBook *book)
1084 {
1085  qof_begin_edit(&book->inst);
1086 }
1087 
1088 static void commit_err (G_GNUC_UNUSED QofInstance *inst, QofBackendError errcode)
1089 {
1090  PERR ("Failed to commit: %d", errcode);
1091 // gnc_engine_signal_commit_error( errcode );
1092 }
1093 
1094 #define GNC_FEATURES "features"
1095 static void
1096 add_feature_to_hash (const gchar *key, KvpValue *value, GHashTable * user_data)
1097 {
1098  gchar *descr = g_strdup(value->get<const char*>());
1099  g_hash_table_insert (user_data, (gchar*)key, descr);
1100 }
1101 
1102 GHashTable *
1103 qof_book_get_features (QofBook *book)
1104 {
1105  KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
1106  GHashTable *features = g_hash_table_new_full (g_str_hash, g_str_equal,
1107  NULL, g_free);
1108 
1109  auto slot = frame->get_slot({GNC_FEATURES});
1110  if (slot != nullptr)
1111  {
1112  frame = slot->get<KvpFrame*>();
1113  frame->for_each_slot_temp(&add_feature_to_hash, features);
1114  }
1115  return features;
1116 }
1117 
1118 void
1119 qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
1120 {
1121  KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
1122  KvpValue* feature = nullptr;
1123  auto feature_slot = frame->get_slot({GNC_FEATURES});
1124  if (feature_slot)
1125  {
1126  auto feature_frame = feature_slot->get<KvpFrame*>();
1127  feature = feature_frame->get_slot({key});
1128  }
1129  if (feature == nullptr || g_strcmp0 (feature->get<const char*>(), descr))
1130  {
1131  qof_book_begin_edit (book);
1132  delete frame->set_path({GNC_FEATURES, key}, new KvpValue(g_strdup (descr)));
1133  qof_instance_set_dirty (QOF_INSTANCE (book));
1134  qof_book_commit_edit (book);
1135  }
1136 }
1137 
1138 
1139 void
1140 qof_book_unset_feature (QofBook *book, const gchar *key, const gchar *descr)
1141 {
1142  KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
1143  KvpValue* feature = nullptr;
1144  auto feature_slot = frame->get_slot({GNC_FEATURES});
1145  if (feature_slot)
1146  {
1147  auto feature_frame = feature_slot->get<KvpFrame*>();
1148  feature = feature_frame->get_slot({key});
1149  }
1150  if (feature == nullptr || g_strcmp0 (feature->get<const char*>(), descr))
1151  {
1152  qof_book_begin_edit (book);
1153  delete frame->set_path({GNC_FEATURES, key}, nullptr);
1154  qof_instance_set_dirty (QOF_INSTANCE (book));
1155  qof_book_commit_edit (book);
1156  }
1157 }
1158 
1159 void
1160 qof_book_load_options (QofBook *book, GncOptionLoad load_cb, GncOptionDB *odb)
1161 {
1162  load_cb (odb, book);
1163 }
1164 
1165 void
1166 qof_book_save_options (QofBook *book, GncOptionSave save_cb,
1167  GncOptionDB* odb, gboolean clear)
1168 {
1169  /* Wrap this in begin/commit so that it commits only once instead of doing
1170  * so for every option. Qof_book_set_option will take care of dirtying the
1171  * book.
1172  */
1173  qof_book_begin_edit (book);
1174  save_cb (odb, book, clear);
1175  qof_book_commit_edit (book);
1176 }
1177 
1178 static void noop (QofInstance *inst) {}
1179 
1180 void
1181 qof_book_commit_edit(QofBook *book)
1182 {
1183  if (!qof_commit_edit (QOF_INSTANCE(book))) return;
1184  qof_commit_edit_part2 (&book->inst, commit_err, noop, noop/*lot_free*/);
1185 }
1186 
1187 /* Deal with the fact that some options are not in the "options" tree but rather
1188  * in the "counters" or "counter_formats" tree */
1189 static Path gslist_to_option_path (GSList *gspath)
1190 {
1191  Path tmp_path;
1192  if (!gspath) return tmp_path;
1193 
1194  Path path_v {str_KVP_OPTION_PATH};
1195  for (auto item = gspath; item != nullptr; item = g_slist_next(item))
1196  tmp_path.push_back(static_cast<const char*>(item->data));
1197  if ((tmp_path.front() == "counters") || (tmp_path.front() == "counter_formats"))
1198  return tmp_path;
1199 
1200  path_v.insert(path_v.end(), tmp_path.begin(), tmp_path.end());
1201  return path_v;
1202 }
1203 
1204 void
1205 qof_book_set_option (QofBook *book, KvpValue *value, GSList *path)
1206 {
1207  KvpFrame *root = qof_instance_get_slots (QOF_INSTANCE (book));
1208  qof_book_begin_edit (book);
1209  delete root->set_path(gslist_to_option_path(path), value);
1210  qof_instance_set_dirty (QOF_INSTANCE (book));
1211  qof_book_commit_edit (book);
1212 
1213  // Also, mark any cached value as invalid
1214  book->cached_num_field_source_isvalid = FALSE;
1215 }
1216 
1217 KvpValue*
1218 qof_book_get_option (QofBook *book, GSList *path)
1219 {
1220  KvpFrame *root = qof_instance_get_slots(QOF_INSTANCE (book));
1221  return root->get_slot(gslist_to_option_path(path));
1222 }
1223 
1224 void
1225 qof_book_options_delete (QofBook *book, GSList *path)
1226 {
1227  KvpFrame *root = qof_instance_get_slots(QOF_INSTANCE (book));
1228  if (path != nullptr)
1229  {
1230  Path path_v {str_KVP_OPTION_PATH};
1231  Path tmp_path;
1232  for (auto item = path; item != nullptr; item = g_slist_next(item))
1233  tmp_path.push_back(static_cast<const char*>(item->data));
1234  delete root->set_path(gslist_to_option_path(path), nullptr);
1235  }
1236  else
1237  delete root->set_path({str_KVP_OPTION_PATH}, nullptr);
1238 }
1239 
1240 /* QofObject function implementation and registration */
1241 gboolean qof_book_register (void)
1242 {
1243  static QofParam params[] =
1244  {
1245  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_entity_get_guid, NULL },
1246  { QOF_PARAM_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
1247  { NULL },
1248  };
1249 
1250  qof_class_register (QOF_ID_BOOK, NULL, params);
1251 
1252  return TRUE;
1253 }
1254 
1255 /* ========================== END OF FILE =============================== */
Holds all of the options for a book, report, or stylesheet, organized by GncOptionSections.
API for data storage Backend.
void qof_book_load_options(QofBook *book, GncOptionLoad load_cb, GncOptionDB *odb)
Load a GncOptionsDB from KVP data.
Definition: qofbook.cpp:1160
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
void qof_book_set_dirty_cb(QofBook *book, QofBookDirtyCB cb, gpointer user_data)
Set the function to call when a book transitions from clean to dirty, or vice versa.
Definition: qofbook.cpp:436
KvpValue * qof_book_get_option(QofBook *book, GSList *path)
Read a single option value.
Definition: qofbook.cpp:1218
void(* QofCollectionForeachCB)(QofCollection *, gpointer user_data)
Invoke the indicated callback on each collection in the book.
Definition: qofbook.h:238
gboolean qof_book_register(void)
Register the book object with the QOF object system.
Definition: qofbook.cpp:1241
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
void qof_object_book_begin(QofBook *book)
To be called from within the book.
Definition: qofobject.cpp:92
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
time64 qof_book_get_session_dirty_time(const QofBook *book)
Retrieve the earliest modification time on the book.
Definition: qofbook.cpp:430
gchar * qof_book_increment_and_format_counter(QofBook *book, const char *counter_name)
This will increment the named counter for this book and format it.
Definition: qofbook.cpp:629
gint qof_book_get_num_days_autoreadonly(const QofBook *book)
Returns the number of days for auto-read-only transactions.
Definition: qofbook.cpp:972
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the &#39;Num&#39; field, FALSE if it uses transaction nu...
Definition: qofbook.cpp:925
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
QofBook * qof_book_new(void)
Allocate, initialise and return a new QofBook.
Definition: qofbook.cpp:311
void qof_book_mark_closed(QofBook *book)
Close a book to editing.
Definition: qofbook.cpp:579
char * qof_book_get_counter_format(const QofBook *book, const char *counter_name)
Get the format string to use for the named counter.
Definition: qofbook.cpp:690
void qof_book_mark_readonly(QofBook *book)
Mark the book as read only.
Definition: qofbook.cpp:513
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
GHashTable * qof_book_get_features(QofBook *book)
Access functions for reading and setting the used-features on this book.
Definition: qofbook.cpp:1103
const char * qof_string_cache_insert(const char *key)
You can use this function with g_hash_table_insert(), for the key (or value), as long as you use the ...
the Core Object Registration/Lookup Private Interface
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
gint64 qof_book_get_counter(QofBook *book, const char *counter_name)
This will get the named counter for this book.
Definition: qofbook.cpp:589
gboolean qof_book_empty(const QofBook *book)
Check if the book has had anything loaded into it.
Definition: qofbook.cpp:520
const gchar * QofIdType
QofIdType declaration.
Definition: qofid.h:85
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
void qof_book_save_options(QofBook *book, GncOptionSave save_cb, GncOptionDB *odb, gboolean clear)
Save a GncOptionsDB back to the book&#39;s KVP.
Definition: qofbook.cpp:1166
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:992
void qof_book_mark_session_saved(QofBook *book)
The qof_book_mark_saved() routine marks the book as having been saved (to a file, to a database)...
Definition: qofbook.cpp:393
void qof_book_set_data_fin(QofBook *book, const gchar *key, gpointer data, QofBookFinalCB)
Same as qof_book_set_data(), except that the callback will be called when the book is destroyed...
void qof_book_set_data(QofBook *book, const gchar *key, gpointer data)
The qof_book_set_data() allows arbitrary pointers to structs to be stored in QofBook.
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:177
gchar * qof_book_normalize_counter_format(const gchar *p, gchar **err_msg)
Validate a counter format string.
Definition: qofbook.cpp:745
gchar * qof_book_normalize_counter_format_internal(const gchar *p, const gchar *gint64_format, gchar **err_msg)
Validate a counter format string with a given format specifier.
Definition: qofbook.cpp:777
gboolean qof_book_session_not_saved(const QofBook *book)
qof_book_not_saved() returns the value of the session_dirty flag, set when changes to any object in t...
Definition: qofbook.cpp:385
const GncGUID * qof_entity_get_guid(gconstpointer ent)
#define QOF_PARAM_KVP
"Known" Object Parameters – some objects might support these
Definition: qofquery.h:113
void qof_collection_destroy(QofCollection *col)
destroy the collection
Definition: qofid.cpp:62
void qof_book_mark_session_dirty(QofBook *book)
The qof_book_mark_dirty() routine marks the book as having been modified.
Definition: qofbook.cpp:407
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:506
This is the private header for the account structure.
void qof_book_print_dirty(const QofBook *book)
This debugging function can be used to traverse the book structure and all subsidiary structures...
Definition: qofbook.cpp:421
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:530
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
gpointer qof_collection_get_data(const QofCollection *col)
Store and retrieve arbitrary object-defined data.
Definition: qofid.cpp:291
void qof_book_set_option(QofBook *book, KvpValue *value, GSList *path)
Save a single option value.
Definition: qofbook.cpp:1205
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:966
QofBackend * qof_book_get_backend(const QofBook *book)
Retrieve the backend used by this book.
Definition: qofbook.cpp:450
gboolean qof_book_shutting_down(const QofBook *book)
Is the book shutting down?
Definition: qofbook.cpp:457
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
void qof_book_options_delete(QofBook *book, GSList *path)
Delete the options.
Definition: qofbook.cpp:1225
The type used to store guids in C.
Definition: guid.h:75
gpointer qof_book_get_data(const QofBook *book, const gchar *key)
Retrieves arbitrary pointers to structs stored by qof_book_set_data.
gboolean qof_book_use_trading_accounts(const QofBook *book)
Returns flag indicating whether this book uses trading accounts.
Definition: qofbook.cpp:913
void qof_string_cache_remove(const char *key)
You can use this function as a destroy notifier for a GHashTable that uses common strings as keys (or...
void qof_book_destroy(QofBook *book)
End any editing sessions associated with book, and free all memory associated with it...
Definition: qofbook.cpp:345
QofCollection * qof_collection_new(QofIdType type)
create a new collection of entities of type
Definition: qofid.cpp:51
GDate * gnc_g_date_new_today()
Returns a newly allocated date of the current clock time, taken from time(2).
Definition: gnc-date.cpp:1229