wtree.c revision 278eca22
1/*
2 * $Xorg: wtree.c,v 1.4 2001/02/09 02:05:30 xorgcvs Exp $
3 *
4Copyright 1989, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25 */
26/* $XFree86: xc/programs/editres/wtree.c,v 1.4 2001/01/17 23:44:53 dawes Exp $ */
27
28#include <stdio.h>
29#include <X11/Intrinsic.h>
30#include <X11/Xutil.h>
31#include <X11/StringDefs.h>
32
33#include <X11/Xaw/Cardinals.h>
34#include <X11/Xaw/Toggle.h>
35#include <X11/Xaw/Viewport.h>
36#include <X11/Xaw/Tree.h>
37
38#include "editresP.h"
39
40static void AddNodeToActiveList ( WNode * node );
41static void RemoveNodeFromActiveList ( WNode * node );
42static Boolean IsActiveNode ( WNode * node );
43static void AddNode ( WNode ** top_node, WidgetTreeInfo * info,
44		      TreeInfo * tree_info );
45static void FillNode ( WidgetTreeInfo * info, WNode * node,
46		       TreeInfo * tree_info );
47static void AddChild ( WNode * parent, WNode * child );
48static WNode ** CopyActiveNodes ( TreeInfo * tree_info );
49
50/*	Function Name: BuildVisualTree
51 *	Description: Creates the Tree and shows it.
52 *	Arguments: tree_parent - parent of the tree widget.
53 *                 event - the event that caused this action.
54 *	Returns: none.
55 */
56
57/* ARGSUSED */
58void
59BuildVisualTree(Widget tree_parent, Event *event)
60{
61    WNode * top;
62    char msg[BUFSIZ];
63
64    if (global_tree_info != NULL) {
65	XtDestroyWidget(global_tree_info->tree_widget);
66	XtFree((char *)global_tree_info->active_nodes);
67	XtFree((char *)global_tree_info);
68    }
69
70    global_tree_info = CreateTree(event);
71    top = global_tree_info->top_node;
72
73    global_tree_info->tree_widget = XtCreateWidget("tree", treeWidgetClass,
74						   tree_parent, NULL, ZERO);
75
76    if (top == NULL) {
77	SetMessage(global_screen_data.info_label,
78		   res_labels[27]);
79	return;
80    }
81
82    AddTreeNode(global_tree_info->tree_widget, top);
83
84    if (XtIsRealized(tree_parent)) /* hack around problems in Xt. */
85	XtRealizeWidget(global_tree_info->tree_widget);
86
87    XtManageChild(global_tree_info->tree_widget);
88
89    sprintf(msg, res_labels[11], top->name, top->class);
90    SetMessage(global_screen_data.info_label, msg);
91}
92
93/*	Function Name: AddTreeNode
94 *	Description: Adds all nodes below this to the Tree widget.
95 *	Arguments: parent - parent of the tree widget.
96 *                 top - the top node of the tree.
97 *	Returns: the tree widget.
98 *
99 * NOTE: This is a recursive function.
100 */
101
102void
103AddTreeNode(Widget tree, WNode *top)
104{
105    int i;
106    Arg args[1];
107    Cardinal num_args = 0;
108    char msg[BUFSIZ];
109
110    if (top->parent != NULL) {
111	if (top->parent->widget == NULL) {
112	    sprintf( msg, res_labels[28],
113		    top->name, top->parent->name, "not been created yet");
114	    SetMessage(global_screen_data.info_label, msg);
115	}
116	XtSetArg(args[num_args], XtNtreeParent, top->parent->widget);
117	num_args++;
118    }
119
120    top->widget = XtCreateManagedWidget(top->name, toggleWidgetClass, tree,
121					args, num_args);
122
123    if (XSaveContext(XtDisplay(top->widget), (Window) top->widget,
124		     NODE_INFO, (XPointer) top) != 0) {
125	sprintf( msg, res_labels[29], top->name);
126	SetMessage(global_screen_data.info_label, msg);
127    }
128
129    XtAddCallback(top->widget, XtNcallback, TreeToggle, (XtPointer) top);
130
131    for (i = 0; i < top->num_children; i++)
132	AddTreeNode(tree, top->children[i]);
133}
134
135/*	Function Name: TreeToggle
136 *	Description: Called whenever a tree node is toggled.
137 *	Arguments: w - the tree widget.
138 *                 node_ptr - pointer to this node's information.
139 *                 state_ptr - state of the toggle.
140 *	Returns: none.
141 */
142
143/* ARGSUSED */
144void
145TreeToggle(Widget w, XtPointer node_ptr, XtPointer state_ptr)
146{
147    Boolean state = (Boolean)(long) state_ptr;
148    WNode * node = (WNode *) node_ptr;
149
150    if (state)
151	AddNodeToActiveList(node);
152    else
153	RemoveNodeFromActiveList(node);
154}
155
156/*	Function Name: AddNodeToActiveList
157 *	Description: Adds this node to the list of active toggles.
158 *	Arguments: node - node to add.
159 *	Returns: none.
160 */
161
162static void
163AddNodeToActiveList(WNode *node)
164{
165    TreeInfo * info = node->tree_info;
166
167    if (IsActiveNode(node))	/* node already active. */
168	return;
169
170    if (info->num_nodes >= info->alloc_nodes) {
171	info->alloc_nodes += NUM_INC;
172	info->active_nodes =(WNode **)XtRealloc((XtPointer) info->active_nodes,
173						sizeof(WNode *) *
174						     info->alloc_nodes);
175    }
176
177    info->active_nodes[info->num_nodes++] = node;
178}
179
180/*	Function Name: RemoveNodeFromActiveList
181 *	Description: Removes a node from the active list.
182 *	Arguments: node - node to remove.
183 *	Returns: none.
184 */
185
186static void
187RemoveNodeFromActiveList(WNode *node)
188{
189    TreeInfo * info = node->tree_info;
190    Boolean found_node = FALSE;
191    int i;
192
193    if (!IsActiveNode(node))	/* This node is not active. */
194	return;
195
196    for (i = 0; i < info->num_nodes; i++) {
197	if (found_node)
198	    info->active_nodes[i - 1] = info->active_nodes[i];
199	else if (info->active_nodes[i] == node)
200	    found_node = TRUE;
201    }
202
203    info->num_nodes--;
204}
205
206/*	Function Name: IsActiveNode
207 *	Description: returns TRUE is this node is on the active list.
208 *	Arguments: node - node to check.
209 *	Returns: see above.
210 */
211
212static Boolean
213IsActiveNode(WNode *node)
214{
215    TreeInfo * info = node->tree_info;
216    int i;
217
218    for (i = 0; i < info->num_nodes; i++)
219	if (info->active_nodes[i] == node)
220	    return(TRUE);
221
222    return(FALSE);
223}
224
225/*	Function Name: CreateTree
226 *	Description: Creates a widget tree give a list of names and classes.
227 *	Arguments: event - the information from the client.
228 *	Returns: The tree_info about this new tree.
229 */
230
231TreeInfo *
232CreateTree(Event *event)
233{
234    SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
235    int i;
236
237    TreeInfo * tree_info;
238
239    tree_info = (TreeInfo *) XtMalloc( (Cardinal) sizeof(TreeInfo));
240
241    tree_info->tree_widget = NULL;
242    tree_info->top_node = NULL;
243    tree_info->active_nodes = NULL;
244    tree_info->num_nodes = tree_info->alloc_nodes = 0;
245    tree_info->flash_widgets = NULL;
246    tree_info->num_flash_widgets = tree_info->alloc_flash_widgets = 0;
247
248    for ( i = 0; i < (int)send_event->num_entries; i++)
249	AddNode(&(tree_info->top_node), (send_event->info + i), tree_info);
250
251    return(tree_info);
252}
253
254/*	Function Name: PrintNodes
255 *	Description: Prints all nodes.
256 *	Arguments: top - the top node.
257 *	Returns: none.
258 */
259
260void
261PrintNodes(WNode *top)
262{
263    int i;
264
265    if (top->parent == NULL)
266	printf("Top of Tree, Name: %10s, ID: %10ld, Class: %10s\n",
267	       top->name, top->id, top->class);
268    else
269	printf("Parent %10s, Name: %10s, ID: %10ld, Class: %10s\n",
270	       top->parent->name, top->name, top->id, top->class);
271
272    for (i = 0; i < top->num_children; i++)
273	PrintNodes(top->children[i]);
274}
275
276/*	Function Name: _TreeRelabel
277 *	Description: Modifies the selected elements of the tree
278 *	Arguments: tree_info - the tree we are working on.
279 *                 type - type of selection to perform
280 *	Returns: none.
281 */
282
283void
284_TreeRelabel(TreeInfo *tree_info, LabelTypes type)
285{
286    WNode * top;
287
288    if (tree_info == NULL) {
289	SetMessage(global_screen_data.info_label,
290		   res_labels[17]);
291	return;
292    }
293
294    top = tree_info->top_node;
295
296    PrepareToLayoutTree(tree_info->tree_widget);
297    _TreeRelabelNode(top, type, TRUE);
298    LayoutTree(tree_info->tree_widget);
299}
300
301/*	Function Name: _TreeSelect
302 *	Description: Activates relatives of the active nodes, as specified
303 *                   by type, or Selects all nodes as specified by type.
304 *	Arguments: tree_info - information about the tree to work on.
305 *                 type - type of activate to invode.
306 *	Returns: none.
307 */
308
309void
310_TreeSelect(TreeInfo *tree_info, SelectTypes type)
311{
312    WNode ** active_nodes;
313    Cardinal num_active_nodes;
314    int i;
315
316    if (tree_info == NULL) {
317	SetMessage(global_screen_data.info_label,
318		   res_labels[17]);
319	return;
320    }
321
322    switch(type) {
323    case SelectNone:
324    case SelectAll:
325    case SelectInvert:
326	_TreeSelectNode(tree_info->top_node, type, TRUE);
327	return;
328    default:
329	break;			/* otherwise continue. */
330    }
331
332    if (tree_info->num_nodes == 0) {
333	SetMessage(global_screen_data.info_label,
334		   res_labels[18]);
335	return;
336    }
337
338    active_nodes = CopyActiveNodes(tree_info);
339    num_active_nodes = tree_info->num_nodes;
340
341    for (i = 0; i < num_active_nodes; i++)
342	_TreeActivateNode(active_nodes[i], type);
343
344    XtFree((XtPointer) active_nodes);
345}
346
347/*	Function Name: _TreeSelectNode
348 *	Description: Modifies the state of a node and all its decendants.
349 *	Arguments: node - node to operate on.
350 *                 type - type of selection to perform.
351 *                 recurse - whether to continue on down the tree.
352 *	Returns: none.
353 */
354
355void
356_TreeSelectNode(WNode *node, SelectTypes type, Boolean recurse)
357{
358    int i;
359    Arg args[1];
360    Boolean state;
361
362    switch(type) {
363    case SelectAll:
364	state = TRUE;
365	break;
366    case SelectNone:
367	state = FALSE;
368	break;
369    case SelectInvert:
370	XtSetArg(args[0], XtNstate, &state);
371	XtGetValues(node->widget, args, ONE);
372
373	state = !state;
374	break;
375    default:
376	SetMessage(global_screen_data.info_label,
377		   res_labels[16]);
378	return;
379    }
380
381    XtSetArg(args[0], XtNstate, state);
382    XtSetValues(node->widget, args, ONE);
383    TreeToggle(node->widget, (XtPointer) node, (XtPointer)(long) state);
384
385    if (!recurse)
386	return;
387
388    for (i = 0; i < node->num_children; i++)
389	_TreeSelectNode(node->children[i], type, recurse);
390}
391
392/*	Function Name: _TreeRelabelNodes
393 *	Description: Modifies the node and all its decendants label.
394 *	Arguments: node - node to operate on.
395 *                 type - type of selection to perform.
396 *                 recurse - whether to continue on down the tree.
397 *	Returns: none.
398 */
399
400void
401_TreeRelabelNode(WNode *node, LabelTypes type, Boolean recurse)
402{
403    int i;
404    Arg args[1];
405    char buf[30];
406    char *label;
407
408    switch(type) {
409    case ClassLabel:
410	XtSetArg(args[0], XtNlabel, node->class);
411	break;
412    case NameLabel:
413	XtSetArg(args[0], XtNlabel, node->name);
414	break;
415    case IDLabel:
416	sprintf(buf, "id: 0x%lx", node->id);
417	XtSetArg(args[0], XtNlabel, buf);
418	break;
419    case WindowLabel:
420	if (node->window == EDITRES_IS_UNREALIZED)
421	    strcpy(buf, "unrealized widget");
422	else if (node->window == EDITRES_IS_OBJECT)
423	    strcpy(buf, "non windowed object");
424	else
425	    sprintf(buf, "win: 0x%lx", node->window);
426
427	XtSetArg(args[0], XtNlabel, buf);
428	break;
429    case ToggleLabel:
430	XtSetArg(args[0], XtNlabel, &label);
431	XtGetValues(node->widget, args, ONE);
432	if (label && !strcmp(label, node->name))
433	    XtSetArg(args[0], XtNlabel, node->class);
434	else
435	    XtSetArg(args[0], XtNlabel, node->name);
436	break;
437    default:
438	SetMessage(global_screen_data.info_label,
439		   res_labels[32]);
440	return;
441    }
442
443    XtSetValues(node->widget, args, ONE);
444
445    if (!recurse)
446	return;
447
448    for (i = 0; i < node->num_children; i++)
449	_TreeRelabelNode(node->children[i], type, recurse);
450}
451
452/*	Function Name: _TreeActivateNode
453 *	Description: Activates relatives of the node specfied, as specified
454 *                   by type.
455 *	Arguments: node - node to opererate on.
456 *                 type - type of activate to invode.
457 *	Returns: none.
458 */
459
460void
461_TreeActivateNode(WNode* node, SelectTypes type)
462{
463    Arg args[1];
464    int i;
465
466    XtSetArg(args[0], XtNstate, TRUE);
467
468    if ((type == SelectParent) || (type == SelectAncestors)) {
469	node = node->parent;
470	if (node == NULL)
471	    return;
472
473	XtSetValues(node->widget, args, ONE);
474	AddNodeToActiveList(node);
475
476	if (type == SelectAncestors)
477	    _TreeActivateNode(node, type);
478    }
479    else if ((type == SelectChildren) || (type == SelectDescendants))
480	for (i = 0; i < node->num_children; i++) {
481	    AddNodeToActiveList(node->children[i]);
482	    XtSetValues(node->children[i]->widget, args, ONE);
483	    if (type == SelectDescendants)
484		_TreeActivateNode(node->children[i], type);
485	}
486    else
487	SetMessage(global_screen_data.info_label,
488		   res_labels[33]);
489}
490
491/************************************************************
492 *
493 * Non - Exported Functions.
494 *
495 ************************************************************/
496
497
498/*	Function Name: AddNode
499 *	Description: adds a node to the widget tree.
500 *	Arguments: top_node - a pointer to the current top node.
501 *                 info - the info from the client about the widget tree.
502 *                 tree_info - global information on this tree.
503 *	Returns: none.
504 */
505
506static void
507AddNode(WNode **top_node, WidgetTreeInfo *info, TreeInfo *tree_info)
508{
509    WNode *node, *parent;
510    Boolean early_break = FALSE;
511    Cardinal number = info->widgets.num_widgets;
512
513    if ( (node = FindNode(*top_node, info->widgets.ids, number)) == NULL) {
514	node = (WNode *) XtCalloc(sizeof(WNode), ONE);
515
516	node->id = info->widgets.ids[number - 1];
517	FillNode(info, node, tree_info);
518
519	for ( number--; number > 0; number--, node = parent) {
520	    parent = FindNode(*top_node, info->widgets.ids, number);
521	    if (parent == NULL) {
522		parent = (WNode *) XtCalloc(sizeof(WNode), ONE);
523		parent->id = info->widgets.ids[number - 1];
524	    }
525	    else
526		early_break = TRUE;
527
528	    AddChild(parent, node);
529
530	    if (early_break)
531		break;
532	}
533
534	if (!early_break) {
535	    if (node->parent == NULL)
536		*top_node = node;
537	    else
538		*top_node = node->parent;
539	}
540    }
541    else
542	FillNode(info, node, tree_info);
543}
544
545/*	Function Name: FillNode
546 *	Description: Fills in everything but the node id in the node.
547 *	Arguments: info - the info from the client.
548 *                 node - node to fill.
549 *                 tree_info - global information on this tree.
550 *	Returns: none
551 */
552
553static void
554FillNode(WidgetTreeInfo *info, WNode *node, TreeInfo *tree_info)
555{
556    node->class = info->class;
557    info->class = NULL;	/* keeps it from deallocating. */
558    node->name = info->name;
559    info->name = NULL;
560    node->window = info->window;
561    node->tree_info = tree_info;
562}
563
564/*	Function Name: AddChild
565 *	Description: Adds a child to an existing node.
566 *	Arguments: parent - parent node.
567 *                 child - child node to add.
568 *	Returns: none.
569 */
570
571static void
572AddChild(WNode *parent, WNode *child)
573{
574    if (parent->num_children >= parent->alloc_children) {
575	parent->alloc_children += NUM_INC;
576	parent->children = (WNode **) XtRealloc((char *)parent->children,
577				     sizeof(WNode *) * parent->alloc_children);
578    }
579
580    parent->children[parent->num_children] = child;
581    (parent->num_children)++;
582
583    child->parent = parent;
584}
585
586/************************************************************
587 *
588 *  Functions that operate of the current tree.
589 *
590 ************************************************************/
591
592/*	Function Name: CopyActiveNodes
593 *	Description: returns a copy of the currently selected nodes.
594 *	Arguments: tree_info - the tree info struct.
595 *	Returns: a copy of the selected nodes.
596 */
597
598static WNode **
599CopyActiveNodes(TreeInfo *tree_info)
600{
601    WNode ** list;
602    int i;
603
604    if ( (tree_info == NULL) || (tree_info->num_nodes == 0))
605	return(NULL);
606
607    list = (WNode **) XtMalloc(sizeof(WNode *) * tree_info->num_nodes);
608
609    for (i = 0; i < tree_info->num_nodes; i++)
610	list[i] = tree_info->active_nodes[i];
611
612    return(list);
613}
614
615/*	Function Name: SetAndCenterTreeNode
616 *	Description: Deactivates all nodes, activates the one specified, and
617 *                   and moves the tree to be centered on the current node.
618 *	Arguments: node - node to use.
619 *	Returns: none.
620 */
621
622void
623SetAndCenterTreeNode(WNode *node)
624{
625    Arg args[5];
626    Cardinal num_args;
627    Position node_x, node_y;
628    Dimension port_width, port_height;
629    Dimension node_width, node_height, node_bw;
630
631    _TreeSelect(node->tree_info, SelectNone); /* Unselect all nodes */
632    _TreeSelectNode(node, SelectAll, FALSE);  /* Select this node */
633
634    /*
635     * Get porthole dimensions.
636     */
637
638    num_args = 0;
639    XtSetArg(args[num_args], XtNwidth, &port_width); num_args++;
640    XtSetArg(args[num_args], XtNheight, &port_height); num_args++;
641    XtGetValues(XtParent(node->tree_info->tree_widget), args, num_args);
642
643    /*
644     * Get node widget dimensions.
645     */
646
647    num_args = 0;
648    XtSetArg(args[num_args], XtNwidth, &node_width); num_args++;
649    XtSetArg(args[num_args], XtNheight, &node_height); num_args++;
650    XtSetArg(args[num_args], XtNborderWidth, &node_bw); num_args++;
651    XtSetArg(args[num_args], XtNx, &node_x); num_args++;
652    XtSetArg(args[num_args], XtNy, &node_y); num_args++;
653    XtGetValues(node->widget, args, num_args);
654
655    /*
656     * reset the node x and y location to be the new x and y location of
657     * the tree relative to the porthole.
658     */
659
660    node_x = port_width/2 - (node_x + node_width/2 + node_bw);
661    node_y = port_height/2 - (node_y + node_height/2 + node_bw);
662
663    num_args = 0;
664    XtSetArg(args[num_args], XtNx, node_x); num_args++;
665    XtSetArg(args[num_args], XtNy, node_y); num_args++;
666    XtSetValues(node->tree_info->tree_widget, args, num_args);
667}
668
669/*	Function Name: PerformTreeToFileDump
670 *	Description: Dumps the contents of the current widget tree to
671 *                   the file specified.
672 *	Arguments: node - node to dump.
673 *                 num_tabs - number of spaces to indent.
674 *                 fp - pointer to the file to write to.
675 *	Returns: none.
676 */
677
678void
679PerformTreeToFileDump(WNode *node, int num_tabs, FILE *fp)
680{
681    int i;
682
683    for (i = 0; i < num_tabs; i++)
684	fprintf(fp, "\t");
685    fprintf(fp, "%s  %s\n", node->class, node->name);
686
687    num_tabs++;
688    for (i = 0; i < node->num_children; i++)
689	PerformTreeToFileDump(node->children[i], num_tabs, fp);
690}
691
692