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