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