Line data Source code
1 : /********************************************************************\
2 : * qofinstance.c -- handler for fields common to all objects *
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 : /*
24 : * Object instance holds many common fields that most
25 : * gnucash objects use.
26 : *
27 : * Copyright (C) 2003 Linas Vepstas <linas@linas.org>
28 : * Copyright (c) 2007 David Hampton <hampton@employees.org>
29 : * Copyright 2017 Aaron Laws <dartme18@gmail.com>
30 : */
31 :
32 : #include "guid.hpp"
33 : #include <config.h>
34 : #include <glib.h>
35 :
36 : #include <cstdint>
37 : #include <utility>
38 : #include "qof.h"
39 : #include "qofbook-p.hpp"
40 : #include "qofid-p.h"
41 : #include "kvp-frame.hpp"
42 : #include "qofinstance-p.h"
43 : #include "qof-backend.hpp"
44 :
45 : static QofLogModule log_module = QOF_MOD_ENGINE;
46 :
47 : /* ========================================================== */
48 :
49 : enum
50 : {
51 : LAST_SIGNAL
52 : };
53 :
54 : enum
55 : {
56 : PROP_0,
57 : PROP_TYPE,
58 : PROP_GUID,
59 : PROP_COLLECTION,
60 : PROP_BOOK,
61 : PROP_LAST_UPDATE,
62 : PROP_EDITLEVEL,
63 : PROP_DESTROYING,
64 : PROP_DIRTY,
65 : PROP_INFANT,
66 :
67 : PROP_VERSION,
68 : PROP_VERSION_CHECK,
69 : PROP_IDATA,
70 : };
71 :
72 : typedef struct QofInstancePrivate
73 : {
74 : // QofIdType e_type; /**< Entity type */
75 : GncGUID guid; /**< GncGUID for the entity */
76 : QofCollection *collection; /**< Entity collection */
77 :
78 : /* The entity_table in which this instance is stored */
79 : QofBook * book;
80 :
81 : /* Timestamp used to track the last modification to this
82 : * instance. Typically used to compare two versions of the
83 : * same object, to see which is newer. When used with the
84 : * SQL backend, this field is reserved for SQL use, to compare
85 : * the version in local memory to the remote, server version.
86 : */
87 : time64 last_update;
88 :
89 : /* Keep track of nesting level of begin/end edit calls */
90 : int editlevel;
91 :
92 : /* In process of being destroyed */
93 : gboolean do_free;
94 :
95 : /* dirty/clean flag. If dirty, then this instance has been modified,
96 : * but has not yet been written out to storage (file/database)
97 : */
98 : gboolean dirty;
99 :
100 : /* True iff this instance has never been committed. */
101 : gboolean infant;
102 :
103 : /* version number, used for tracking multiuser updates */
104 : gint32 version;
105 : guint32 version_check; /* data aging timestamp */
106 :
107 : /* -------------------------------------------------------------- */
108 : /* Backend private expansion data */
109 : guint32 idata; /* used by the sql backend for kvp management */
110 : } QofInstancePrivate;
111 :
112 : #define GET_PRIVATE(o) \
113 : ((QofInstancePrivate*)qof_instance_get_instance_private((QofInstance*)o))
114 :
115 10566954 : G_DEFINE_TYPE_WITH_PRIVATE(QofInstance, qof_instance, G_TYPE_OBJECT)
116 115260 : QOF_GOBJECT_FINALIZE(qof_instance);
117 : #undef G_PARAM_READWRITE
118 : #define G_PARAM_READWRITE static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_WRITABLE)
119 :
120 : static void qof_instance_get_property (GObject *object,
121 : guint prop_id,
122 : GValue *value,
123 : GParamSpec *pspec);
124 : static void qof_instance_set_property (GObject *object,
125 : guint prop_id,
126 : const GValue *value,
127 : GParamSpec *pspec);
128 : static void qof_instance_dispose(GObject*);
129 77 : static void qof_instance_class_init(QofInstanceClass *klass)
130 : {
131 77 : GObjectClass *object_class = G_OBJECT_CLASS(klass);
132 77 : object_class->finalize = qof_instance_finalize;
133 77 : object_class->dispose = qof_instance_dispose;
134 77 : object_class->set_property = qof_instance_set_property;
135 77 : object_class->get_property = qof_instance_get_property;
136 :
137 77 : klass->get_display_name = nullptr;
138 77 : klass->refers_to_object = nullptr;
139 77 : klass->get_typed_referring_object_list = nullptr;
140 :
141 : g_object_class_install_property
142 77 : (object_class,
143 : PROP_GUID,
144 : g_param_spec_boxed ("guid",
145 : "Object GncGUID",
146 : "The object Globally Unique ID.",
147 : GNC_TYPE_GUID,
148 : G_PARAM_READWRITE));
149 :
150 : g_object_class_install_property
151 77 : (object_class,
152 : PROP_BOOK,
153 : g_param_spec_object ("book",
154 : "Object Book",
155 : "The book that contains this object.",
156 : QOF_TYPE_BOOK,
157 : G_PARAM_READWRITE));
158 :
159 : g_object_class_install_property
160 77 : (object_class,
161 : PROP_LAST_UPDATE,
162 : g_param_spec_pointer ("last-update",
163 : "Object Last Update",
164 : "A pointer to the last time this object was "
165 : "updated. This value is present for use by "
166 : "backends and shouldn't be written by other "
167 : "code.",
168 : G_PARAM_READWRITE));
169 :
170 : g_object_class_install_property
171 77 : (object_class,
172 : PROP_EDITLEVEL,
173 : g_param_spec_int ("editlevel",
174 : "Object Edit Level",
175 : "The object edit level.",
176 : 0, G_MAXINT32, 0,
177 : G_PARAM_READABLE));
178 :
179 : g_object_class_install_property
180 77 : (object_class,
181 : PROP_DESTROYING,
182 : g_param_spec_boolean ("destroying",
183 : "Object Destroying",
184 : "This flag is set to TRUE if the object is "
185 : "about to be destroyed.",
186 : FALSE,
187 : G_PARAM_READWRITE));
188 :
189 : g_object_class_install_property
190 77 : (object_class,
191 : PROP_DIRTY,
192 : g_param_spec_boolean ("dirty",
193 : "Object Dirty",
194 : "This flag is set to TRUE if the object has "
195 : "unsaved changes.",
196 : FALSE,
197 : G_PARAM_READWRITE));
198 :
199 : g_object_class_install_property
200 77 : (object_class,
201 : PROP_INFANT,
202 : g_param_spec_boolean ("infant",
203 : "Object Infant",
204 : "This flag is set to TRUE if the object has "
205 : "never been added to a book. This implies "
206 : "that its destruction does not affect the "
207 : "state of the book, and therefore the saved "
208 : "state of the data file.",
209 : FALSE,
210 : G_PARAM_READABLE));
211 :
212 : g_object_class_install_property
213 77 : (object_class,
214 : PROP_VERSION,
215 : g_param_spec_int ("version",
216 : "Version",
217 : "The version number of the current instance state.",
218 : 0,
219 : G_MAXINT32,
220 : 0,
221 : G_PARAM_READWRITE));
222 :
223 : g_object_class_install_property
224 77 : (object_class,
225 : PROP_VERSION_CHECK,
226 : g_param_spec_uint ("version-check",
227 : "Version Check",
228 : "The version check number of the current instance state.",
229 : 0,
230 : G_MAXUINT32,
231 : 0,
232 : G_PARAM_READWRITE));
233 :
234 : g_object_class_install_property
235 77 : (object_class,
236 : PROP_IDATA,
237 : g_param_spec_uint ("idata",
238 : "Object IData",
239 : "Per instance backend private data.",
240 : 0, G_MAXUINT32, 0,
241 : G_PARAM_READWRITE));
242 77 : }
243 :
244 : static void
245 153723 : qof_instance_init (QofInstance *inst)
246 : {
247 : QofInstancePrivate *priv;
248 :
249 153723 : priv = GET_PRIVATE(inst);
250 153723 : priv->book = nullptr;
251 153723 : inst->kvp_data = new KvpFrame;
252 153723 : priv->last_update = 0;
253 153723 : priv->editlevel = 0;
254 153723 : priv->do_free = FALSE;
255 153723 : priv->dirty = FALSE;
256 153723 : priv->infant = TRUE;
257 153723 : }
258 :
259 : void
260 95870 : qof_instance_init_data (QofInstance *inst, QofIdType type, QofBook *book)
261 : {
262 : QofInstancePrivate *priv;
263 : QofCollection *col;
264 : QofIdType col_type;
265 :
266 95870 : g_return_if_fail(QOF_IS_INSTANCE(inst));
267 95870 : priv = GET_PRIVATE(inst);
268 95870 : g_return_if_fail(!priv->book);
269 :
270 95870 : priv->book = book;
271 95870 : col = qof_book_get_collection (book, type);
272 95870 : g_return_if_fail(col != nullptr);
273 :
274 : /* XXX We passed redundant info to this routine ... but I think that's
275 : * OK, it might eliminate programming errors. */
276 :
277 95870 : col_type = qof_collection_get_type(col);
278 95870 : if (g_strcmp0(col_type, type))
279 : {
280 0 : PERR ("attempt to insert \"%s\" into \"%s\"", type, col_type);
281 0 : return;
282 : }
283 95870 : priv = GET_PRIVATE(inst);
284 95870 : inst->e_type = static_cast<QofIdType>(CACHE_INSERT (type));
285 :
286 : do
287 : {
288 95870 : guid_replace(&priv->guid);
289 :
290 95870 : if (nullptr == qof_collection_lookup_entity (col, &priv->guid))
291 95870 : break;
292 :
293 0 : PWARN("duplicate id created, trying again");
294 : }
295 : while (1);
296 :
297 95870 : priv->collection = col;
298 :
299 95870 : qof_collection_insert_entity (col, inst);
300 : }
301 :
302 : static void
303 123003 : qof_instance_dispose (GObject *instp)
304 : {
305 : QofInstancePrivate *priv;
306 123003 : QofInstance* inst = QOF_INSTANCE(instp);
307 :
308 123003 : priv = GET_PRIVATE(instp);
309 123003 : if (priv->collection)
310 107653 : qof_collection_remove_entity(inst);
311 :
312 123003 : CACHE_REMOVE(inst->e_type);
313 123003 : inst->e_type = nullptr;
314 :
315 123003 : G_OBJECT_CLASS(qof_instance_parent_class)->dispose(instp);
316 123003 : }
317 :
318 : static void
319 115260 : qof_instance_finalize_real (GObject *instp)
320 : {
321 : QofInstancePrivate *priv;
322 115260 : QofInstance* inst = QOF_INSTANCE(instp);
323 :
324 115260 : delete inst->kvp_data;
325 115260 : inst->kvp_data = nullptr;
326 :
327 115260 : priv = GET_PRIVATE(inst);
328 115260 : priv->editlevel = 0;
329 115260 : priv->do_free = FALSE;
330 115260 : priv->dirty = FALSE;
331 115260 : }
332 :
333 : /* Note that g_value_set_object() refs the object, as does
334 : * g_object_get(). But g_object_get() only unrefs once when it disgorges
335 : * the object, leaving an unbalanced ref, which leaks. So instead of
336 : * using g_value_set_object(), use g_value_take_object() which doesn't
337 : * ref the object when used in get_property().
338 : */
339 : static void
340 161 : qof_instance_get_property (GObject *object,
341 : guint prop_id,
342 : GValue *value,
343 : GParamSpec *pspec)
344 : {
345 : QofInstance *inst;
346 : QofInstancePrivate *priv;
347 :
348 161 : g_return_if_fail(QOF_IS_INSTANCE(object));
349 :
350 161 : inst = QOF_INSTANCE(object);
351 161 : priv = GET_PRIVATE(inst);
352 :
353 161 : switch (prop_id)
354 : {
355 160 : case PROP_GUID:
356 160 : g_value_set_boxed(value, &priv->guid);
357 160 : break;
358 0 : case PROP_COLLECTION:
359 0 : g_value_set_pointer(value, priv->collection);
360 0 : break;
361 0 : case PROP_BOOK:
362 0 : g_value_take_object(value, priv->book);
363 0 : break;
364 1 : case PROP_LAST_UPDATE:
365 1 : g_value_set_pointer(value, &priv->last_update);
366 1 : break;
367 0 : case PROP_EDITLEVEL:
368 0 : g_value_set_int(value, priv->editlevel);
369 0 : break;
370 0 : case PROP_DESTROYING:
371 0 : g_value_set_boolean(value, priv->do_free);
372 0 : break;
373 0 : case PROP_DIRTY:
374 0 : g_value_set_boolean(value, qof_instance_get_dirty(inst));
375 0 : break;
376 0 : case PROP_INFANT:
377 0 : g_value_set_boolean(value, priv->infant);
378 0 : break;
379 0 : case PROP_VERSION:
380 0 : g_value_set_int(value, priv->version);
381 0 : break;
382 0 : case PROP_VERSION_CHECK:
383 0 : g_value_set_uint(value, priv->version_check);
384 0 : break;
385 0 : case PROP_IDATA:
386 0 : g_value_set_uint(value, priv->idata);
387 0 : break;
388 0 : default:
389 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
390 0 : break;
391 : }
392 : }
393 :
394 : static void
395 50235 : qof_instance_set_property (GObject *object,
396 : guint prop_id,
397 : const GValue *value,
398 : GParamSpec *pspec)
399 : {
400 : QofInstance *inst;
401 : Time64 t;
402 :
403 50235 : g_return_if_fail(QOF_IS_INSTANCE(object));
404 :
405 50235 : inst = QOF_INSTANCE(object);
406 :
407 50235 : switch (prop_id)
408 : {
409 50232 : case PROP_GUID:
410 50232 : qof_instance_set_guid(inst,
411 50232 : static_cast<GncGUID*>(g_value_get_boxed(value)));
412 50232 : break;
413 0 : case PROP_COLLECTION:
414 0 : qof_instance_set_collection(inst, static_cast<QofCollection*>(g_value_get_pointer(value)));
415 0 : break;
416 3 : case PROP_BOOK:
417 3 : qof_instance_set_book(inst,
418 3 : static_cast<QofBook*>(g_value_get_object(value)));
419 3 : break;
420 0 : case PROP_LAST_UPDATE:
421 0 : t = *(static_cast<Time64*>(g_value_get_pointer(value)));
422 0 : qof_instance_set_last_update(inst, t.t);
423 0 : break;
424 0 : case PROP_DESTROYING:
425 0 : qof_instance_set_destroying(inst, g_value_get_boolean(value));
426 0 : break;
427 0 : case PROP_DIRTY:
428 0 : qof_instance_set_dirty(inst);
429 0 : break;
430 0 : case PROP_VERSION:
431 0 : qof_instance_set_version(inst, g_value_get_int(value));
432 0 : break;
433 0 : case PROP_VERSION_CHECK:
434 0 : qof_instance_set_version_check(inst, g_value_get_uint(value));
435 0 : break;
436 0 : case PROP_IDATA:
437 0 : qof_instance_set_idata(inst, g_value_get_uint(value));
438 0 : break;
439 0 : default:
440 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
441 0 : break;
442 : }
443 : }
444 :
445 : const GncGUID *
446 450304 : qof_instance_get_guid (gconstpointer inst)
447 : {
448 : QofInstancePrivate *priv;
449 :
450 450304 : if (!inst) return nullptr;
451 450299 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), guid_null());
452 450299 : priv = GET_PRIVATE(inst);
453 450299 : return &(priv->guid);
454 : }
455 :
456 : const GncGUID *
457 50792 : qof_entity_get_guid (gconstpointer ent)
458 : {
459 50792 : return ent ? qof_instance_get_guid(ent) : guid_null();
460 : }
461 :
462 : void
463 59803 : qof_instance_set_guid (gpointer ptr, const GncGUID *guid)
464 : {
465 : QofInstancePrivate *priv;
466 : QofInstance *inst;
467 : QofCollection *col;
468 :
469 59803 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
470 :
471 59803 : inst = QOF_INSTANCE(ptr);
472 59803 : priv = GET_PRIVATE(inst);
473 59803 : if (guid_equal (guid, &priv->guid))
474 4901 : return;
475 :
476 54902 : col = priv->collection;
477 54902 : qof_collection_remove_entity(inst);
478 54902 : priv->guid = *guid;
479 54902 : qof_collection_insert_entity(col, inst);
480 : }
481 :
482 : void
483 2805 : qof_instance_copy_guid (gpointer to, gconstpointer from)
484 : {
485 2805 : g_return_if_fail(QOF_IS_INSTANCE(to));
486 2805 : g_return_if_fail(QOF_IS_INSTANCE(from));
487 :
488 2805 : GET_PRIVATE(to)->guid = GET_PRIVATE(from)->guid;
489 : }
490 :
491 : gint
492 1105 : qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
493 : {
494 : const QofInstancePrivate *priv1, *priv2;
495 :
496 1105 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr1), -1);
497 1105 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr2), 1);
498 :
499 1105 : priv1 = GET_PRIVATE(ptr1);
500 1105 : priv2 = GET_PRIVATE(ptr2);
501 :
502 1105 : return guid_compare(&priv1->guid, &priv2->guid);
503 : }
504 :
505 : QofCollection *
506 313417 : qof_instance_get_collection (gconstpointer ptr)
507 : {
508 :
509 313417 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr), nullptr);
510 313417 : return GET_PRIVATE(ptr)->collection;
511 : }
512 :
513 : void
514 359075 : qof_instance_set_collection (gconstpointer ptr, QofCollection *col)
515 : {
516 359075 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
517 359075 : GET_PRIVATE(ptr)->collection = col;
518 : }
519 :
520 : QofBook *
521 934747 : qof_instance_get_book (gconstpointer inst)
522 : {
523 934747 : if (!inst) return nullptr;
524 934746 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), nullptr);
525 934746 : return GET_PRIVATE(inst)->book;
526 : }
527 :
528 : void
529 7 : qof_instance_set_book (gconstpointer inst, QofBook *book)
530 : {
531 7 : g_return_if_fail(QOF_IS_INSTANCE(inst));
532 7 : GET_PRIVATE(inst)->book = book;
533 : }
534 :
535 : void
536 7685 : qof_instance_copy_book (gpointer ptr1, gconstpointer ptr2)
537 : {
538 7685 : g_return_if_fail(QOF_IS_INSTANCE(ptr1));
539 7685 : g_return_if_fail(QOF_IS_INSTANCE(ptr2));
540 :
541 7685 : GET_PRIVATE(ptr1)->book = GET_PRIVATE(ptr2)->book;
542 : }
543 :
544 : gboolean
545 10041 : qof_instance_books_equal (gconstpointer ptr1, gconstpointer ptr2)
546 : {
547 : const QofInstancePrivate *priv1, *priv2;
548 :
549 10041 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr1), FALSE);
550 10041 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr2), FALSE);
551 :
552 10041 : priv1 = GET_PRIVATE(ptr1);
553 10041 : priv2 = GET_PRIVATE(ptr2);
554 :
555 10041 : return (priv1->book == priv2->book);
556 : }
557 :
558 : /* Watch out: This function is still used (as a "friend") in src/import-export/aqb/gnc-ab-kvp.c */
559 : KvpFrame*
560 2561 : qof_instance_get_slots (const QofInstance *inst)
561 : {
562 2561 : if (!inst) return nullptr;
563 2561 : return inst->kvp_data;
564 : }
565 :
566 : void
567 1367 : qof_instance_set_slots (QofInstance *inst, KvpFrame *frm)
568 : {
569 : QofInstancePrivate *priv;
570 :
571 1367 : if (!inst) return;
572 :
573 1367 : priv = GET_PRIVATE(inst);
574 1367 : if (inst->kvp_data && (inst->kvp_data != frm))
575 : {
576 1366 : delete inst->kvp_data;
577 : }
578 :
579 1367 : priv->dirty = TRUE;
580 1367 : inst->kvp_data = frm;
581 : }
582 :
583 : void
584 6 : qof_instance_set_last_update (QofInstance *inst, time64 t)
585 : {
586 6 : if (!inst) return;
587 6 : GET_PRIVATE(inst)->last_update = t;
588 : }
589 :
590 : gint
591 52057 : qof_instance_get_editlevel (gconstpointer ptr)
592 : {
593 52057 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr), 0);
594 52057 : return GET_PRIVATE(ptr)->editlevel;
595 : }
596 :
597 9343 : void qof_instance_increase_editlevel (gpointer ptr)
598 : {
599 9343 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
600 9343 : GET_PRIVATE(ptr)->editlevel++;
601 : }
602 :
603 6943 : void qof_instance_decrease_editlevel (gpointer ptr)
604 : {
605 6943 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
606 6943 : GET_PRIVATE(ptr)->editlevel--;
607 : }
608 :
609 9 : void qof_instance_reset_editlevel (gpointer ptr)
610 : {
611 9 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
612 9 : GET_PRIVATE(ptr)->editlevel = 0;
613 : }
614 :
615 : int
616 8 : qof_instance_version_cmp (const QofInstance *left, const QofInstance *right)
617 : {
618 : QofInstancePrivate *lpriv, *rpriv;
619 :
620 8 : if (!left && !right) return 0;
621 7 : if (!left) return -1;
622 6 : if (!right) return +1;
623 :
624 5 : lpriv = GET_PRIVATE(left);
625 5 : rpriv = GET_PRIVATE(right);
626 5 : return lpriv->last_update < rpriv->last_update ? -1 :
627 5 : lpriv->last_update > rpriv->last_update ? 1 : 0;
628 : }
629 :
630 : gboolean
631 240150 : qof_instance_get_destroying (gconstpointer ptr)
632 : {
633 240150 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr), FALSE);
634 240150 : return GET_PRIVATE(ptr)->do_free;
635 : }
636 :
637 : void
638 54091 : qof_instance_set_destroying (gpointer ptr, gboolean value)
639 : {
640 54091 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
641 54091 : GET_PRIVATE(ptr)->do_free = value;
642 : }
643 :
644 : gboolean
645 89 : qof_instance_get_dirty_flag (gconstpointer ptr)
646 : {
647 89 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr), FALSE);
648 89 : return GET_PRIVATE(ptr)->dirty;
649 : }
650 :
651 : void
652 6 : qof_instance_set_dirty_flag (gconstpointer inst, gboolean flag)
653 : {
654 6 : g_return_if_fail(QOF_IS_INSTANCE(inst));
655 6 : GET_PRIVATE(inst)->dirty = flag;
656 : }
657 :
658 : void
659 13200 : qof_instance_mark_clean (QofInstance *inst)
660 : {
661 13200 : if (!inst) return;
662 13200 : GET_PRIVATE(inst)->dirty = FALSE;
663 : }
664 :
665 : void
666 2 : qof_instance_print_dirty (const QofInstance *inst, gpointer dummy)
667 : {
668 : QofInstancePrivate *priv;
669 :
670 2 : priv = GET_PRIVATE(inst);
671 2 : if (priv->dirty)
672 : {
673 : gchar guidstr[GUID_ENCODING_LENGTH+1];
674 0 : guid_to_string_buff(&priv->guid, guidstr);
675 0 : printf("%s instance %s is dirty.\n", inst->e_type, guidstr);
676 : }
677 2 : }
678 :
679 : gboolean
680 37064 : qof_instance_get_dirty (QofInstance *inst)
681 : {
682 : QofInstancePrivate *priv;
683 :
684 37064 : if (!inst)
685 : {
686 1 : return FALSE;
687 : }
688 :
689 37063 : priv = GET_PRIVATE(inst);
690 37063 : return priv->dirty;
691 : }
692 :
693 : void
694 645669 : qof_instance_set_dirty(QofInstance* inst)
695 : {
696 : QofInstancePrivate *priv;
697 :
698 645669 : priv = GET_PRIVATE(inst);
699 645669 : priv->dirty = TRUE;
700 645669 : }
701 :
702 : gboolean
703 146 : qof_instance_get_infant(const QofInstance *inst)
704 : {
705 146 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), FALSE);
706 146 : return GET_PRIVATE(inst)->infant;
707 : }
708 :
709 : gint32
710 1 : qof_instance_get_version (gconstpointer inst)
711 : {
712 1 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), 0);
713 1 : return GET_PRIVATE(inst)->version;
714 : }
715 :
716 : void
717 0 : qof_instance_set_version (gpointer inst, gint32 vers)
718 : {
719 0 : g_return_if_fail(QOF_IS_INSTANCE(inst));
720 0 : GET_PRIVATE(inst)->version = vers;
721 : }
722 :
723 : void
724 4917 : qof_instance_copy_version (gpointer to, gconstpointer from)
725 : {
726 4917 : g_return_if_fail(QOF_IS_INSTANCE(to));
727 4917 : g_return_if_fail(QOF_IS_INSTANCE(from));
728 4917 : GET_PRIVATE(to)->version = GET_PRIVATE(from)->version;
729 : }
730 :
731 : guint32
732 3 : qof_instance_get_version_check (gconstpointer inst)
733 : {
734 3 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), 0);
735 3 : return GET_PRIVATE(inst)->version_check;
736 : }
737 :
738 : void
739 0 : qof_instance_set_version_check (gpointer inst, guint32 value)
740 : {
741 0 : g_return_if_fail(QOF_IS_INSTANCE(inst));
742 0 : GET_PRIVATE(inst)->version_check = value;
743 : }
744 :
745 : void
746 11 : qof_instance_copy_version_check (gpointer to, gconstpointer from)
747 : {
748 11 : g_return_if_fail(QOF_IS_INSTANCE(to));
749 11 : g_return_if_fail(QOF_IS_INSTANCE(from));
750 11 : GET_PRIVATE(to)->version_check = GET_PRIVATE(from)->version_check;
751 : }
752 :
753 1 : guint32 qof_instance_get_idata (gconstpointer inst)
754 : {
755 1 : if (!inst)
756 : {
757 0 : return 0;
758 : }
759 1 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), 0);
760 1 : return GET_PRIVATE(inst)->idata;
761 : }
762 :
763 0 : void qof_instance_set_idata(gpointer inst, guint32 idata)
764 : {
765 0 : if (!inst)
766 : {
767 0 : return;
768 : }
769 0 : g_return_if_fail(QOF_IS_INSTANCE(inst));
770 0 : GET_PRIVATE(inst)->idata = idata;
771 : }
772 :
773 : /* ========================================================== */
774 :
775 : /* Returns a displayable name to represent this object */
776 2 : gchar* qof_instance_get_display_name(const QofInstance* inst)
777 : {
778 2 : g_return_val_if_fail( inst != nullptr, nullptr );
779 :
780 2 : if ( QOF_INSTANCE_GET_CLASS(inst)->get_display_name != nullptr )
781 : {
782 1 : return QOF_INSTANCE_GET_CLASS(inst)->get_display_name(inst);
783 : }
784 : else
785 : {
786 : /* Not implemented - return default string */
787 1 : return g_strdup_printf("Object %s %p",
788 1 : qof_collection_get_type(qof_instance_get_collection(inst)),
789 1 : inst);
790 : }
791 : }
792 :
793 : typedef struct
794 : {
795 : const QofInstance* inst;
796 : GList* list;
797 : } GetReferringObjectHelperData;
798 :
799 : static void
800 42 : get_referring_object_instance_helper(QofInstance* inst, gpointer user_data)
801 : {
802 42 : QofInstance** pInst = (QofInstance**)user_data;
803 :
804 42 : if (*pInst == nullptr)
805 : {
806 18 : *pInst = inst;
807 : }
808 42 : }
809 :
810 : static void
811 18 : get_referring_object_helper(QofCollection* coll, gpointer user_data)
812 : {
813 18 : QofInstance* first_instance = nullptr;
814 18 : GetReferringObjectHelperData* data = (GetReferringObjectHelperData*)user_data;
815 :
816 18 : qof_collection_foreach(coll, get_referring_object_instance_helper, &first_instance);
817 :
818 18 : if (first_instance != nullptr)
819 : {
820 18 : GList* new_list = qof_instance_get_typed_referring_object_list(first_instance, data->inst);
821 18 : data->list = g_list_concat(data->list, new_list);
822 : }
823 18 : }
824 :
825 : /* Returns a list of objects referring to this object */
826 6 : GList* qof_instance_get_referring_object_list(const QofInstance* inst)
827 : {
828 : GetReferringObjectHelperData data;
829 :
830 6 : g_return_val_if_fail( inst != nullptr, nullptr );
831 :
832 : /* scan all collections */
833 6 : data.inst = inst;
834 6 : data.list = nullptr;
835 :
836 6 : qof_book_foreach_collection(qof_instance_get_book(inst),
837 : get_referring_object_helper,
838 : &data);
839 6 : return data.list;
840 : }
841 :
842 : static void
843 43 : get_typed_referring_object_instance_helper(QofInstance* inst, gpointer user_data)
844 : {
845 43 : GetReferringObjectHelperData* data = (GetReferringObjectHelperData*)user_data;
846 :
847 43 : if (qof_instance_refers_to_object(inst, data->inst))
848 : {
849 12 : data->list = g_list_prepend(data->list, inst);
850 : }
851 43 : }
852 :
853 : GList*
854 21 : qof_instance_get_referring_object_list_from_collection(const QofCollection* coll, const QofInstance* ref)
855 : {
856 : GetReferringObjectHelperData data;
857 :
858 21 : g_return_val_if_fail( coll != nullptr, nullptr );
859 21 : g_return_val_if_fail( ref != nullptr, nullptr );
860 :
861 21 : data.inst = ref;
862 21 : data.list = nullptr;
863 :
864 21 : qof_collection_foreach(coll, get_typed_referring_object_instance_helper, &data);
865 21 : return data.list;
866 : }
867 :
868 : GList*
869 20 : qof_instance_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
870 : {
871 20 : g_return_val_if_fail( inst != nullptr, nullptr );
872 20 : g_return_val_if_fail( ref != nullptr, nullptr );
873 :
874 20 : if ( QOF_INSTANCE_GET_CLASS(inst)->get_typed_referring_object_list != nullptr )
875 : {
876 5 : return QOF_INSTANCE_GET_CLASS(inst)->get_typed_referring_object_list(inst, ref);
877 : }
878 : else
879 : {
880 : /* Not implemented - by default, loop through all objects of this object's type and check
881 : them individually. */
882 : QofCollection* coll;
883 :
884 15 : coll = qof_instance_get_collection(inst);
885 15 : return qof_instance_get_referring_object_list_from_collection(coll, ref);
886 : }
887 : }
888 :
889 : /* Check if this object refers to a specific object */
890 45 : gboolean qof_instance_refers_to_object(const QofInstance* inst, const QofInstance* ref)
891 : {
892 45 : g_return_val_if_fail( inst != nullptr, FALSE );
893 45 : g_return_val_if_fail( ref != nullptr, FALSE );
894 :
895 45 : if ( QOF_INSTANCE_GET_CLASS(inst)->refers_to_object != nullptr )
896 : {
897 25 : return QOF_INSTANCE_GET_CLASS(inst)->refers_to_object(inst, ref);
898 : }
899 : else
900 : {
901 : /* Not implemented - default = NO */
902 20 : return FALSE;
903 : }
904 : }
905 :
906 : /* g_object_set/get wrappers */
907 : void
908 9085 : qof_instance_get (const QofInstance *inst, const gchar *first_prop, ...)
909 : {
910 : va_list ap;
911 9085 : g_return_if_fail (QOF_IS_INSTANCE (inst));
912 :
913 9085 : va_start (ap, first_prop);
914 9085 : g_object_get_valist (G_OBJECT (inst), first_prop, ap);
915 9085 : va_end (ap);
916 : }
917 :
918 : void
919 389 : qof_instance_set (QofInstance *inst, const gchar *first_prop, ...)
920 : {
921 : va_list ap;
922 389 : g_return_if_fail (QOF_IS_INSTANCE (inst));
923 :
924 389 : qof_instance_set_dirty (inst);
925 389 : va_start (ap, first_prop);
926 389 : g_object_set_valist (G_OBJECT (inst), first_prop, ap);
927 389 : va_end (ap);
928 : }
929 :
930 :
931 : /* =================================================================== */
932 : /* Entity edit and commit utilities */
933 : /* =================================================================== */
934 :
935 : gboolean
936 694976 : qof_begin_edit (QofInstance *inst)
937 : {
938 : QofInstancePrivate *priv;
939 :
940 694976 : if (!inst) return FALSE;
941 :
942 694975 : priv = GET_PRIVATE(inst);
943 694975 : priv->editlevel++;
944 694975 : if (1 < priv->editlevel) return FALSE;
945 158955 : if (0 >= priv->editlevel)
946 0 : priv->editlevel = 1;
947 :
948 158955 : auto be = qof_book_get_backend(priv->book);
949 158955 : if (be)
950 11041 : be->begin(inst);
951 : else
952 147914 : priv->dirty = TRUE;
953 :
954 158955 : return TRUE;
955 : }
956 :
957 694212 : gboolean qof_commit_edit (QofInstance *inst)
958 : {
959 : QofInstancePrivate *priv;
960 :
961 694212 : if (!inst) return FALSE;
962 :
963 694211 : priv = GET_PRIVATE(inst);
964 694211 : priv->editlevel--;
965 694211 : if (0 < priv->editlevel) return FALSE;
966 :
967 158193 : if (0 > priv->editlevel)
968 : {
969 1 : PERR ("unbalanced call - resetting (was %d)", priv->editlevel);
970 1 : priv->editlevel = 0;
971 : }
972 158193 : return TRUE;
973 : }
974 :
975 : gboolean
976 171211 : qof_commit_edit_part2(QofInstance *inst,
977 : void (*on_error)(QofInstance *, QofBackendError),
978 : void (*on_done)(QofInstance *),
979 : void (*on_free)(QofInstance *))
980 : {
981 : QofInstancePrivate *priv;
982 :
983 171211 : priv = GET_PRIVATE(inst);
984 :
985 171211 : if (priv->dirty &&
986 169192 : !(priv->infant && priv->do_free)) {
987 118378 : qof_collection_mark_dirty(priv->collection);
988 118378 : qof_book_mark_session_dirty(priv->book);
989 : }
990 :
991 : /* See if there's a backend. If there is, invoke it. */
992 171211 : auto be = qof_book_get_backend(priv->book);
993 171211 : if (be)
994 : {
995 : QofBackendError errcode;
996 :
997 : /* clear errors */
998 : do
999 : {
1000 14812 : errcode = be->get_error();
1001 : }
1002 14812 : while (errcode != ERR_BACKEND_NO_ERR);
1003 :
1004 14812 : be->commit(inst);
1005 14812 : errcode = be->get_error();
1006 14812 : if (errcode != ERR_BACKEND_NO_ERR)
1007 : {
1008 : /* XXX Should perform a rollback here */
1009 1 : priv->do_free = FALSE;
1010 :
1011 : /* Push error back onto the stack */
1012 1 : be->set_error (errcode);
1013 1 : if (on_error)
1014 1 : on_error(inst, errcode);
1015 1 : return FALSE;
1016 : }
1017 14811 : if (!priv->dirty) //Cleared if the save was successful
1018 14811 : priv->infant = FALSE;
1019 : }
1020 :
1021 171210 : if (priv->do_free)
1022 : {
1023 53989 : if (on_free)
1024 53989 : on_free(inst);
1025 53989 : return TRUE;
1026 : }
1027 :
1028 117221 : if (on_done)
1029 108838 : on_done(inst);
1030 117221 : return TRUE;
1031 : }
1032 :
1033 : gboolean
1034 1692 : qof_instance_has_kvp (QofInstance *inst)
1035 : {
1036 1692 : return (inst->kvp_data != nullptr && !inst->kvp_data->empty());
1037 : }
1038 :
1039 140 : void qof_instance_set_path_kvp (QofInstance * inst, GValue const * value, std::vector<std::string> const & path)
1040 : {
1041 140 : delete inst->kvp_data->set_path (path, kvp_value_from_gvalue (value));
1042 140 : }
1043 :
1044 : void
1045 2187 : qof_instance_set_kvp (QofInstance * inst, GValue const * value, unsigned count, ...)
1046 : {
1047 2187 : std::vector<std::string> path;
1048 : va_list args;
1049 2187 : va_start (args, count);
1050 4674 : for (unsigned i{0}; i < count; ++i)
1051 4974 : path.push_back (va_arg (args, char const *));
1052 2187 : va_end (args);
1053 2187 : delete inst->kvp_data->set_path (path, kvp_value_from_gvalue (value));
1054 2187 : }
1055 :
1056 : template <typename T> std::optional<T>
1057 226636 : qof_instance_get_path_kvp (QofInstance* inst, const Path& path)
1058 : {
1059 226636 : g_return_val_if_fail (QOF_IS_INSTANCE(inst), std::nullopt);
1060 225904 : auto kvp_value{inst->kvp_data->get_slot(path)};
1061 225904 : return kvp_value ? std::make_optional<T>(kvp_value->get<T>()) : std::nullopt;
1062 : }
1063 :
1064 : template <typename T> void
1065 5560 : qof_instance_set_path_kvp (QofInstance* inst, std::optional<T> value, const Path& path)
1066 : {
1067 5560 : g_return_if_fail (QOF_IS_INSTANCE(inst));
1068 5560 : delete inst->kvp_data->set_path(path, value ? new KvpValue(*value) : nullptr);
1069 5560 : qof_instance_set_dirty (inst);
1070 : }
1071 :
1072 : template std::optional<Time64> qof_instance_get_path_kvp <Time64> (QofInstance*, const Path&);
1073 : template std::optional<GDate> qof_instance_get_path_kvp <GDate> (QofInstance*, const Path&);
1074 : template std::optional<const char*> qof_instance_get_path_kvp <const char*> (QofInstance*, const Path&);
1075 : template std::optional<gnc_numeric> qof_instance_get_path_kvp <gnc_numeric> (QofInstance*, const Path&);
1076 : template std::optional<GncGUID*> qof_instance_get_path_kvp <GncGUID*> (QofInstance*, const Path&);
1077 : template std::optional<int64_t> qof_instance_get_path_kvp <int64_t> (QofInstance*, const Path&);
1078 :
1079 : template void qof_instance_set_path_kvp <Time64> (QofInstance*, std::optional<Time64>, const Path& path);
1080 : template void qof_instance_set_path_kvp <GDate> (QofInstance*, std::optional<GDate>, const Path& path);
1081 : template void qof_instance_set_path_kvp <const char*> (QofInstance*, std::optional<const char*>, const Path& path);
1082 : template void qof_instance_set_path_kvp <gnc_numeric> (QofInstance*, std::optional<gnc_numeric>, const Path& path);
1083 : template void qof_instance_set_path_kvp <GncGUID*> (QofInstance*, std::optional<GncGUID*>, const Path& path);
1084 : template void qof_instance_set_path_kvp <int64_t> (QofInstance*, std::optional<int64_t>, const Path& path);
1085 :
1086 6702 : void qof_instance_get_path_kvp (QofInstance * inst, GValue * value, std::vector<std::string> const & path)
1087 : {
1088 6702 : gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
1089 6702 : }
1090 :
1091 : void
1092 4815 : qof_instance_get_kvp (QofInstance * inst, GValue * value, unsigned count, ...)
1093 : {
1094 4815 : std::vector<std::string> path;
1095 : va_list args;
1096 4815 : va_start (args, count);
1097 12024 : for (unsigned i{0}; i < count; ++i)
1098 14418 : path.push_back (va_arg (args, char const *));
1099 4815 : va_end (args);
1100 4815 : gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
1101 4815 : }
1102 :
1103 : void
1104 7774 : qof_instance_copy_kvp (QofInstance *to, const QofInstance *from)
1105 : {
1106 7774 : delete to->kvp_data;
1107 7774 : to->kvp_data = new KvpFrame(*from->kvp_data);
1108 7774 : }
1109 :
1110 : void
1111 13 : qof_instance_swap_kvp (QofInstance *a, QofInstance *b)
1112 : {
1113 13 : std::swap(a->kvp_data, b->kvp_data);
1114 13 : }
1115 :
1116 : int
1117 462 : qof_instance_compare_kvp (const QofInstance *a, const QofInstance *b)
1118 : {
1119 462 : return compare(a->kvp_data, b->kvp_data);
1120 : }
1121 :
1122 : char*
1123 2 : qof_instance_kvp_as_string (const QofInstance *inst)
1124 : {
1125 2 : auto str{inst->kvp_data->to_string()};
1126 6 : return g_strdup(str.c_str());
1127 2 : }
1128 :
1129 : void
1130 8 : qof_instance_kvp_add_guid (const QofInstance *inst, const char* path,
1131 : time64 time, const char *key,
1132 : const GncGUID *guid)
1133 : {
1134 8 : g_return_if_fail (inst->kvp_data != nullptr);
1135 :
1136 8 : auto container = new KvpFrame;
1137 8 : Time64 t{time};
1138 40 : container->set({key}, new KvpValue(const_cast<GncGUID*>(guid)));
1139 24 : container->set({"date"}, new KvpValue(t));
1140 40 : delete inst->kvp_data->set_path({path}, new KvpValue(container));
1141 32 : }
1142 :
1143 : inline static gboolean
1144 1 : kvp_match_guid (KvpValue *v, std::vector<std::string> const & path, const GncGUID *guid)
1145 : {
1146 1 : if (v->get_type() != KvpValue::Type::FRAME)
1147 0 : return FALSE;
1148 1 : auto frame = v->get<KvpFrame*>();
1149 1 : auto val = frame->get_slot(path);
1150 1 : if (val == nullptr || val->get_type() != KvpValue::Type::GUID)
1151 0 : return FALSE;
1152 1 : auto this_guid = val->get<GncGUID*>();
1153 :
1154 1 : return guid_equal (this_guid, guid);
1155 : }
1156 :
1157 : gboolean
1158 1 : qof_instance_kvp_has_guid (const QofInstance *inst, const char *path,
1159 : const char* key, const GncGUID *guid)
1160 : {
1161 1 : g_return_val_if_fail (inst->kvp_data != nullptr, FALSE);
1162 1 : g_return_val_if_fail (guid != nullptr, FALSE);
1163 :
1164 3 : auto v = inst->kvp_data->get_slot({path});
1165 1 : if (v == nullptr) return FALSE;
1166 :
1167 1 : switch (v->get_type())
1168 : {
1169 1 : case KvpValue::Type::FRAME:
1170 4 : return kvp_match_guid (v, {key}, guid);
1171 : break;
1172 0 : case KvpValue::Type::GLIST:
1173 : {
1174 0 : auto list = v->get<GList*>();
1175 0 : for (auto node = list; node != nullptr; node = node->next)
1176 : {
1177 0 : auto val = static_cast<KvpValue*>(node->data);
1178 0 : if (kvp_match_guid (val, {key}, guid))
1179 : {
1180 0 : return TRUE;
1181 : }
1182 : }
1183 0 : break;
1184 : }
1185 0 : default:
1186 0 : PWARN ("Instance KVP on path %s contains the wrong type.", path);
1187 0 : break;
1188 : }
1189 0 : return FALSE;
1190 4 : }
1191 :
1192 : void
1193 0 : qof_instance_kvp_remove_guid (const QofInstance *inst, const char *path,
1194 : const char *key, const GncGUID *guid)
1195 : {
1196 0 : g_return_if_fail (inst->kvp_data != nullptr);
1197 0 : g_return_if_fail (guid != nullptr);
1198 :
1199 0 : auto v = inst->kvp_data->get_slot({path});
1200 0 : if (v == nullptr) return;
1201 :
1202 0 : switch (v->get_type())
1203 : {
1204 0 : case KvpValue::Type::FRAME:
1205 0 : if (kvp_match_guid (v, {key}, guid))
1206 : {
1207 0 : delete inst->kvp_data->set_path({path}, nullptr);
1208 : }
1209 0 : break;
1210 0 : case KvpValue::Type::GLIST:
1211 : {
1212 0 : auto list = v->get<GList*>();
1213 0 : for (auto node = list; node != nullptr; node = node->next)
1214 : {
1215 0 : auto val = static_cast<KvpValue*>(node->data);
1216 0 : if (kvp_match_guid (val, {key}, guid))
1217 : {
1218 0 : list = g_list_delete_link (list, node);
1219 0 : v->set(list);
1220 0 : delete val;
1221 0 : break;
1222 : }
1223 : }
1224 0 : break;
1225 : }
1226 0 : default:
1227 0 : PWARN ("Instance KVP on path %s contains the wrong type.", path);
1228 0 : break;
1229 : }
1230 0 : return;
1231 0 : }
1232 :
1233 : void
1234 0 : qof_instance_kvp_merge_guids (const QofInstance *target,
1235 : const QofInstance *donor, const char *path)
1236 : {
1237 0 : g_return_if_fail (target != nullptr);
1238 0 : g_return_if_fail (donor != nullptr);
1239 :
1240 0 : if (! qof_instance_has_slot (donor, path)) return;
1241 0 : auto v = donor->kvp_data->get_slot({path});
1242 0 : if (v == nullptr) return;
1243 :
1244 0 : auto target_val = target->kvp_data->get_slot({path});
1245 0 : switch (v->get_type())
1246 : {
1247 0 : case KvpValue::Type::FRAME:
1248 0 : if (target_val)
1249 0 : target_val->add(v);
1250 : else
1251 0 : target->kvp_data->set_path({path}, v);
1252 0 : donor->kvp_data->set({path}, nullptr); //Contents moved, Don't delete!
1253 0 : break;
1254 0 : case KvpValue::Type::GLIST:
1255 0 : if (target_val)
1256 : {
1257 0 : auto list = target_val->get<GList*>();
1258 0 : list = g_list_concat(list, v->get<GList*>());
1259 0 : target_val->set(list);
1260 : }
1261 : else
1262 0 : target->kvp_data->set({path}, v);
1263 0 : donor->kvp_data->set({path}, nullptr); //Contents moved, Don't delete!
1264 0 : break;
1265 0 : default:
1266 0 : PWARN ("Instance KVP on path %s contains the wrong type.", path);
1267 0 : break;
1268 : }
1269 0 : }
1270 :
1271 4 : bool qof_instance_has_path_slot (QofInstance const * inst, std::vector<std::string> const & path)
1272 : {
1273 4 : return inst->kvp_data->get_slot (path) != nullptr;
1274 : }
1275 :
1276 : gboolean
1277 370 : qof_instance_has_slot (const QofInstance *inst, const char *path)
1278 : {
1279 1480 : return inst->kvp_data->get_slot({path}) != nullptr;
1280 740 : }
1281 :
1282 4 : void qof_instance_slot_path_delete (QofInstance const * inst, std::vector<std::string> const & path)
1283 : {
1284 4 : delete inst->kvp_data->set (path, nullptr);
1285 4 : }
1286 :
1287 : void
1288 0 : qof_instance_slot_delete (QofInstance const *inst, char const * path)
1289 : {
1290 0 : delete inst->kvp_data->set ({path}, nullptr);
1291 0 : }
1292 :
1293 5 : void qof_instance_slot_path_delete_if_empty (QofInstance const * inst, std::vector<std::string> const & path)
1294 : {
1295 5 : auto slot = inst->kvp_data->get_slot (path);
1296 5 : if (slot)
1297 : {
1298 5 : auto frame = slot->get <KvpFrame*> ();
1299 5 : if (frame && frame->empty())
1300 2 : delete inst->kvp_data->set (path, nullptr);
1301 : }
1302 5 : }
1303 :
1304 : void
1305 455 : qof_instance_slot_delete_if_empty (QofInstance const *inst, char const * path)
1306 : {
1307 1365 : auto slot = inst->kvp_data->get_slot ({path});
1308 455 : if (slot)
1309 : {
1310 2 : auto frame = slot->get <KvpFrame*> ();
1311 2 : if (frame && frame->empty ())
1312 0 : delete inst->kvp_data->set ({path}, nullptr);
1313 : }
1314 1365 : }
1315 :
1316 : std::vector <std::pair <std::string, KvpValue*>>
1317 0 : qof_instance_get_slots_prefix (QofInstance const * inst, std::string const & prefix)
1318 : {
1319 0 : std::vector <std::pair <std::string, KvpValue*>> ret;
1320 0 : inst->kvp_data->for_each_slot_temp ([&prefix, &ret] (std::string const & key, KvpValue * val) {
1321 0 : if (key.find (prefix) == 0)
1322 0 : ret.emplace_back (key, val);
1323 0 : });
1324 0 : return ret;
1325 : }
1326 :
1327 : namespace {
1328 : struct wrap_param
1329 : {
1330 : void (*proc)(const char*, const GValue*, void*);
1331 : void *user_data;
1332 : };
1333 : }
1334 :
1335 : static void
1336 0 : wrap_gvalue_function (const char* key, KvpValue *val, wrap_param & param)
1337 : {
1338 0 : GValue gv = G_VALUE_INIT;
1339 0 : if (val->get_type() != KvpValue::Type::FRAME)
1340 0 : gvalue_from_kvp_value(val, &gv);
1341 : else
1342 : {
1343 0 : g_value_init (&gv, G_TYPE_STRING);
1344 0 : g_value_set_string (&gv, nullptr);
1345 : }
1346 0 : param.proc(key, &gv, param.user_data);
1347 0 : g_value_unset (&gv);
1348 0 : }
1349 :
1350 : void
1351 0 : qof_instance_foreach_slot (const QofInstance *inst, const char* head, const char* category,
1352 : void (*proc)(const char*, const GValue*, void*), void* data)
1353 : {
1354 0 : std::vector<std::string> path {head};
1355 0 : if (category)
1356 0 : path.emplace_back (category);
1357 :
1358 0 : auto slot = inst->kvp_data->get_slot(path);
1359 0 : if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
1360 0 : return;
1361 0 : auto frame = slot->get<KvpFrame*>();
1362 0 : wrap_param new_data {proc, data};
1363 0 : frame->for_each_slot_temp(&wrap_gvalue_function, new_data);
1364 0 : }
1365 :
1366 : /* ========================== END OF FILE ======================= */
1367 :
|