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