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