Branch data 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 : 10406449 : G_DEFINE_TYPE_WITH_PRIVATE(QofInstance, qof_instance, G_TYPE_OBJECT)
116 : 111292 : 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 : 75 : static void qof_instance_class_init(QofInstanceClass *klass)
130 : : {
131 : 75 : GObjectClass *object_class = G_OBJECT_CLASS(klass);
132 : 75 : object_class->finalize = qof_instance_finalize;
133 : 75 : object_class->dispose = qof_instance_dispose;
134 : 75 : object_class->set_property = qof_instance_set_property;
135 : 75 : object_class->get_property = qof_instance_get_property;
136 : :
137 : 75 : klass->get_display_name = nullptr;
138 : 75 : klass->refers_to_object = nullptr;
139 : 75 : klass->get_typed_referring_object_list = nullptr;
140 : :
141 : : g_object_class_install_property
142 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : (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 : 75 : }
243 : :
244 : : static void
245 : 149475 : qof_instance_init (QofInstance *inst)
246 : : {
247 : : QofInstancePrivate *priv;
248 : :
249 : 149475 : priv = GET_PRIVATE(inst);
250 : 149475 : priv->book = nullptr;
251 : 149475 : inst->kvp_data = new KvpFrame;
252 : 149475 : priv->last_update = 0;
253 : 149475 : priv->editlevel = 0;
254 : 149475 : priv->do_free = FALSE;
255 : 149475 : priv->dirty = FALSE;
256 : 149475 : priv->infant = TRUE;
257 : 149475 : }
258 : :
259 : : void
260 : 91674 : qof_instance_init_data (QofInstance *inst, QofIdType type, QofBook *book)
261 : : {
262 : : QofInstancePrivate *priv;
263 : : QofCollection *col;
264 : : QofIdType col_type;
265 : :
266 : 91674 : g_return_if_fail(QOF_IS_INSTANCE(inst));
267 : 91674 : priv = GET_PRIVATE(inst);
268 : 91674 : g_return_if_fail(!priv->book);
269 : :
270 : 91674 : priv->book = book;
271 : 91674 : col = qof_book_get_collection (book, type);
272 : 91674 : 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 : 91674 : col_type = qof_collection_get_type(col);
278 : 91674 : if (g_strcmp0(col_type, type))
279 : : {
280 : 0 : PERR ("attempt to insert \"%s\" into \"%s\"", type, col_type);
281 : 0 : return;
282 : : }
283 : 91674 : priv = GET_PRIVATE(inst);
284 : 91674 : inst->e_type = static_cast<QofIdType>(CACHE_INSERT (type));
285 : :
286 : : do
287 : : {
288 : 91674 : guid_replace(&priv->guid);
289 : :
290 : 91674 : if (nullptr == qof_collection_lookup_entity (col, &priv->guid))
291 : 91674 : break;
292 : :
293 : 0 : PWARN("duplicate id created, trying again");
294 : : }
295 : : while (1);
296 : :
297 : 91674 : priv->collection = col;
298 : :
299 : 91674 : qof_collection_insert_entity (col, inst);
300 : : }
301 : :
302 : : static void
303 : 118962 : qof_instance_dispose (GObject *instp)
304 : : {
305 : : QofInstancePrivate *priv;
306 : 118962 : QofInstance* inst = QOF_INSTANCE(instp);
307 : :
308 : 118962 : priv = GET_PRIVATE(instp);
309 : 118962 : if (priv->collection)
310 : 103737 : qof_collection_remove_entity(inst);
311 : :
312 : 118962 : CACHE_REMOVE(inst->e_type);
313 : 118962 : inst->e_type = nullptr;
314 : :
315 : 118962 : G_OBJECT_CLASS(qof_instance_parent_class)->dispose(instp);
316 : 118962 : }
317 : :
318 : : static void
319 : 111292 : qof_instance_finalize_real (GObject *instp)
320 : : {
321 : : QofInstancePrivate *priv;
322 : 111292 : QofInstance* inst = QOF_INSTANCE(instp);
323 : :
324 : 111292 : delete inst->kvp_data;
325 : 111292 : inst->kvp_data = nullptr;
326 : :
327 : 111292 : priv = GET_PRIVATE(inst);
328 : 111292 : priv->editlevel = 0;
329 : 111292 : priv->do_free = FALSE;
330 : 111292 : priv->dirty = FALSE;
331 : 111292 : }
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 : 467579 : qof_instance_get_guid (gconstpointer inst)
447 : : {
448 : : QofInstancePrivate *priv;
449 : :
450 : 467579 : if (!inst) return nullptr;
451 : 467574 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), guid_null());
452 : 467574 : priv = GET_PRIVATE(inst);
453 : 467574 : return &(priv->guid);
454 : : }
455 : :
456 : : const GncGUID *
457 : 65648 : qof_entity_get_guid (gconstpointer ent)
458 : : {
459 : 65648 : return ent ? qof_instance_get_guid(ent) : guid_null();
460 : : }
461 : :
462 : : void
463 : 59764 : qof_instance_set_guid (gpointer ptr, const GncGUID *guid)
464 : : {
465 : : QofInstancePrivate *priv;
466 : : QofInstance *inst;
467 : : QofCollection *col;
468 : :
469 : 59764 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
470 : :
471 : 59764 : inst = QOF_INSTANCE(ptr);
472 : 59764 : priv = GET_PRIVATE(inst);
473 : 59764 : if (guid_equal (guid, &priv->guid))
474 : 4862 : 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 : 2789 : qof_instance_copy_guid (gpointer to, gconstpointer from)
484 : : {
485 : 2789 : g_return_if_fail(QOF_IS_INSTANCE(to));
486 : 2789 : g_return_if_fail(QOF_IS_INSTANCE(from));
487 : :
488 : 2789 : GET_PRIVATE(to)->guid = GET_PRIVATE(from)->guid;
489 : : }
490 : :
491 : : gint
492 : 1157 : qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
493 : : {
494 : : const QofInstancePrivate *priv1, *priv2;
495 : :
496 : 1157 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr1), -1);
497 : 1157 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr2), 1);
498 : :
499 : 1157 : priv1 = GET_PRIVATE(ptr1);
500 : 1157 : priv2 = GET_PRIVATE(ptr2);
501 : :
502 : 1157 : return guid_compare(&priv1->guid, &priv2->guid);
503 : : }
504 : :
505 : : QofCollection *
506 : 305302 : qof_instance_get_collection (gconstpointer ptr)
507 : : {
508 : :
509 : 305302 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr), nullptr);
510 : 305302 : return GET_PRIVATE(ptr)->collection;
511 : : }
512 : :
513 : : void
514 : 346767 : qof_instance_set_collection (gconstpointer ptr, QofCollection *col)
515 : : {
516 : 346767 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
517 : 346767 : GET_PRIVATE(ptr)->collection = col;
518 : : }
519 : :
520 : : QofBook *
521 : 944696 : qof_instance_get_book (gconstpointer inst)
522 : : {
523 : 944696 : if (!inst) return nullptr;
524 : 944695 : g_return_val_if_fail(QOF_IS_INSTANCE(inst), nullptr);
525 : 944695 : 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 : 7630 : qof_instance_copy_book (gpointer ptr1, gconstpointer ptr2)
537 : : {
538 : 7630 : g_return_if_fail(QOF_IS_INSTANCE(ptr1));
539 : 7630 : g_return_if_fail(QOF_IS_INSTANCE(ptr2));
540 : :
541 : 7630 : GET_PRIVATE(ptr1)->book = GET_PRIVATE(ptr2)->book;
542 : : }
543 : :
544 : : gboolean
545 : 9966 : qof_instance_books_equal (gconstpointer ptr1, gconstpointer ptr2)
546 : : {
547 : : const QofInstancePrivate *priv1, *priv2;
548 : :
549 : 9966 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr1), FALSE);
550 : 9966 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr2), FALSE);
551 : :
552 : 9966 : priv1 = GET_PRIVATE(ptr1);
553 : 9966 : priv2 = GET_PRIVATE(ptr2);
554 : :
555 : 9966 : 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 : 2560 : qof_instance_get_slots (const QofInstance *inst)
561 : : {
562 : 2560 : if (!inst) return nullptr;
563 : 2560 : 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 : 51423 : qof_instance_get_editlevel (gconstpointer ptr)
592 : : {
593 : 51423 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr), 0);
594 : 51423 : return GET_PRIVATE(ptr)->editlevel;
595 : : }
596 : :
597 : 9185 : void qof_instance_increase_editlevel (gpointer ptr)
598 : : {
599 : 9185 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
600 : 9185 : GET_PRIVATE(ptr)->editlevel++;
601 : : }
602 : :
603 : 6811 : void qof_instance_decrease_editlevel (gpointer ptr)
604 : : {
605 : 6811 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
606 : 6811 : 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 : 9 : return lpriv->last_update < rpriv->last_update ? -1 :
627 : 9 : lpriv->last_update > rpriv->last_update ? 1 : 0;
628 : : }
629 : :
630 : : gboolean
631 : 237724 : qof_instance_get_destroying (gconstpointer ptr)
632 : : {
633 : 237724 : g_return_val_if_fail(QOF_IS_INSTANCE(ptr), FALSE);
634 : 237724 : return GET_PRIVATE(ptr)->do_free;
635 : : }
636 : :
637 : : void
638 : 50248 : qof_instance_set_destroying (gpointer ptr, gboolean value)
639 : : {
640 : 50248 : g_return_if_fail(QOF_IS_INSTANCE(ptr));
641 : 50248 : 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 : 36841 : qof_instance_get_dirty (QofInstance *inst)
681 : : {
682 : : QofInstancePrivate *priv;
683 : :
684 : 36841 : if (!inst)
685 : : {
686 : 1 : return FALSE;
687 : : }
688 : :
689 : 36840 : priv = GET_PRIVATE(inst);
690 : 36840 : return priv->dirty;
691 : : }
692 : :
693 : : void
694 : 617073 : qof_instance_set_dirty(QofInstance* inst)
695 : : {
696 : : QofInstancePrivate *priv;
697 : :
698 : 617073 : priv = GET_PRIVATE(inst);
699 : 617073 : priv->dirty = TRUE;
700 : 617073 : }
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 : 4878 : qof_instance_copy_version (gpointer to, gconstpointer from)
725 : : {
726 : 4878 : g_return_if_fail(QOF_IS_INSTANCE(to));
727 : 4878 : g_return_if_fail(QOF_IS_INSTANCE(from));
728 : 4878 : 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 : 90 : get_referring_object_instance_helper(QofInstance* inst, gpointer user_data)
801 : : {
802 : 90 : QofInstance** pInst = (QofInstance**)user_data;
803 : :
804 : 90 : if (*pInst == nullptr)
805 : : {
806 : 18 : *pInst = inst;
807 : : }
808 : 90 : }
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 : 107 : get_typed_referring_object_instance_helper(QofInstance* inst, gpointer user_data)
844 : : {
845 : 107 : GetReferringObjectHelperData* data = (GetReferringObjectHelperData*)user_data;
846 : :
847 : 107 : if (qof_instance_refers_to_object(inst, data->inst))
848 : : {
849 : 36 : data->list = g_list_prepend(data->list, inst);
850 : : }
851 : 107 : }
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 : 109 : gboolean qof_instance_refers_to_object(const QofInstance* inst, const QofInstance* ref)
891 : : {
892 : 109 : g_return_val_if_fail( inst != nullptr, FALSE );
893 : 109 : g_return_val_if_fail( ref != nullptr, FALSE );
894 : :
895 : 109 : if ( QOF_INSTANCE_GET_CLASS(inst)->refers_to_object != nullptr )
896 : : {
897 : 65 : return QOF_INSTANCE_GET_CLASS(inst)->refers_to_object(inst, ref);
898 : : }
899 : : else
900 : : {
901 : : /* Not implemented - default = NO */
902 : 44 : return FALSE;
903 : : }
904 : : }
905 : :
906 : : /* g_object_set/get wrappers */
907 : : void
908 : 8584 : qof_instance_get (const QofInstance *inst, const gchar *first_prop, ...)
909 : : {
910 : : va_list ap;
911 : 8584 : g_return_if_fail (QOF_IS_INSTANCE (inst));
912 : :
913 : 8584 : va_start (ap, first_prop);
914 : 8584 : g_object_get_valist (G_OBJECT (inst), first_prop, ap);
915 : 8584 : va_end (ap);
916 : : }
917 : :
918 : : void
919 : 384 : qof_instance_set (QofInstance *inst, const gchar *first_prop, ...)
920 : : {
921 : : va_list ap;
922 : 384 : g_return_if_fail (QOF_IS_INSTANCE (inst));
923 : :
924 : 384 : qof_instance_set_dirty (inst);
925 : 384 : va_start (ap, first_prop);
926 : 384 : g_object_set_valist (G_OBJECT (inst), first_prop, ap);
927 : 384 : va_end (ap);
928 : : }
929 : :
930 : :
931 : : /* =================================================================== */
932 : : /* Entity edit and commit utilities */
933 : : /* =================================================================== */
934 : :
935 : : gboolean
936 : 662635 : qof_begin_edit (QofInstance *inst)
937 : : {
938 : : QofInstancePrivate *priv;
939 : :
940 : 662635 : if (!inst) return FALSE;
941 : :
942 : 662634 : priv = GET_PRIVATE(inst);
943 : 662634 : priv->editlevel++;
944 : 662634 : if (1 < priv->editlevel) return FALSE;
945 : 150918 : if (0 >= priv->editlevel)
946 : 0 : priv->editlevel = 1;
947 : :
948 : 150918 : auto be = qof_book_get_backend(priv->book);
949 : 150918 : if (be)
950 : 11041 : be->begin(inst);
951 : : else
952 : 139877 : priv->dirty = TRUE;
953 : :
954 : 150918 : return TRUE;
955 : : }
956 : :
957 : 661871 : gboolean qof_commit_edit (QofInstance *inst)
958 : : {
959 : : QofInstancePrivate *priv;
960 : :
961 : 661871 : if (!inst) return FALSE;
962 : :
963 : 661870 : priv = GET_PRIVATE(inst);
964 : 661870 : priv->editlevel--;
965 : 661870 : if (0 < priv->editlevel) return FALSE;
966 : :
967 : 150156 : if (0 > priv->editlevel)
968 : : {
969 : 1 : PERR ("unbalanced call - resetting (was %d)", priv->editlevel);
970 : 1 : priv->editlevel = 0;
971 : : }
972 : 150156 : return TRUE;
973 : : }
974 : :
975 : : gboolean
976 : 163034 : 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 : 163034 : priv = GET_PRIVATE(inst);
984 : :
985 : 163034 : if (priv->dirty &&
986 : 161015 : !(priv->infant && priv->do_free)) {
987 : 114044 : qof_collection_mark_dirty(priv->collection);
988 : 114044 : qof_book_mark_session_dirty(priv->book);
989 : : }
990 : :
991 : : /* See if there's a backend. If there is, invoke it. */
992 : 163034 : auto be = qof_book_get_backend(priv->book);
993 : 163034 : 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 : 163033 : if (priv->do_free)
1022 : : {
1023 : 50146 : if (on_free)
1024 : 50146 : on_free(inst);
1025 : 50146 : return TRUE;
1026 : : }
1027 : :
1028 : 112887 : if (on_done)
1029 : 104587 : on_done(inst);
1030 : 112887 : return TRUE;
1031 : : }
1032 : :
1033 : : gboolean
1034 : 1682 : qof_instance_has_kvp (QofInstance *inst)
1035 : : {
1036 : 1682 : 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 : 2181 : qof_instance_set_kvp (QofInstance * inst, GValue const * value, unsigned count, ...)
1046 : : {
1047 : 2181 : std::vector<std::string> path;
1048 : : va_list args;
1049 : 2181 : va_start (args, count);
1050 : 4658 : for (unsigned i{0}; i < count; ++i)
1051 : 4954 : path.push_back (va_arg (args, char const *));
1052 : 2181 : va_end (args);
1053 : 2181 : delete inst->kvp_data->set_path (path, kvp_value_from_gvalue (value));
1054 : 2181 : }
1055 : :
1056 : : template <typename T> std::optional<T>
1057 : 220599 : qof_instance_get_path_kvp (QofInstance* inst, const Path& path)
1058 : : {
1059 : 220599 : g_return_val_if_fail (QOF_IS_INSTANCE(inst), std::nullopt);
1060 : 219867 : auto kvp_value{inst->kvp_data->get_slot(path)};
1061 : 219867 : return kvp_value ? std::make_optional<T>(kvp_value->get<T>()) : std::nullopt;
1062 : : }
1063 : :
1064 : : template <typename T> void
1065 : 5526 : qof_instance_set_path_kvp (QofInstance* inst, std::optional<T> value, const Path& path)
1066 : : {
1067 : 5526 : g_return_if_fail (QOF_IS_INSTANCE(inst));
1068 : 5526 : delete inst->kvp_data->set_path(path, value ? new KvpValue(*value) : nullptr);
1069 : 5526 : 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 : 6597 : void qof_instance_get_path_kvp (QofInstance * inst, GValue * value, std::vector<std::string> const & path)
1087 : : {
1088 : 6597 : gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
1089 : 6597 : }
1090 : :
1091 : : void
1092 : 4375 : qof_instance_get_kvp (QofInstance * inst, GValue * value, unsigned count, ...)
1093 : : {
1094 : 4375 : std::vector<std::string> path;
1095 : : va_list args;
1096 : 4375 : va_start (args, count);
1097 : 11021 : for (unsigned i{0}; i < count; ++i)
1098 : 13292 : path.push_back (va_arg (args, char const *));
1099 : 4375 : va_end (args);
1100 : 4375 : gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
1101 : 4375 : }
1102 : :
1103 : : void
1104 : 7719 : qof_instance_copy_kvp (QofInstance *to, const QofInstance *from)
1105 : : {
1106 : 7719 : delete to->kvp_data;
1107 : 7719 : to->kvp_data = new KvpFrame(*from->kvp_data);
1108 : 7719 : }
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 : 32 : container->set({key}, new KvpValue(const_cast<GncGUID*>(guid)));
1139 : 16 : container->set({"date"}, new KvpValue(t));
1140 : 32 : delete inst->kvp_data->set_path({path}, new KvpValue(container));
1141 : 48 : }
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 : 0 : if (v == nullptr) return FALSE;
1166 : :
1167 : 1 : switch (v->get_type())
1168 : : {
1169 : 1 : case KvpValue::Type::FRAME:
1170 : 3 : 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 : 6 : }
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 : 365 : qof_instance_has_slot (const QofInstance *inst, const char *path)
1278 : : {
1279 : 1460 : return inst->kvp_data->get_slot({path}) != nullptr;
1280 : 1095 : }
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 : 1367 : }
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 : :
|