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