source: trunk/third/bonobo/bonobo/bonobo-ui-node.c @ 17169

Revision 17169, 13.0 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17168, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*
3 * bonobo-ui-node.c: Code to manipulate BonoboUINode objects
4 *
5 * Author:
6 *      Havoc Pennington <hp@redhat.com>
7 *
8 * Copyright 2000 Red Hat, Inc.
9 */
10
11#include "config.h"
12#include <bonobo/bonobo-ui-node.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include <gnome-xml/parser.h>
17#include <gnome-xml/parserInternals.h>
18#include <gnome-xml/xmlmemory.h>
19
20/* Having this struct here makes debugging nicer. */
21struct _BonoboUINode {
22        xmlNode real_node;
23};
24
25#define XML_NODE(x) (&(x)->real_node)
26#define BNODE(x) ((BonoboUINode *)(x))
27
28/**
29 * bonobo_ui_node_new:
30 * @name: The name for the node
31 *
32 * Creates a new node with name @name
33 *
34 * Return value: a new node pointer
35 **/
36BonoboUINode*
37bonobo_ui_node_new (const char   *name)
38{
39        return BNODE (xmlNewNode (NULL, name));
40}
41
42/**
43 * bonobo_ui_node_new_child:
44 * @parent: the parent
45 * @name: the name of the new child
46 *
47 * Create a new node as a child of @parent with name @name
48 *
49 * Return value: pointer to the new child
50 **/
51BonoboUINode*
52bonobo_ui_node_new_child (BonoboUINode *parent,
53                          const char   *name)
54{
55        return BNODE (xmlNewChild (XML_NODE (parent), NULL, name, NULL));
56}
57
58/**
59 * bonobo_ui_node_copy:
60 * @node: the node
61 * @recursive: whether to dup children too.
62 *
63 * Copy an XML node, if @recursive do a deep copy, otherwise just dup the node itself.
64 *
65 * Return value: a copy of the node
66 **/
67BonoboUINode*
68bonobo_ui_node_copy (BonoboUINode *node,
69                     gboolean recursive)
70{
71        return BNODE (xmlCopyNode (XML_NODE (node), recursive));
72}
73
74/**
75 * bonobo_ui_node_free:
76 * @node: a node.
77 *
78 * Frees the memory associated with the @node and unlink it from the tree
79 **/
80void
81bonobo_ui_node_free (BonoboUINode *node)
82{
83        xmlFreeNode (XML_NODE (node));
84}
85
86/**
87 * bonobo_ui_node_set_data:
88 * @node: the node
89 * @data: user data
90 *
91 * Associates some user data with the node pointer
92 **/
93void
94bonobo_ui_node_set_data (BonoboUINode *node,
95                         gpointer      data)
96{
97        XML_NODE (node)->_private = data;
98}
99
100/**
101 * bonobo_ui_node_get_data:
102 * @node: the node
103 *
104 * Gets user data associated with @node
105 *
106 * Return value: the user data, see bonobo_ui_node_set_data
107 **/
108gpointer
109bonobo_ui_node_get_data (BonoboUINode *node)
110{
111        return XML_NODE (node)->_private;
112}
113
114static xmlAttrPtr
115get_attr (xmlNode *node, const char *name)
116{
117        xmlAttrPtr prop;
118
119        if ((node == NULL) || (name == NULL)) return(NULL);
120        /*
121         * Check on the properties attached to the node
122         */
123        prop = node->properties;
124        while (prop != NULL) {
125                if (!xmlStrcmp(prop->name, name))  {
126                        return(prop);
127                }
128                prop = prop->next;
129      }
130       
131      return(NULL);
132}
133
134/**
135 * bonobo_ui_node_set_attr:
136 * @node: The node
137 * @name: the name of the attr
138 * @value: the value for the attr
139 *
140 * Set the attribute of @name on @node to @value overriding any
141 * previous values of that attr.
142 **/
143void
144bonobo_ui_node_set_attr (BonoboUINode *node,
145                         const char   *name,
146                         const char   *value)
147{
148        if (value == NULL) {
149                xmlAttrPtr attr = get_attr (XML_NODE (node), name);
150                if (attr)
151                        xmlRemoveProp (attr);
152        } else {
153                xmlSetProp (XML_NODE (node), name, value);
154        }
155}
156
157/**
158 * bonobo_ui_node_get_attr:
159 * @node: the node
160 * @name: the name of the attr to get
161 *
162 * Fetch the value of an attr of name @name from @node
163 * see also: bonobo_ui_node_free_string
164 *
165 * Return value: the attr text.
166 **/
167char*
168bonobo_ui_node_get_attr (BonoboUINode *node,
169                         const char   *name)
170{
171        return xmlGetProp (XML_NODE (node), name);
172}
173
174/**
175 * bonobo_ui_node_has_attr:
176 * @node: the node
177 * @name: the name of the attr to detect
178 *
179 * Determines whether the @node has an attribute of name @name
180 *
181 * Return value: TRUE if the attr exists
182 **/
183gboolean
184bonobo_ui_node_has_attr (BonoboUINode *node,
185                         const char   *name)
186{
187        return get_attr (XML_NODE (node), name) != NULL;
188}
189
190/**
191 * bonobo_ui_node_remove_attr:
192 * @node: the node
193 * @name: name of the attribute
194 *
195 * remove any attribute with name @name from @node
196 **/
197void
198bonobo_ui_node_remove_attr (BonoboUINode *node,
199                            const char   *name)
200{
201        xmlAttrPtr attr = get_attr (XML_NODE (node), name);
202        if (attr)
203                xmlRemoveProp (attr);
204}
205
206/**
207 * bonobo_ui_node_add_child:
208 * @parent: the parent
209 * @child: the new child
210 *
211 * Add a @child node to the @parent node ( after the other children )
212 **/
213void
214bonobo_ui_node_add_child (BonoboUINode *parent,
215                          BonoboUINode *child)
216{
217        xmlAddChild (XML_NODE (parent), XML_NODE (child));
218}
219
220/**
221 * bonobo_ui_node_insert_before:
222 * @sibling: the node to insert
223 * @prev_sibling: the placeholder for insertion
224 *
225 * Insert a @sibling before @prev_sibling in a node list
226 **/
227void
228bonobo_ui_node_insert_before (BonoboUINode *sibling,
229                              BonoboUINode *prev_sibling)
230{
231        xmlAddPrevSibling (XML_NODE (sibling), XML_NODE (prev_sibling));
232}
233
234/**
235 * bonobo_ui_node_unlink:
236 * @node: the node
237 *
238 * Unlink @node from its tree, ie. disassociate it with its parent
239 **/
240void
241bonobo_ui_node_unlink (BonoboUINode *node)
242{
243        xmlUnlinkNode (XML_NODE (node));
244}
245
246/**
247 * bonobo_ui_node_replace:
248 * @old_node: node to be replaced
249 * @new_node: node to replace with
250 *
251 * Replace @old_node with @new_node in the tree. @old_node is
252 * left unlinked and floating with its children.
253 **/
254void
255bonobo_ui_node_replace (BonoboUINode *old_node,
256                        BonoboUINode *new_node)
257{
258        /* libxml has these args indisputably backward */
259        xmlReplaceNode (XML_NODE (new_node),
260                        XML_NODE (old_node));
261}
262
263/**
264 * bonobo_ui_node_set_content:
265 * @node: the node
266 * @content: the new content
267 *
268 * Set the textual content of @node to @content
269 **/
270void
271bonobo_ui_node_set_content (BonoboUINode *node,
272                            const char   *content)
273{
274        xmlNodeSetContent (XML_NODE (node), content);
275}
276
277/**
278 * bonobo_ui_node_get_content:
279 * @node: the node
280 *
281 * see also: bonobo_ui_node_free_string
282 *
283 * Return value: the content of @node
284 **/
285char *
286bonobo_ui_node_get_content (BonoboUINode *node)
287{
288        return xmlNodeGetContent (XML_NODE (node));
289}
290
291/**
292 * bonobo_ui_node_next:
293 * @node: the node
294 *
295 * accesses the next node.
296 *
297 * Return value: the node after @node in the list
298 **/
299BonoboUINode*
300bonobo_ui_node_next (BonoboUINode *node)
301{
302        return BNODE (XML_NODE (node)->next);
303}
304
305/**
306 * bonobo_ui_node_prev:
307 * @node: the node
308 *
309 * accesses the previous node.
310 *
311 * Return value: the node before @node in the list
312 **/
313BonoboUINode*
314bonobo_ui_node_prev (BonoboUINode *node)
315{
316        return BNODE (XML_NODE (node)->prev);
317}
318
319/**
320 * bonobo_ui_node_children:
321 * @node: the node
322 *
323 * accesses the node's children.
324 *
325 * Return value: the first child of @node
326 **/
327BonoboUINode*
328bonobo_ui_node_children (BonoboUINode *node)
329{
330        return BNODE (XML_NODE (node)->xmlChildrenNode);
331}
332
333/**
334 * bonobo_ui_node_parent:
335 * @node: the node
336 *
337 * accesses the node's parent.
338 *
339 * Return value: the parent node of @node
340 **/
341BonoboUINode*
342bonobo_ui_node_parent (BonoboUINode *node)
343{
344        return BNODE (XML_NODE (node)->parent);
345}
346
347/**
348 * bonobo_ui_node_get_name:
349 * @node: the node
350 *
351 * Return value: the name of @node
352 **/
353const char*
354bonobo_ui_node_get_name (BonoboUINode *node)
355{
356        return XML_NODE (node)->name;
357}
358
359/**
360 * bonobo_ui_node_has_name:
361 * @node: the node
362 * @name: a name the node might have
363 *
364 * accesses the node's name.
365 *
366 * Return value: TRUE if @node has name == @name
367 **/
368gboolean
369bonobo_ui_node_has_name (BonoboUINode *node,
370                         const char   *name)
371{
372        return strcmp (XML_NODE (node)->name, name) == 0;
373}
374
375/**
376 * bonobo_ui_node_free_string:
377 * @str: the string to free.
378 *
379 * Frees a string returned by any of the get routines.
380 **/
381void
382bonobo_ui_node_free_string (char *str)
383{
384        if (str)
385                xmlFree (str);
386}
387
388/**
389 * bonobo_ui_node_to_string:
390 * @node: the node tree
391 * @recurse: whether to dump its children as well
392 *
393 * Convert the Node to its XML string representation
394 * see also: bonobo_ui_node_free_string
395 *
396 * Return value: the string representation or NULL on error
397 **/
398char *
399bonobo_ui_node_to_string (BonoboUINode *node,
400                          gboolean      recurse)
401{
402        xmlDoc     *doc;
403        xmlChar    *mem = NULL;
404        int         size;
405
406        doc = xmlNewDoc ("1.0");
407        g_return_val_if_fail (doc != NULL, NULL);
408
409        doc->xmlRootNode = XML_NODE(bonobo_ui_node_copy (node, TRUE));
410        g_return_val_if_fail (doc->xmlRootNode != NULL, NULL);
411
412        if (!recurse && bonobo_ui_node_children (BNODE (doc->xmlRootNode))) {
413                BonoboUINode *tmp;
414                while ((tmp = bonobo_ui_node_children (BNODE (doc->xmlRootNode)))) {
415                        xmlUnlinkNode (XML_NODE(tmp));
416                        bonobo_ui_node_free (tmp);
417                }
418        }
419
420        xmlDocDumpMemory (doc, &mem, &size);
421
422        g_return_val_if_fail (mem != NULL, NULL);
423
424        xmlFreeDoc (doc);
425
426        return mem;
427}
428
429/**
430 * bonobo_ui_node_from_string:
431 * @xml: the xml string
432 *
433 * Parses a string into an XML tree
434 *
435 * Return value: the xml tree.
436 **/
437BonoboUINode*
438bonobo_ui_node_from_string (const char *xml)
439{
440        /* We have crap error reporting for this function */
441        xmlDoc  *doc;
442        BonoboUINode *node;
443       
444        doc = xmlParseDoc ((char *)xml);
445        if (!doc)
446                return NULL;
447       
448        node = BNODE (doc->xmlRootNode);
449        bonobo_ui_node_strip (&node);
450
451        xmlUnlinkNode (XML_NODE (node));
452        doc->xmlRootNode = NULL;
453       
454        xmlFreeDoc (doc);
455
456        return node;
457}
458
459/**
460 * bonobo_ui_node_from_file:
461 * @fname: the filename containing the xml
462 *
463 * Loads and parses the filename into an XML tree
464 *
465 * Return value: the xml tree.
466 **/
467BonoboUINode*
468bonobo_ui_node_from_file (const char *fname)
469{
470        /* Error reporting blows here too (because it blows
471         * in libxml)
472         */
473        xmlDoc  *doc;
474        BonoboUINode *node;
475
476        g_return_val_if_fail (fname != NULL, NULL);
477       
478        doc = xmlParseFile (fname);
479
480        g_return_val_if_fail (doc != NULL, NULL);
481
482        node = BNODE (doc->xmlRootNode);
483        bonobo_ui_node_strip (&node);
484
485        xmlUnlinkNode (XML_NODE (node));
486        doc->xmlRootNode = NULL;
487
488        xmlFreeDoc (doc);
489
490        return node;
491}
492
493/**
494 * bonobo_ui_node_transparent:
495 * @node: the node
496 *
497 * Determines whether @node is transparent. A node is
498 * transparent if it has no content and either no attributes
499 * or a single 'name' attribute.
500 *
501 * Return value: TRUE if transparent
502 **/
503gboolean
504bonobo_ui_node_transparent (BonoboUINode *node)
505{
506        xmlNode *n = XML_NODE (node);
507        gboolean ret = FALSE;
508
509        g_return_val_if_fail (n != NULL, TRUE);
510
511        if (n->content) {
512                ret = FALSE;
513
514        } else if (!n->properties) {
515                if (!strcmp (XML_NODE (node)->name, "placeholder"))
516                        ret = TRUE;
517                else if (!strcmp (XML_NODE (node)->name, "menu"))
518                        ret = TRUE;
519
520        } else if (!n->properties->next) {
521                if (!strcmp (n->properties->name, "name"))
522                        ret = TRUE;
523        }
524
525        return ret;
526}
527
528/**
529 * bonobo_ui_node_copy_attrs:
530 * @src: the attr source node
531 * @dest: where to dump the attrs.
532 *
533 * This function copies all the attributes from @src to @dest
534 * effectively cloning the @src node as @dest
535 **/
536void
537bonobo_ui_node_copy_attrs (BonoboUINode *src,
538                           BonoboUINode *dest)
539{
540        xmlAttr *attr;
541       
542        for (attr = XML_NODE (src)->properties; attr; attr = attr->next) {
543                char *txt = xmlGetProp (XML_NODE (src), attr->name);
544
545                g_assert (txt != NULL);
546
547                xmlSetProp (XML_NODE (dest), attr->name, txt);
548
549                xmlFree (txt);
550        }
551}
552
553static gboolean
554do_strip (xmlNode *node)
555{
556        xmlNode *l, *next;
557        gboolean suspicious = FALSE;
558
559        if (!node)
560                return FALSE;
561
562        switch (node->type) {
563        case XML_DOCUMENT_FRAG_NODE:
564        case XML_ELEMENT_NODE:
565        case XML_TEXT_NODE:
566        case XML_ENTITY_NODE:
567        case XML_ENTITY_REF_NODE: {
568                xmlAttr *a, *nexta;
569
570                node->nsDef = NULL;
571                node->ns = NULL;
572                node->doc = NULL;
573
574                for (a = node->properties; a; a = nexta) {
575                        nexta = a->next;
576                        a->ns = NULL;
577                        do_strip (a->val);
578                }
579
580                for (l = node->xmlChildrenNode; l; l = next) {
581                        next = l->next;
582                        do_strip (l);
583                }
584                break;
585        }
586
587        case XML_ATTRIBUTE_NODE: {
588                xmlAttr *attr = (xmlAttr *)node;
589                attr->ns = NULL;
590                do_strip (attr->val);
591                break;
592        }
593
594        case XML_PI_NODE:
595        case XML_COMMENT_NODE:
596        case XML_DOCUMENT_NODE:
597        case XML_HTML_DOCUMENT_NODE:
598        case XML_DOCUMENT_TYPE_NODE:
599        case XML_NOTATION_NODE:
600        case XML_CDATA_SECTION_NODE:
601                suspicious = TRUE;
602                break;
603        }
604
605        if (suspicious) {
606/*              g_warning ("node looks suspicious %d: '%s'",
607                           node->type,
608                           bonobo_ui_node_to_string (BNODE (node), TRUE));*/
609                xmlUnlinkNode (node);
610                bonobo_ui_node_free (BNODE (node));
611                return TRUE;
612        } else
613                return FALSE;
614}
615
616/**
617 * bonobo_ui_node_strip:
618 * @node: a pointer to the node's pointer
619 *
620 *   This function is used to purge unwanted content from
621 * a set of nodes, and particularly clean up stray Doc and
622 * NS pointers that cause serious trouble later.
623 **/
624void
625bonobo_ui_node_strip (BonoboUINode **node)
626{
627        BonoboUINode *next, *l;
628
629        for (l = *node; l; l = next) {
630                next = bonobo_ui_node_next (l);
631                if (l == *node && do_strip (XML_NODE (l)))
632                        *node = next;
633        }
634}
Note: See TracBrowser for help on using the repository browser.