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