1 /* Fo
2 * fo-node.c: Base class for objects that are nodes in a tree
3 *
4 * Copyright (C) 2001 Sun Microsystems
5 * Copyright (C) 2007-2010 Menteith Consulting Ltd
6 *
7 * See COPYING for the status of this software.
8 */
9
10 #include "fo-utils.h"
11 #include "fo-node-private.h"
12
13 /**
14 * SECTION:fo-node
15 * @short_description: Object for making trees
16 *
17 * #FoObject child type that makes trees.
18 */
19
20 enum {
21 PROP_0,
22 PROP_PARENT,
23 PROP_NEXT_SIBLING,
24 PROP_FIRST_CHILD
25 };
26
27 static void fo_node_init (FoNode *object);
28 static void fo_node_base_class_init (FoNodeClass *klass);
29 static void fo_node_class_init (FoNodeClass *klass);
30 static void fo_node_get_property (GObject *object,
31 guint prop_id,
32 GValue *value,
33 GParamSpec *pspec);
34 static void fo_node_set_property (GObject *object,
35 guint prop_id,
36 const GValue *value,
37 GParamSpec *pspec);
38
39 static void _dispose (GObject *object);
40
41 static void _debug_dump (FoObject *object,
42 gint depth);
43 static void _debug_dump_tree (FoNode *fo_node,
44 gint depth);
45 static gchar* _sprintf (FoObject *object);
46 static FoNode* _insert_default (FoNode *parent,
47 gint position,
48 FoNode *fo_node);
49 static FoNode* _insert_before_default (FoNode *parent,
50 FoNode *sibling,
51 FoNode *fo_node);
52 static FoNode* _insert_after_default (FoNode *parent,
53 FoNode *sibling,
54 FoNode *fo_node);
55 static void _unlink_with_next_siblings_default (FoNode *fo_node);
56 static FoNode* _insert_with_next_siblings_default (FoNode *parent,
57 gint position,
58 FoNode *fo_node);
59 static FoNode* _prepend_default (FoNode *parent,
60 FoNode *fo_node);
61 static FoNode* _append_default (FoNode *parent,
62 FoNode *fo_node);
63 static void _log_warning (FoObject *object,
64 GError **warning);
65 static void _log_error (FoObject *object,
66 GError **error);
67 static gboolean _log_or_propagate_error (FoObject *fo_object,
68 GError **dest,
69 GError *src);
70 static gboolean _maybe_propagate_error (FoObject *fo_object,
71 GError **dest,
72 GError *src,
73 gboolean continue_after_error);
74
75 static gpointer parent_class;
76
77 /**
78 * fo_node_get_type:
79 *
80 * Register the #FoNode object type.
81 *
82 * Return value: #GType value of the #FoNode object type.
83 **/
84 GType
fo_node_get_type(void)85 fo_node_get_type (void)
86 {
87 static GType object_type = 0;
88
89 if (!object_type)
90 {
91 static const GTypeInfo object_info =
92 {
93 sizeof (FoNodeClass),
94 (GBaseInitFunc) fo_node_base_class_init,
95 (GBaseFinalizeFunc) NULL,
96 (GClassInitFunc) fo_node_class_init,
97 NULL, /* class_finalize */
98 NULL, /* class_data */
99 sizeof (FoNode),
100 0, /* n_preallocs */
101 (GInstanceInitFunc) fo_node_init,
102 NULL /* value_table */
103 };
104
105 object_type = g_type_register_static (FO_TYPE_OBJECT,
106 "FoNode",
107 &object_info,
108 G_TYPE_FLAG_ABSTRACT);
109 }
110
111 return object_type;
112 }
113
114 /**
115 * fo_node_init:
116 * @fo_node: #FoNode object to initialise.
117 *
118 * Implements #GInstanceInitFunc for #FoNode.
119 **/
120 void
fo_node_init(FoNode * object)121 fo_node_init (FoNode *object)
122 {
123 object->node = g_node_new ((gpointer *) object);
124 }
125
126 /**
127 * fo_node_base_class_init:
128 * @klass: #FoNodeClass base class object to initialise.
129 *
130 * Implements #GBaseInitFunc for #FoNodeClass.
131 **/
132 void
fo_node_base_class_init(FoNodeClass * klass)133 fo_node_base_class_init (FoNodeClass *klass)
134 {
135 FoObjectClass *fo_object_class = FO_OBJECT_CLASS (klass);
136
137 fo_object_class->debug_dump = _debug_dump;
138 fo_object_class->print_sprintf = _sprintf;
139 fo_object_class->log_warning = _log_warning;
140 fo_object_class->log_error = _log_error;
141 fo_object_class->log_or_propagate_error = _log_or_propagate_error;
142 fo_object_class->maybe_propagate_error = _maybe_propagate_error;
143
144 klass->debug_dump_tree = _debug_dump_tree;
145 klass->insert = _insert_default;
146 klass->insert_before = _insert_before_default;
147 klass->insert_after = _insert_after_default;
148 klass->insert_with_next_siblings =
149 _insert_with_next_siblings_default;
150 klass->unlink_with_next_siblings =
151 _unlink_with_next_siblings_default;
152 klass->prepend = _prepend_default;
153 klass->append = _append_default;
154 }
155
156 /**
157 * fo_node_class_init:
158 * @klass: #FoNodeClass object to initialise.
159 *
160 * Implements #GClassInitFunc for #FoNodeClass.
161 **/
162 void
fo_node_class_init(FoNodeClass * klass)163 fo_node_class_init (FoNodeClass *klass)
164 {
165 GObjectClass *object_class = G_OBJECT_CLASS (klass);
166
167 parent_class = g_type_class_peek_parent (klass);
168
169 object_class->dispose = _dispose;
170
171 object_class->set_property = fo_node_set_property;
172 object_class->get_property = fo_node_get_property;
173
174 g_object_class_install_property
175 (object_class,
176 PROP_PARENT,
177 g_param_spec_object ("parent",
178 _("parent node"),
179 _("Parent node in the node tree"),
180 FO_TYPE_NODE,
181 G_PARAM_READABLE));
182 g_object_class_install_property
183 (object_class,
184 PROP_NEXT_SIBLING,
185 g_param_spec_object ("next-sibling",
186 _("Next sibling node"),
187 _("Next sibling node in the node tree"),
188 FO_TYPE_NODE,
189 G_PARAM_READABLE));
190 g_object_class_install_property
191 (object_class,
192 PROP_FIRST_CHILD,
193 g_param_spec_object ("first-child",
194 _("first child node"),
195 _("First child node in the node tree"),
196 FO_TYPE_NODE,
197 G_PARAM_READABLE));
198 }
199
200 /**
201 * _dispose:
202 * @object: #FoNode object to finalize.
203 *
204 * Implements #GObjectFinalizeFunc for #FoNode.
205 **/
206 void
_dispose(GObject * object)207 _dispose (GObject *object)
208 {
209 FoNode *node;
210
211 node = FO_NODE (object);
212 /* Node should already be removed from the FoNode tree, since this
213 destroys the GNode subtree remaining under node */
214 if (node->node != NULL)
215 {
216 g_node_destroy (node->node);
217 node->node = NULL;
218 }
219
220 G_OBJECT_CLASS (parent_class)->dispose (object);
221 }
222
223 /**
224 * fo_node_get_property:
225 * @object: #GObject whose property will be retrieved.
226 * @prop_id: Property ID assigned when property registered.
227 * @value: #GValue to set with property value.
228 * @pspec: Parameter specification for this property type.
229 *
230 * Implements #GObjectGetPropertyFunc for #FoNode.
231 **/
232 void
fo_node_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)233 fo_node_get_property (GObject *object,
234 guint param_id,
235 GValue *value,
236 GParamSpec *pspec)
237 {
238 FoNode *fo_node = FO_NODE (object);
239
240 switch (param_id)
241 {
242 case PROP_PARENT:
243 g_value_set_object (value, G_OBJECT (fo_node_parent (fo_node)));
244 break;
245 case PROP_NEXT_SIBLING:
246 g_value_set_object (value, G_OBJECT (fo_node_next_sibling (fo_node)));
247 break;
248 case PROP_FIRST_CHILD:
249 g_value_set_object (value, G_OBJECT (fo_node_first_child (fo_node)));
250 break;
251 default:
252 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
253 break;
254 }
255 }
256
257 /**
258 * fo_node_set_property:
259 * @object: #GObject whose property will be set.
260 * @prop_id: Property ID assigned when property registered.
261 * @value: New value for property.
262 * @pspec: Parameter specification for this property type.
263 *
264 * Implements #GObjectSetPropertyFunc for #FoNode.
265 **/
266 void
fo_node_set_property(GObject * object,guint param_id,const GValue * value G_GNUC_UNUSED,GParamSpec * pspec)267 fo_node_set_property (GObject *object,
268 guint param_id,
269 const GValue *value G_GNUC_UNUSED,
270 GParamSpec *pspec)
271 {
272 switch (param_id)
273 {
274 default:
275 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
276 break;
277 }
278 }
279
280 /**
281 * fo_node_new:
282 *
283 * Creates a new #FoNode initialized to default value.
284 *
285 * Return value: the new #FoNode
286 **/
287 FoNode *
fo_node_new(void)288 fo_node_new (void)
289 {
290 FoNode *object;
291
292 object = FO_NODE (g_object_new (fo_node_get_type (), NULL));
293
294 return object;
295 }
296
297 /**
298 * _debug_dump:
299 * @object: #FoObject to be dumped.
300 * @depth: Relative indent to add to the output.
301 *
302 * Implements #FoObject debug_dump method for #FoNode.
303 **/
304 static void
_debug_dump(FoObject * object,gint depth)305 _debug_dump (FoObject *object,
306 gint depth)
307 {
308 g_return_if_fail (object != NULL);
309 g_return_if_fail (FO_IS_NODE (object));
310
311 gchar *indent = g_strnfill (depth * 2, ' ');
312 gchar* object_sprintf = fo_object_debug_sprintf (object);
313
314 g_log (G_LOG_DOMAIN,
315 G_LOG_LEVEL_DEBUG,
316 "%s%s",
317 indent,
318 object_sprintf);
319
320 g_free (object_sprintf);
321 g_free (indent);
322
323 FO_NODE_GET_CLASS (object)->debug_dump_properties (FO_NODE (object),
324 depth + 2);
325 FoNode *child = fo_node_first_child (FO_NODE (object));
326 while (child != NULL)
327 {
328 fo_object_debug_dump (child,
329 depth + 1);
330
331 child = fo_node_next_sibling (child);
332 }
333 }
334
335 /**
336 * _debug_dump_tree:
337 * @node: #FoNode to be dumped.
338 * @depth: Relative indent to add to the output.
339 *
340 * Implements #FoNode debug_dump_tree method for #FoNode.
341 **/
342 static void
_debug_dump_tree(FoNode * fo_node,gint depth)343 _debug_dump_tree (FoNode *fo_node,
344 gint depth)
345 {
346 gchar *indent = g_strnfill (depth * 2, ' ');
347 gchar* fo_node_sprintf;
348 FoNode *child;
349
350 g_return_if_fail (fo_node != NULL);
351 g_return_if_fail (FO_IS_NODE (fo_node));
352
353 fo_node_sprintf = fo_object_debug_sprintf (fo_node);
354
355 g_log (G_LOG_DOMAIN,
356 G_LOG_LEVEL_DEBUG,
357 "%s%s",
358 indent,
359 fo_node_sprintf);
360
361 g_free (fo_node_sprintf);
362 g_free (indent);
363
364 child = fo_node_first_child (fo_node);
365 while (child != NULL)
366 {
367 fo_node_debug_dump_tree (child,
368 depth + 1);
369
370 child = fo_node_next_sibling (child);
371 }
372 }
373
374 /**
375 * fo_node_debug_dump_tree:
376 * @fo_node: #FoNode to be dumped.
377 * @depth: Relative indent to add to the output.
378 *
379 * Logs the tree structure beginning at @fo_node.
380 **/
381 void
fo_node_debug_dump_tree(FoNode * fo_node,gint depth)382 fo_node_debug_dump_tree (FoNode *fo_node,
383 gint depth)
384 {
385 gchar *indent = g_strnfill (depth * 2, ' ');
386
387 if (fo_node == NULL)
388 {
389 g_log (G_LOG_DOMAIN,
390 G_LOG_LEVEL_DEBUG,
391 "%s(null)",
392 indent);
393 }
394 else if (!G_IS_OBJECT (fo_node))
395 {
396 g_log (G_LOG_DOMAIN,
397 G_LOG_LEVEL_DEBUG,
398 "%sNot a GObject: %p",
399 indent,
400 fo_node);
401 }
402 else if (!FO_IS_NODE (fo_node))
403 {
404 g_log (G_LOG_DOMAIN,
405 G_LOG_LEVEL_DEBUG,
406 "%sGObject but not an FoFo_Node:: %s (%p : %d)",
407 indent,
408 g_type_name (G_TYPE_FROM_INSTANCE (fo_node)),
409 fo_node,
410 ((GObject *) fo_node)->ref_count);
411 }
412 else
413 {
414 FO_NODE_GET_CLASS (fo_node)->debug_dump_tree (fo_node, depth);
415 }
416
417 g_free (indent);
418 }
419
420 /**
421 * _sprintf:
422 * @object: #FoNode to be printed.
423 *
424 * Creates string representation of value of @object.
425 *
426 * String must be freed by caller.
427 *
428 * Return value: String representation of @object.
429 **/
430 static gchar*
_sprintf(FoObject * object)431 _sprintf (FoObject *object)
432 {
433 g_return_val_if_fail (object != NULL, NULL);
434 g_return_val_if_fail (FO_IS_NODE (object), NULL);
435
436 return (g_strdup_printf("%s",
437 g_type_name (G_TYPE_FROM_INSTANCE (object))));
438 }
439
440
441 /**
442 * fo_node_get_ancestor_or_self_by_type:
443 * @node: #FoNode at which to begin.
444 * @type: Required #GType of ancestor node.
445 *
446 * Find the nearest ancestor node, or @node itself, with the same
447 * #GType as @type.
448 *
449 * Does not change the ref count of any node.
450 *
451 * Return value: #FoNode ancestor (or self) with required #GType, or NULL.
452 **/
453 FoNode*
fo_node_get_ancestor_or_self_by_type(FoNode * node,const GType type)454 fo_node_get_ancestor_or_self_by_type (FoNode *node,
455 const GType type)
456 {
457 FoNode *use_node;
458
459 g_return_val_if_fail (FO_IS_NODE (node), NULL);
460
461 if (type != 0)
462 {
463 use_node = node;
464
465 while (use_node && !g_type_is_a (G_TYPE_FROM_INSTANCE (use_node), type))
466 {
467 use_node = fo_node_parent (use_node);
468 }
469 }
470 else
471 {
472 use_node = NULL;
473 }
474
475 return use_node;
476 }
477
478 /**
479 * fo_node_get_ancestor_or_self_by_name:
480 * @node: #FoNode at which to begin.
481 * @name: Required name of ancestor node.
482 *
483 * Find the nearest ancestor node, or @node itself, with the same
484 * name as @name.
485 *
486 * Does not change the ref count of any node.
487 *
488 * Return value: #FoNode ancestor (or self) with required #GType, or NULL.
489 **/
490 FoNode*
fo_node_get_ancestor_or_self_by_name(FoNode * node,const gchar * name)491 fo_node_get_ancestor_or_self_by_name (FoNode *node,
492 const gchar *name)
493 {
494 GType type;
495
496 g_return_val_if_fail (FO_IS_NODE (node), NULL);
497 g_return_val_if_fail (name != NULL, NULL);
498
499 type = g_type_from_name (name);
500
501 return fo_node_get_ancestor_or_self_by_type (node,
502 type);
503 }
504
505 /**
506 * fo_node_get_child_by_type:
507 * @node: #FoNode that is parent of nodes to be tested for matching #GType.
508 * @type: #GType value.
509 *
510 * Find the first child of @node with #GType matching @type value.
511 *
512 * Does not change the ref count of any node.
513 *
514 * Allows 0 as value of @type since may have been called by
515 * #fo_node_get_child_by_name for a type that has yet to be
516 * instantiated. Of course, if @type is 0, this function returns
517 * NULL.
518 *
519 * Return value: First child of specified type, or NULL.
520 **/
521 FoNode*
fo_node_get_child_by_type(FoNode * node,const GType type)522 fo_node_get_child_by_type (FoNode *node,
523 const GType type)
524 {
525 FoNode *child = NULL;
526
527 g_return_val_if_fail (FO_IS_NODE (node), NULL);
528
529 if (type != 0)
530 {
531 child = fo_node_first_child (node);
532
533 while (child && G_TYPE_FROM_INSTANCE (child) != type)
534 {
535 child = fo_node_next_sibling (child);
536 }
537
538 return child;
539 }
540 else
541 {
542 return NULL;
543 }
544 }
545
546 /**
547 * fo_node_get_child_by_name:
548 * @node: #FoNode that is parent of nodes to be tested for type name.
549 * @name: Name of type.
550 *
551 * Find the first child of @node with type name matching @name value.
552 *
553 * Does not change the ref count of any node.
554 *
555 * Return value: First child of specified type, or NULL.
556 **/
557 FoNode*
fo_node_get_child_by_name(FoNode * node,const gchar * name)558 fo_node_get_child_by_name (FoNode *node,
559 const gchar *name)
560 {
561 GType type;
562
563 g_return_val_if_fail (FO_IS_NODE (node), NULL);
564 g_return_val_if_fail (name != NULL, NULL);
565
566 type = g_type_from_name (name);
567
568 return fo_node_get_child_by_type (node, type);
569 }
570
571 /**
572 * fo_node_dump_path_to_root:
573 * @node: #FoNode for which to dump path to root.
574 *
575 * Dumps (i.e., logs messages with 'DEBUG' severity) the node path
576 * from @node to the root of the #FoNode tree containing @node.
577 **/
578 void
fo_node_dump_path_to_root(FoNode * node)579 fo_node_dump_path_to_root (FoNode *node)
580 {
581 FoNode *use_node;
582 gint depth = 0;
583 gchar *indent, *object_sprintf;
584
585 use_node = node;
586
587 while (!FO_NODE_IS_ROOT (use_node))
588 {
589 indent = g_strnfill (2 * depth++, ' ');
590 object_sprintf = fo_object_debug_sprintf (use_node);
591
592 g_log (G_LOG_DOMAIN,
593 G_LOG_LEVEL_DEBUG,
594 "%s%s",
595 indent,
596 object_sprintf);
597
598 g_free (object_sprintf);
599 g_free (indent);
600
601 use_node = fo_node_parent (use_node);
602 }
603 }
604
605 /**
606 * _insert_default:
607 * @parent: The #FoNode to place @fo_node under.
608 * @position: The position to place @fo_node at, with respect to its
609 * siblings. If @position is -1, @fo_node is inserted as
610 * the last child of @parent.
611 * @fo_node: The #FoNode to insert.
612 *
613 * Inserts an #FoNode beneath the parent at the given position.
614 *
615 * Return value: The inserted #FoNode.
616 **/
617 static FoNode *
_insert_default(FoNode * parent,gint position,FoNode * fo_node)618 _insert_default (FoNode *parent,
619 gint position,
620 FoNode *fo_node)
621 {
622 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
623 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
624
625 g_object_ref_sink (fo_node);
626
627 return ((FoNode *) g_node_insert (parent->node,
628 position,
629 fo_node->node)->data);
630 }
631
632 /**
633 * fo_node_insert:
634 * @parent: The #FoNode to place @fo_node under.
635 * @position: The position to place @fo_node at, with respect to its
636 * siblings. If @position is -1, @fo_node is inserted as
637 * the last child of @parent.
638 * @fo_node: The #FoNode to insert.
639 *
640 * Inserts an #FoNode beneath the parent at the given position.
641 *
642 * Return value: The inserted #FoNode.
643 **/
644 FoNode *
fo_node_insert(FoNode * parent,gint position,FoNode * fo_node)645 fo_node_insert (FoNode *parent,
646 gint position,
647 FoNode *fo_node)
648 {
649 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
650 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
651
652 return FO_NODE_GET_CLASS (parent)->insert (parent,
653 position,
654 fo_node);
655 }
656
657 /**
658 * _insert_before_default:
659 * @parent: The #FoNode to place @fo_node under.
660 * @sibling: The sibling #FoNode to place @fo_node before. If
661 * @sibling is NULL, @fo_node is inserted as the last child
662 * of @parent.
663 * @fo_node: The #FoNode to insert.
664 *
665 * Inserts an #FoNode beneath the parent before the given sibling.
666 *
667 * Return value: The inserted #FoNode.
668 **/
669 static FoNode *
_insert_before_default(FoNode * parent,FoNode * sibling,FoNode * fo_node)670 _insert_before_default (FoNode *parent,
671 FoNode *sibling,
672 FoNode *fo_node)
673 {
674 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
675 g_return_val_if_fail (sibling == NULL || FO_IS_NODE (sibling), fo_node);
676 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
677
678 g_object_ref_sink (fo_node);
679
680 return ((FoNode *) g_node_insert_before (parent->node,
681 sibling->node,
682 fo_node->node)->data);
683 }
684
685 /**
686 * fo_node_insert_before:
687 * @parent: The #FoNode to place @fo_node under.
688 * @sibling: The sibling #FoNode to place @fo_node before. If
689 * @sibling is NULL, @fo_node is inserted as the last child
690 * of @parent.
691 * @fo_node: The #FoNode to insert.
692 *
693 * Inserts an #FoNode beneath the parent before the given sibling.
694 *
695 * Return value: The inserted #FoNode.
696 **/
697 FoNode*
fo_node_insert_before(FoNode * parent,FoNode * sibling,FoNode * fo_node)698 fo_node_insert_before (FoNode *parent,
699 FoNode *sibling,
700 FoNode *fo_node)
701 {
702 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
703 g_return_val_if_fail (sibling == NULL || FO_IS_NODE (sibling), fo_node);
704 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
705
706 return FO_NODE_GET_CLASS (parent)->insert_before (parent,
707 sibling,
708 fo_node);
709 }
710
711 /**
712 * _insert_after_default:
713 * @parent: The #FoNode to place @fo_node under.
714 * @sibling: The sibling #FoNode to place @fo_node after. If
715 * @sibling is NULL, @fo_node is inserted as the first child
716 * of @parent.
717 * @fo_node: The #FoNode to insert.
718 *
719 * Inserts an #FoNode beneath the parent after the given sibling.
720 *
721 * Return value: The inserted #FoNode.
722 **/
723 static FoNode *
_insert_after_default(FoNode * parent,FoNode * sibling,FoNode * fo_node)724 _insert_after_default (FoNode *parent,
725 FoNode *sibling,
726 FoNode *fo_node)
727 {
728 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
729 g_return_val_if_fail (sibling == NULL || FO_IS_NODE (sibling), fo_node);
730 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
731
732 g_object_ref_sink (fo_node);
733
734 return ((FoNode *) g_node_insert_after (parent->node,
735 sibling->node,
736 fo_node->node)->data);
737 }
738
739 /**
740 * fo_node_insert_after:
741 * @parent: The #FoNode to place @fo_node under.
742 * @sibling: The sibling #FoNode to place @fo_node after. If
743 * @sibling is NULL, @fo_node is inserted as the first child
744 * of @parent.
745 * @fo_node: The #FoNode to insert.
746 *
747 * Inserts an #FoNode beneath the parent after the given sibling.
748 *
749 * Return value: The inserted #FoNode.
750 **/
751 FoNode *
fo_node_insert_after(FoNode * parent,FoNode * sibling,FoNode * fo_node)752 fo_node_insert_after (FoNode *parent,
753 FoNode *sibling,
754 FoNode *fo_node)
755 {
756 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
757 g_return_val_if_fail (sibling == NULL || FO_IS_NODE (sibling), fo_node);
758 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
759
760 return FO_NODE_GET_CLASS (parent)->insert_after (parent,
761 sibling,
762 fo_node);
763 }
764
765 /**
766 * _prepend_default:
767 * @parent: The #FoNode to place @fo_node under.
768 * @fo_node: The #FoNode to insert.
769 *
770 * Inserts an #FoNode as the first child of the given parent.
771 *
772 * Return value: The inserted #FoNode.
773 **/
774 static FoNode *
_prepend_default(FoNode * parent,FoNode * fo_node)775 _prepend_default (FoNode *parent,
776 FoNode *fo_node)
777 {
778 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
779 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
780
781 g_object_ref_sink (fo_node);
782
783 return ((FoNode *) g_node_prepend (parent->node,
784 fo_node->node)->data);
785 }
786
787 /**
788 * fo_node_prepend:
789 * @parent: The #FoNode to place @fo_node under.
790 * @fo_node: The #FoNode to insert.
791 *
792 * Inserts an #FoNode as the first child of the given parent.
793 *
794 * Return value: The inserted #FoNode.
795 **/
796 FoNode*
fo_node_prepend(FoNode * parent,FoNode * fo_node)797 fo_node_prepend (FoNode *parent,
798 FoNode *fo_node)
799 {
800 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
801 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
802
803 return FO_NODE_GET_CLASS (parent)->prepend (parent,
804 fo_node);
805 }
806
807 /**
808 * _append_default:
809 * @parent: The #FoNode to place @fo_node under.
810 * @fo_node: The #FoNode to insert.
811 *
812 * Inserts an #FoNode as the last child of the given parent.
813 *
814 * Return value: The inserted #FoNode.
815 **/
816 static FoNode*
_append_default(FoNode * parent,FoNode * fo_node)817 _append_default (FoNode *parent,
818 FoNode *fo_node)
819 {
820 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
821 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
822
823 g_object_ref_sink (fo_node);
824
825 return ((FoNode *) g_node_append (parent->node,
826 fo_node->node)->data);
827 }
828
829 /**
830 * fo_node_append:
831 * @parent: The #FoNode to place @fo_node under.
832 * @fo_node: The #FoNode to insert.
833 *
834 * Inserts an #FoNode as the last child of the given parent.
835 *
836 * Return value: The inserted #FoNode.
837 **/
838 FoNode*
fo_node_append(FoNode * parent,FoNode * fo_node)839 fo_node_append (FoNode *parent,
840 FoNode *fo_node)
841 {
842 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
843 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
844
845 return FO_NODE_GET_CLASS (parent)->append (parent,
846 fo_node);
847 }
848
849 typedef struct _FoNodeFuncData
850 {
851 FoNodeForeachFunc func;
852 gpointer node_func_data;
853 } FoNodeFuncData;
854
855 /**
856 * _g_node_children_foreach_func:
857 * @node: The #GNode for an #FoNode.
858 * @data: #FoNodeFuncData with #FoNodeForeachFunc and 'real' user data.
859 *
860 * Calls the #FoNodeForeachFunc function with the #FoNode
861 * corresponding to @node and the 'real' user data as arguments.
862 **/
863 static void
_g_node_children_foreach_func(GNode * node,gpointer data)864 _g_node_children_foreach_func (GNode *node,
865 gpointer data)
866 {
867 const FoNodeFuncData *fo_node_func_data = (FoNodeFuncData *) data;
868
869 fo_node_func_data->func (node->data,
870 fo_node_func_data->node_func_data);
871 }
872
873 /**
874 * fo_node_children_foreach:
875 * @fo_node: An #FoNode.
876 * @flags: Which types of children are to be visited, one of
877 * G_TRAVERSE_ALL, G_TRAVERSE_LEAFS and G_TRAVERSE_NON_LEAFS.
878 * @func: The function to call for each visited node.
879 * @data: User data to pass to the function.
880 *
881 * Calls a function for each of the children of an #FoNode. Note that
882 * it doesn't descend beneath the child nodes.
883 **/
884 void
fo_node_children_foreach(FoNode * fo_node,GTraverseFlags flags,FoNodeForeachFunc func,gpointer data)885 fo_node_children_foreach (FoNode *fo_node,
886 GTraverseFlags flags,
887 FoNodeForeachFunc func,
888 gpointer data)
889 {
890 FoNodeFuncData g_node_children_foreach_data = {func, data};
891
892 g_node_children_foreach (fo_node->node,
893 flags,
894 _g_node_children_foreach_func,
895 &g_node_children_foreach_data);
896 }
897
898 typedef struct _FoNodeTraverseFuncData
899 {
900 FoNodeTraverseFunc func;
901 gpointer node_func_data;
902 } FoNodeTraverseFuncData;
903
904 /**
905 * _g_node_traverse_func:
906 * @node: The #GNode for an #FoNode.
907 * @data: #FoNodeFuncData with #FoNodeTraverseFunc and 'real' user data.
908 *
909 * Calls the #FoNodeTraverseFunc function with the #FoNode
910 * corresponding to @node and the 'real' user data as arguments.
911 *
912 * Return value: The value returned by the #FoNodeTraverseFunc.
913 **/
914 static gboolean
_g_node_traverse_func(GNode * node,gpointer data)915 _g_node_traverse_func (GNode *node,
916 gpointer data)
917 {
918 const FoNodeTraverseFuncData *traverse_func_data =
919 (FoNodeTraverseFuncData *) data;
920
921 return traverse_func_data->func (node->data,
922 traverse_func_data->node_func_data);
923 }
924
925 /**
926 * fo_node_traverse:
927 * @root: The root #FoNode of the tree to traverse.
928 * @order: The order in which nodes are visited - G_IN_ORDER,
929 * G_PRE_ORDER, G_POST_ORDER, or G_LEVEL_ORDER.
930 * @flags: Which types of children are to be visited, one of
931 * G_TRAVERSE_ALL, G_TRAVERSE_LEAFS and G_TRAVERSE_NON_LEAFS.
932 * @max_depth: The maximum depth of the traversal. Nodes below this
933 * depth will not be visited. If max_depth is -1 all nodes
934 * in the tree are visited. If depth is 1, only the root
935 * is visited. If depth is 2, the root and its children
936 * are visited. And so on.
937 * @func: The function to call for each visited GNode.
938 * @data: User data to pass to the function.
939 *
940 * Traverses a tree starting at the given root #FoNode. It calls the
941 * given function for each node visited. The traversal can be halted
942 * at any point by returning %TRUE from @func.
943 **/
944 void
fo_node_traverse(FoNode * root,GTraverseType order,GTraverseFlags flags,gint max_depth,FoNodeTraverseFunc func,gpointer data)945 fo_node_traverse (FoNode *root,
946 GTraverseType order,
947 GTraverseFlags flags,
948 gint max_depth,
949 FoNodeTraverseFunc func,
950 gpointer data)
951 {
952 FoNodeTraverseFuncData g_node_traverse_data = {func, data};
953
954 if (root->node != NULL)
955 {
956 g_node_traverse (root->node,
957 order,
958 flags,
959 max_depth,
960 _g_node_traverse_func,
961 &g_node_traverse_data);
962 }
963 }
964
965 /**
966 * fo_node_next_sibling:
967 * @fo_node: The #FoNode.
968 *
969 * Gets the next sibling #FoNode of @fo_node.
970 *
971 * Return value: The next sibling of @fo_node, or %NULL.
972 **/
973 FoNode *
fo_node_next_sibling(FoNode * fo_node)974 fo_node_next_sibling (FoNode *fo_node)
975 {
976 g_return_val_if_fail (fo_node != NULL, NULL);
977 g_return_val_if_fail (FO_IS_NODE (fo_node), NULL);
978
979 return g_node_next_sibling (fo_node->node) ?
980 ((FoNode *) g_node_next_sibling (fo_node->node)->data) : NULL;
981 }
982
983 /**
984 * fo_node_first_child:
985 * @fo_node: The #FoNode.
986 *
987 * Gets the first child #FoNode of @fo_node.
988 *
989 * Return value: The first child of @fo_node, or %NULL.
990 **/
991 FoNode *
fo_node_first_child(FoNode * fo_node)992 fo_node_first_child (FoNode *fo_node)
993 {
994 g_return_val_if_fail (fo_node != NULL, NULL);
995 g_return_val_if_fail (FO_IS_NODE (fo_node), NULL);
996
997 return g_node_first_child (fo_node->node) ?
998 ((FoNode *) g_node_first_child (fo_node->node)->data) : NULL;
999 }
1000
1001 /**
1002 * fo_node_parent:
1003 * @fo_node: The #FoNode.
1004 *
1005 * Gets the parent #FoNode of @fo_node.
1006 *
1007 * Return value: The parent of @fo_node.
1008 **/
1009 FoNode *
fo_node_parent(FoNode * fo_node)1010 fo_node_parent (FoNode *fo_node)
1011 {
1012 g_return_val_if_fail (fo_node != NULL, NULL);
1013 g_return_val_if_fail (FO_IS_NODE (fo_node), NULL);
1014
1015 return fo_node->node->parent ?
1016 FO_NODE (fo_node->node->parent->data) : NULL;
1017 }
1018
1019 /**
1020 * _unlink_with_next_siblings_default:
1021 * @fo_node: First #FoNode to be unlinked
1022 *
1023 * Unlink @fo_node and its next siblings (i.e., 'following siblings'
1024 * in XPath parlance) from their place in their current #FoNode tree.
1025 *
1026 * @fo_node and its next siblings remain linked together, and any of
1027 * those nodes keep their child nodes. Neither @fo_node nor any of
1028 * its following siblings are valid roots since they each have a next
1029 * and/or a previous sibling, even if they don't have a parent.
1030 **/
1031 static void
_unlink_with_next_siblings_default(FoNode * fo_node)1032 _unlink_with_next_siblings_default (FoNode *fo_node)
1033 {
1034 g_return_if_fail (fo_node != NULL);
1035 g_return_if_fail (FO_IS_NODE (fo_node));
1036
1037 GNode *use_node = fo_node->node;
1038
1039 if (use_node->prev != NULL)
1040 {
1041 use_node->prev->next = NULL;
1042 use_node->prev = NULL;
1043 }
1044 else if (use_node->parent != NULL)
1045 {
1046 /* If there was no 'prev', this could be the first child of a
1047 parent. */
1048 use_node->parent->children = NULL;
1049 }
1050
1051 while (use_node != NULL)
1052 {
1053 g_object_force_floating (use_node->data);
1054
1055 use_node->parent = NULL;
1056 use_node = use_node->next;
1057 }
1058 }
1059
1060 /**
1061 * fo_node_unlink_with_next_siblings:
1062 * @fo_node: First #FoNode to be unlinked
1063 *
1064 * Unlink @fo_node and its next siblings (i.e., 'following siblings'
1065 * in XPath parlance) from their place in their current #FoNode tree.
1066 *
1067 * @fo_node and its next siblings remain linked together, and any of
1068 * those nodes keep their child nodes. Neither @fo_node nor any of
1069 * its following siblings are valid roots since they each have a next
1070 * and/or a previous sibling, even if they don't have a parent.
1071 **/
1072 void
fo_node_unlink_with_next_siblings(FoNode * fo_node)1073 fo_node_unlink_with_next_siblings (FoNode *fo_node)
1074 {
1075 g_return_if_fail (fo_node != NULL);
1076 g_return_if_fail (FO_IS_NODE (fo_node));
1077
1078 FO_NODE_GET_CLASS (fo_node)->unlink_with_next_siblings (fo_node);
1079 }
1080
1081 /**
1082 * fo_node_unlink:
1083 * @fo_node: the #FoNode to unlink, which becomes the root of a new
1084 * tree
1085 *
1086 * Unlinks a #FoNode from a tree, resulting in two separate trees.
1087 **/
1088 void
fo_node_unlink(FoNode * fo_node)1089 fo_node_unlink (FoNode *fo_node)
1090 {
1091 /* Only unref fo_node if it's currently in a tree. */
1092 gboolean will_unref = (fo_node->node->prev != NULL) ||
1093 (fo_node->node->parent != NULL);
1094
1095 g_node_unlink (fo_node->node);
1096
1097 if (will_unref)
1098 {
1099 g_object_unref (fo_node);
1100 }
1101 }
1102
1103 /**
1104 * fo_node_insert_with_next_siblings_default:
1105 * @parent: The #FoNode to place @fo_node under.
1106 * @position: The position to place @fo_node at, with respect to its
1107 * siblings. If @position is -1, @fo_node is inserted as
1108 * the last child of @parent.
1109 * @fo_node: First #FoNode to be inserted.
1110 *
1111 * Insert @fo_node and its next siblings (i.e., 'following siblings'
1112 * in XPath parlance) beneath @parent at the given position.
1113 *
1114 * @fo_node and its next siblings should not already have a parent
1115 * #FoNode.
1116 *
1117 * Return value: The inserted #FoNode.
1118 **/
1119 static FoNode *
_insert_with_next_siblings_default(FoNode * parent,gint position,FoNode * fo_node)1120 _insert_with_next_siblings_default (FoNode *parent,
1121 gint position,
1122 FoNode *fo_node)
1123 {
1124 g_return_val_if_fail (parent != NULL, fo_node);
1125 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
1126 g_return_val_if_fail (fo_node != NULL, fo_node);
1127 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
1128
1129 FoNode *use_node = fo_node;
1130
1131 while (use_node != NULL)
1132 {
1133 FoNode *next_sibling = fo_node_next_sibling (use_node);
1134
1135 /* Keep a reference while use_node is unlinked. */
1136 g_object_ref_sink (use_node);
1137
1138 fo_node_unlink (use_node);
1139 fo_node_insert (parent, position++, use_node);
1140 g_object_unref (use_node);
1141
1142 use_node = next_sibling;
1143 }
1144
1145 return fo_node;
1146 }
1147
1148 /**
1149 * fo_node_insert_with_next_siblings:
1150 * @parent: The #FoNode to place @fo_node under.
1151 * @position: The position to place @fo_node at, with respect to its
1152 * siblings. If @position is -1, @fo_node is inserted as
1153 * the last child of @parent.
1154 * @fo_node: First #FoNode to be inserted.
1155 *
1156 * Insert @fo_node and its next siblings (i.e., 'following siblings'
1157 * in XPath parlance) beneath @parent at the given position.
1158 *
1159 * @fo_node and its next siblings should not already have a parent
1160 * #FoNode.
1161 *
1162 * Return value: The inserted #FoNode.
1163 **/
1164 FoNode *
fo_node_insert_with_next_siblings(FoNode * parent,gint position,FoNode * fo_node)1165 fo_node_insert_with_next_siblings (FoNode *parent,
1166 gint position,
1167 FoNode *fo_node)
1168 {
1169 g_return_val_if_fail (parent != NULL, fo_node);
1170 g_return_val_if_fail (FO_IS_NODE (parent), fo_node);
1171 g_return_val_if_fail (fo_node != NULL, fo_node);
1172 g_return_val_if_fail (FO_IS_NODE (fo_node), fo_node);
1173
1174 return FO_NODE_GET_CLASS (parent)->insert_with_next_siblings (parent,
1175 position,
1176 fo_node);
1177 }
1178
1179 /**
1180 * _path_step_sprintf:
1181 * @fo_node: The #FoNode
1182 *
1183 * Creates a string representation of the XPath step for @fo_node.
1184 *
1185 * The string should be freed by the calling function.
1186 *
1187 * Return value: String representing the XPath step for @fo_node.
1188 **/
1189 static gchar*
_path_step_sprintf(FoNode * fo_node)1190 _path_step_sprintf (FoNode *fo_node)
1191 {
1192 g_return_val_if_fail (FO_IS_NODE (fo_node), NULL);
1193
1194 gchar *node_name = fo_object_sprintf (FO_OBJECT (fo_node));
1195
1196 FoNode *sibling_node = fo_node_prev_sibling (fo_node);
1197
1198 gint count = 1;
1199 while (sibling_node != NULL)
1200 {
1201 if (G_TYPE_FROM_INSTANCE (sibling_node) ==
1202 G_TYPE_FROM_INSTANCE (fo_node))
1203 count++;
1204 sibling_node = fo_node_prev_sibling (sibling_node);
1205 }
1206
1207 GString *path_step = g_string_new (NULL);
1208 g_string_printf (path_step,
1209 "/%s[%d%s]",
1210 node_name,
1211 count,
1212 g_object_is_floating (fo_node) ? " (floating)" : "");
1213
1214 g_free (node_name);
1215
1216 return g_string_free (path_step, FALSE);
1217 }
1218
1219 /**
1220 * fo_node_path_to_root_sprintf:
1221 * @fo_node: The #FoNode.
1222 *
1223 * Creates a string representation of the path from @fo_node to the
1224 * root of its #FoNode tree.
1225 *
1226 * The string should be freed by the calling function.
1227 *
1228 * Return value: String representation of path from @fo_node to its
1229 * root.
1230 **/
1231 static gchar*
fo_node_path_to_root_sprintf(FoNode * fo_node)1232 fo_node_path_to_root_sprintf (FoNode *fo_node)
1233 {
1234 g_return_val_if_fail (fo_node != NULL, NULL);
1235 g_return_val_if_fail (FO_IS_NODE (fo_node), NULL);
1236
1237 gchar *node_name = _path_step_sprintf (fo_node);
1238 GString *path = g_string_new (node_name);
1239 g_free (node_name);
1240
1241 FoNode *use_node = fo_node_parent (FO_NODE (fo_node));
1242
1243 while (use_node != NULL)
1244 {
1245 gchar *old_path = g_strdup (path->str);
1246
1247 node_name = _path_step_sprintf (use_node);
1248
1249 g_string_printf (path,
1250 "%s%s",
1251 node_name,
1252 old_path);
1253
1254 g_free (node_name);
1255 g_free (old_path);
1256
1257 use_node = fo_node_parent (use_node);
1258 }
1259
1260 return g_string_free (path, FALSE);
1261 }
1262
1263 /**
1264 * _log_warning:
1265 * @object: #FoNode that is subject of @warning.
1266 * @warning: #GError with information about warning that occurred.
1267 *
1268 * Logs both the warning represented by @warning and the #FoNode path from
1269 * @object to the root of its #FoNode tree.
1270 **/
1271 static void
_log_warning(FoObject * object,GError ** warning)1272 _log_warning (FoObject *object,
1273 GError **warning)
1274 {
1275 g_return_if_fail (object != NULL);
1276 g_return_if_fail (FO_IS_NODE (object));
1277 g_return_if_fail (warning != NULL && *warning != NULL);
1278
1279 gchar *node_name = _path_step_sprintf (FO_NODE (object));
1280 GString *path = g_string_new (NULL);
1281 g_string_printf (path,
1282 "%s",
1283 node_name);
1284 g_free (node_name);
1285
1286 FoNode *use_node = fo_node_parent (FO_NODE (object));
1287
1288 while (use_node != NULL)
1289 {
1290 gchar *old_path = g_strdup (path->str);
1291
1292 node_name = _path_step_sprintf (use_node);
1293
1294 g_string_printf (path,
1295 "%s%s",
1296 node_name,
1297 old_path);
1298
1299 g_free (node_name);
1300 g_free (old_path);
1301
1302 use_node = fo_node_parent (use_node);
1303 }
1304
1305 g_warning ("%s: %s\nObject path: %s",
1306 g_quark_to_string ((*warning)->domain),
1307 (*warning)->message,
1308 path->str);
1309
1310 g_string_free (path, TRUE);
1311 g_clear_error (warning);
1312 }
1313
1314 /**
1315 * _log_error:
1316 * @object: The #FoNode.
1317 * @error: #GError indicating the error.
1318 *
1319 * Logs both the error represented by @error and the #FoNode path from
1320 * @object to the root of its #FoNode tree.
1321 **/
1322 static void
_log_error(FoObject * object,GError ** error)1323 _log_error (FoObject *object,
1324 GError **error)
1325 {
1326 g_return_if_fail (object != NULL);
1327 g_return_if_fail (FO_IS_NODE (object));
1328 g_return_if_fail (error != NULL && *error != NULL);
1329
1330 gchar *node_name = _path_step_sprintf (FO_NODE (object));
1331 GString *path = g_string_new (NULL);
1332 g_string_printf (path,
1333 "%s",
1334 node_name);
1335 g_free (node_name);
1336
1337 FoNode *use_node = fo_node_parent (FO_NODE (object));
1338
1339 while (use_node != NULL)
1340 {
1341 gchar *old_path = g_strdup (path->str);
1342
1343 node_name = _path_step_sprintf (use_node);
1344
1345 g_string_printf (path,
1346 "%s%s",
1347 node_name,
1348 old_path);
1349
1350 g_free (node_name);
1351 g_free (old_path);
1352
1353 use_node = fo_node_parent (use_node);
1354 }
1355
1356 g_critical ("%s: %s\nObject path: %s",
1357 g_quark_to_string ((*error)->domain),
1358 (*error)->message,
1359 path->str);
1360
1361 g_string_free (path, TRUE);
1362 g_clear_error (error);
1363 }
1364
1365 /**
1366 * _log_or_propagate_error:
1367 * @fo_object: #FoObject that is the subject of @src.
1368 * @dest: #GError to which to propagate @src, or NULL.
1369 * @src: #GError with information about error that occurred.
1370 *
1371 * If can propagate @src to @dest, do so, otherwise log @src using
1372 * fo_object_log_error().
1373 *
1374 * Return value: %TRUE if error propagated, otherwise %FALSE.
1375 **/
1376 static gboolean
_log_or_propagate_error(FoObject * fo_object,GError ** dest,GError * src)1377 _log_or_propagate_error (FoObject *fo_object,
1378 GError **dest,
1379 GError *src)
1380 {
1381 GError *new_error;
1382 GString *new_message = g_string_new (NULL);
1383 gchar *path_to_root;
1384
1385 g_return_val_if_fail (FO_IS_NODE (fo_object), TRUE);
1386 g_return_val_if_fail (dest == NULL || *dest == NULL, TRUE);
1387 g_return_val_if_fail (src != NULL, TRUE);
1388
1389 path_to_root = fo_node_path_to_root_sprintf (FO_NODE (fo_object));
1390
1391 g_string_printf (new_message,
1392 "%s\nObject path: %s",
1393 src->message,
1394 path_to_root);
1395
1396 new_error = g_error_new (src->domain,
1397 src->code,
1398 "%s",
1399 new_message->str);
1400
1401 g_string_free (new_message, TRUE);
1402 g_free (path_to_root);
1403
1404 g_error_free (src);
1405
1406 if (dest != NULL)
1407 {
1408 g_propagate_error (dest,
1409 new_error);
1410 return TRUE;
1411 }
1412 else
1413 {
1414 fo_object_log_error (fo_object,
1415 &new_error);
1416 return FALSE;
1417 }
1418 }
1419
1420 /**
1421 * _maybe_propagate_error:
1422 * @fo_object: #FoObject that is the subject of @src.
1423 * @dest: #GError to which to propagate @src, or NULL.
1424 * @src: #GError with information about error that occurred.
1425 * @continue_after_error: Whether or not to continue after an error.
1426 *
1427 * If @continue_after_error is %FALSE and can propagate @src to @dest,
1428 * then do so, otherwise log @src using fo_object_log_error().
1429 *
1430 * Return value: %TRUE if error propagated, otherwise %FALSE.
1431 **/
1432 static gboolean
_maybe_propagate_error(FoObject * fo_object,GError ** dest,GError * src,gboolean continue_after_error)1433 _maybe_propagate_error (FoObject *fo_object,
1434 GError **dest,
1435 GError *src,
1436 gboolean continue_after_error)
1437 {
1438 GError *new_error;
1439 GString *new_message = g_string_new (NULL);
1440 gchar *path_to_root;
1441
1442 g_return_val_if_fail (FO_IS_NODE (fo_object), TRUE);
1443 g_return_val_if_fail (dest == NULL || *dest == NULL, TRUE);
1444 g_return_val_if_fail (src != NULL, TRUE);
1445
1446 path_to_root = fo_node_path_to_root_sprintf (FO_NODE (fo_object));
1447
1448 g_string_printf (new_message,
1449 "%s\nObject path: %s",
1450 src->message,
1451 path_to_root);
1452
1453 new_error = g_error_new (src->domain,
1454 src->code,
1455 "%s",
1456 new_message->str);
1457
1458 g_string_free (new_message, TRUE);
1459 g_free (path_to_root);
1460
1461 g_error_free (src);
1462
1463 if ((continue_after_error == FALSE) &&
1464 (dest != NULL))
1465 {
1466 g_propagate_error (dest,
1467 new_error);
1468 return TRUE;
1469 }
1470 else
1471 {
1472 fo_object_log_error (fo_object,
1473 &new_error);
1474 return FALSE;
1475 }
1476 }
1477