1 /*
2  *
3 Copyright 1989, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in 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 
38 static void AddNodeToActiveList ( WNode * node );
39 static void RemoveNodeFromActiveList ( WNode * node );
40 static Boolean IsActiveNode ( WNode * node );
41 static void AddNode ( WNode ** top_node, WidgetTreeInfo * info,
42 		      TreeInfo * tree_info );
43 static void FillNode ( WidgetTreeInfo * info, WNode * node,
44 		       TreeInfo * tree_info );
45 static void AddChild ( WNode * parent, WNode * child );
46 static 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 */
56 void
BuildVisualTree(Widget tree_parent,Event * event)57 BuildVisualTree(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     snprintf(msg, sizeof(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 
100 void
AddTreeNode(Widget tree,WNode * top)101 AddTreeNode(Widget tree, WNode *top)
102 {
103     Cardinal 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 	    snprintf(msg, sizeof(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 	snprintf(msg, sizeof(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 */
142 void
TreeToggle(Widget w,XtPointer node_ptr,XtPointer state_ptr)143 TreeToggle(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 
160 static void
AddNodeToActiveList(WNode * node)161 AddNodeToActiveList(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 
184 static void
RemoveNodeFromActiveList(WNode * node)185 RemoveNodeFromActiveList(WNode *node)
186 {
187     TreeInfo * info = node->tree_info;
188     Boolean found_node = FALSE;
189     Cardinal 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 
210 static Boolean
IsActiveNode(WNode * node)211 IsActiveNode(WNode *node)
212 {
213     TreeInfo * info = node->tree_info;
214     Cardinal 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 
229 TreeInfo *
CreateTree(Event * event)230 CreateTree(Event *event)
231 {
232     SendWidgetTreeEvent * send_event = (SendWidgetTreeEvent *) event;
233     unsigned short 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 < 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 
258 void
PrintNodes(WNode * top)259 PrintNodes(WNode *top)
260 {
261     Cardinal 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 
281 void
_TreeRelabel(TreeInfo * tree_info,LabelTypes type)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 
307 void
_TreeSelect(TreeInfo * tree_info,SelectTypes type)308 _TreeSelect(TreeInfo *tree_info, SelectTypes type)
309 {
310     WNode ** active_nodes;
311     Cardinal num_active_nodes;
312     Cardinal 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 
353 void
_TreeSelectNode(WNode * node,SelectTypes type,Boolean recurse)354 _TreeSelectNode(WNode *node, SelectTypes type, Boolean recurse)
355 {
356     Cardinal 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 
398 void
_TreeRelabelNode(WNode * node,LabelTypes type,Boolean recurse)399 _TreeRelabelNode(WNode *node, LabelTypes type, Boolean recurse)
400 {
401     Cardinal 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 	snprintf(buf, sizeof(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 	    snprintf(buf, sizeof(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 
458 void
_TreeActivateNode(WNode * node,SelectTypes type)459 _TreeActivateNode(WNode* node, SelectTypes type)
460 {
461     Arg args[1];
462     Cardinal 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 
504 static void
AddNode(WNode ** top_node,WidgetTreeInfo * info,TreeInfo * tree_info)505 AddNode(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 
551 static void
FillNode(WidgetTreeInfo * info,WNode * node,TreeInfo * tree_info)552 FillNode(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 
569 static void
AddChild(WNode * parent,WNode * child)570 AddChild(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 
596 static WNode **
CopyActiveNodes(TreeInfo * tree_info)597 CopyActiveNodes(TreeInfo *tree_info)
598 {
599     WNode ** list;
600     Cardinal 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 
620 void
SetAndCenterTreeNode(WNode * node)621 SetAndCenterTreeNode(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 
676 void
PerformTreeToFileDump(WNode * node,Cardinal num_tabs,FILE * fp)677 PerformTreeToFileDump(WNode *node, Cardinal num_tabs, FILE *fp)
678 {
679     Cardinal 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