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