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